├── .github ├── dependabot.yml └── workflows │ ├── build-pull-request.yml │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main ├── java └── me │ └── dadus33 │ └── chatitem │ ├── C.java │ ├── ChatItem.java │ ├── ItemPlayer.java │ ├── ItemSlot.java │ ├── Storage.java │ ├── Translation.java │ ├── chatmanager │ ├── Chat.java │ ├── ChatAction.java │ ├── ChatEventListener.java │ ├── ChatManager.java │ ├── HandItem.java │ ├── v1 │ │ ├── PacketEditingChatManager.java │ │ ├── basecomp │ │ │ ├── IComponentManager.java │ │ │ └── hook │ │ │ │ ├── AdventureComponentManager.java │ │ │ │ ├── ComponentNMSManager.java │ │ │ │ ├── IChatBaseComponentManager.java │ │ │ │ ├── PCMComponentManager.java │ │ │ │ └── StringComponentManager.java │ │ ├── json │ │ │ ├── JSONManipulator.java │ │ │ └── Translator.java │ │ ├── listeners │ │ │ └── ChatPacketManager.java │ │ ├── packets │ │ │ ├── ChatItemPacket.java │ │ │ ├── ChatItemPacketManager.java │ │ │ ├── PacketContent.java │ │ │ ├── PacketHandler.java │ │ │ ├── PacketManager.java │ │ │ ├── PacketType.java │ │ │ ├── custom │ │ │ │ ├── CustomPacketManager.java │ │ │ │ └── channel │ │ │ │ │ ├── ChannelAbstract.java │ │ │ │ │ ├── ChannelInboundHandler.java │ │ │ │ │ ├── INC2Channel.java │ │ │ │ │ └── INCChannel.java │ │ │ └── protocollib │ │ │ │ └── ProtocollibPacketManager.java │ │ └── utils │ │ │ ├── Item.java │ │ │ ├── ItemRewriter.java │ │ │ ├── ItemRewriter_1_11_TO_1_10.java │ │ │ └── ItemRewriter_1_9_TO_1_8.java │ ├── v2 │ │ ├── ChatListener.java │ │ └── ChatListenerChatManager.java │ ├── v3 │ │ ├── PaperChatManager.java │ │ └── PaperListener.java │ └── v4 │ │ ├── OwnListener.java │ │ └── OwnManager.java │ ├── commands │ ├── CIReloadCommand.java │ └── ChatItemCommand.java │ ├── hook │ ├── ChatControlSupport.java │ ├── ChatManagerSupport.java │ ├── DiscordSrvSupport.java │ ├── ecoenchants │ │ ├── EcoEnchantsSupport.java │ │ ├── EcoEnchantsV10Support.java │ │ └── EcoEnchantsV8Support.java │ └── placeholders │ │ ├── EssentialsPlaceholdersHook.java │ │ ├── IPlaceholders.java │ │ ├── MVdWPlaceholderAPIHook.java │ │ ├── OwnPlaceholder.java │ │ ├── PlaceholderAPIHook.java │ │ └── VaultPlaceholderHook.java │ ├── invsee │ ├── InvShower.java │ └── hook │ │ ├── EnderChestShower.java │ │ ├── OneItemShower.java │ │ └── PlayerInventoryShower.java │ ├── itemnamer │ ├── INamer.java │ ├── NamerManager.java │ └── hook │ │ ├── ChatItemTranslationNamer.java │ │ ├── DefaultNamer.java │ │ ├── ItemDisplayNamer.java │ │ └── LangUtilsNamer.java │ ├── listeners │ ├── InventoryListener.java │ ├── JoinListener.java │ ├── TranslationInventoryListener.java │ └── holder │ │ ├── AdminHolder.java │ │ ├── ChatItemHolder.java │ │ ├── CustomInventoryHolder.java │ │ └── TranslationHolder.java │ ├── platform │ ├── IPlatform.java │ └── hook │ │ ├── PaperPlatform.java │ │ └── SpigotPlatform.java │ ├── playernamer │ ├── IPlayerNamer.java │ ├── PlayerNamerManager.java │ └── hook │ │ ├── DefaultPlayerNamer.java │ │ ├── HexNicksV2PlayerNamer.java │ │ └── HexNicksV3PlayerNamer.java │ ├── playerversion │ ├── IPlayerVersion.java │ ├── PlayerVersionManager.java │ └── hooks │ │ ├── DefaultVersionHook.java │ │ ├── ProtocolSupportHook.java │ │ └── ViaVersionHook.java │ └── utils │ ├── ColorManager.java │ ├── Colors.java │ ├── ItemUtils.java │ ├── Messages.java │ ├── PacketUtils.java │ ├── ReflectionUtils.java │ ├── SemVer.java │ ├── Utils.java │ └── Version.java └── resources ├── config.yml ├── lang ├── af_za.json ├── ar_sa.json ├── ast_es.json ├── az_az.json ├── ba_ru.json ├── bar.json ├── be_by.json ├── bg_bg.json ├── br_fr.json ├── brb.json ├── bs_ba.json ├── ca_es.json ├── cs_cz.json ├── cy_gb.json ├── da_dk.json ├── de_at.json ├── de_ch.json ├── de_de.json ├── el_gr.json ├── en_au.json ├── en_ca.json ├── en_gb.json ├── en_nz.json ├── en_pt.json ├── en_ud.json ├── enp.json ├── enws.json ├── eo_uy.json ├── es_ar.json ├── es_cl.json ├── es_ec.json ├── es_es.json ├── es_mx.json ├── es_uy.json ├── es_ve.json ├── esan.json ├── et_ee.json ├── eu_es.json ├── fa_ir.json ├── fi_fi.json ├── fil_ph.json ├── fo_fo.json ├── fr_ca.json ├── fr_fr.json ├── fra_de.json ├── fur_it.json ├── fy_nl.json ├── ga_ie.json ├── gd_gb.json ├── gl_es.json ├── haw_us.json ├── he_il.json ├── hi_in.json ├── hr_hr.json ├── hu_hu.json ├── hy_am.json ├── id_id.json ├── ig_ng.json ├── io_en.json ├── is_is.json ├── isv.json ├── it_it.json ├── ja_jp.json ├── jbo_en.json ├── ka_ge.json ├── kk_kz.json ├── kn_in.json ├── ko_kr.json ├── ksh.json ├── kw_gb.json ├── la_la.json ├── lb_lu.json ├── legacy.yml ├── li_li.json ├── lmo.json ├── lol_us.json ├── lt_lt.json ├── lv_lv.json ├── lzh.json ├── mk_mk.json ├── mn_mn.json ├── ms_my.json ├── mt_mt.json ├── nds_de.json ├── nl_be.json ├── nl_nl.json ├── nn_no.json ├── no_no.json ├── oc_fr.json ├── ovd.json ├── pl_pl.json ├── pt_br.json ├── pt_pt.json ├── qya_aa.json ├── ro_ro.json ├── rpr.json ├── ru_ru.json ├── ry_ua.json ├── se_no.json ├── sk_sk.json ├── sl_si.json ├── so_so.json ├── sq_al.json ├── sr_sp.json ├── sv_se.json ├── sxu.json ├── szl.json ├── ta_in.json ├── th_th.json ├── tl_ph.json ├── tlh_aa.json ├── tok.json ├── tr_tr.json ├── tt_ru.json ├── uk_ua.json ├── val_es.json ├── vec_it.json ├── vi_vn.json ├── yi_de.json ├── yo_ng.json ├── zh_cn.json ├── zh_hk.json ├── zh_tw.json └── zlm_arab.json ├── langs.yml └── plugin.yml /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/build-pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Build v2 for PR 2 | 3 | on: 4 | pull_request: 5 | branches: [ v2 ] 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | name: Checkout repo 15 | 16 | - name: Set up JDK 21 17 | uses: actions/setup-java@v4 18 | with: 19 | java-version: '21' 20 | distribution: 'temurin' 21 | cache: maven 22 | 23 | - name: Build with Maven 24 | run: mvn install --file pom.xml 25 | 26 | - uses: actions/upload-artifact@v3 27 | name: Upload Artifact 28 | with: 29 | name: ChatItem.jar 30 | path: target/ChatItem-*.jar 31 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build v2 2 | 3 | on: 4 | push: 5 | branches: [ v2 ] 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | name: Checkout repo 15 | 16 | - name: Set up JDK 21 17 | uses: actions/setup-java@v4 18 | with: 19 | java-version: '21' 20 | distribution: 'temurin' 21 | cache: maven 22 | 23 | - name: Build with Maven 24 | run: mvn install --file pom.xml 25 | 26 | - uses: actions/upload-artifact@v4 27 | name: Upload Artifact 28 | with: 29 | name: ChatItem.jar 30 | path: target/ChatItem-*.jar 31 | - name: Send file README.md to discord channel 32 | uses: sinshutu/upload-to-discord@master 33 | env: 34 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} 35 | with: 36 | args: target/ChatItem-*.jar 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | src/test/ 3 | bin/ 4 | target/ 5 | *.iml 6 | dependency-reduced-pom.xml 7 | .classpath 8 | .project 9 | .settings/ 10 | /.apt_generated/ 11 | /.apt_generated_tests/ 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatItem 2 | 3 | The official repository of the ChatItem Spigot/Bukkit plugin. 4 | 5 | You can: 6 | 7 | - [Download latest dev build](https://nightly.link/dadus33-plugins/ChatItem/workflows/build/v2/ChatItem.jar.zip) 8 | - [ ![Come on discord](https://img.shields.io/badge/chat-on_discord-7289da.svg) ](https://discord.gg/yng5PPf62h) 9 | - [Check the wiki](https://github.com/dadus33-plugins/ChatItem/wiki) 10 | 11 | # Item doesn't show up well in chat 12 | 13 | You can do `/chatitem admin` then select one of the other paper items in the menu. It will change how the plugin tries to display items in chat. 14 | 15 | **If you still have an issue, please do**: 16 | 1) Do `/chatitem admin` then select on "Debug" item at top right 17 | 2) Try to use ChatItem in chat 18 | 3) Come on discord [here](https://discord.gg/yng5PPf62h) or in private message: `Elikill58#0743` 19 | 4) Send the **full file `logs/latest.log`** 20 | 21 | PS: Yes you can disable the debug behavior after. 22 | 23 | # Building 24 | 25 | Building this is simple as we use Maven. 26 | 27 | To build it, simply clone this repository and then run `mvn clean install`. 28 | 29 | You can add the parameter `export_dir` to set the URL where the JAR will be exported. 30 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/C.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem; 2 | 3 | import net.kyori.adventure.text.Component; 4 | import net.kyori.adventure.text.TextComponent; 5 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 6 | 7 | public class C { 8 | 9 | public static TextComponent text(String s) { 10 | return LegacyComponentSerializer.legacySection().deserialize(s); 11 | } 12 | 13 | public static String string(Component c) { 14 | return LegacyComponentSerializer.legacySection().serialize(c); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/ItemPlayer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem; 2 | 3 | import java.util.UUID; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.entity.Player; 8 | 9 | import me.dadus33.chatitem.playerversion.PlayerVersionManager; 10 | import me.dadus33.chatitem.utils.Version; 11 | 12 | public class ItemPlayer { 13 | 14 | private static final ConcurrentHashMap PLAYERS = new ConcurrentHashMap<>(); 15 | public static ItemPlayer getPlayer(Player p) { 16 | return PLAYERS.computeIfAbsent(p.getUniqueId(), ItemPlayer::new); 17 | } 18 | public static ItemPlayer getPlayer(UUID uuid) { 19 | return PLAYERS.computeIfAbsent(uuid, ItemPlayer::new); 20 | } 21 | private final UUID uuid; 22 | private int protocolVersion = 0; 23 | private Version version = null; 24 | private String clientName = "unknow"; 25 | 26 | public ItemPlayer(UUID uuid) { 27 | this.uuid = uuid; 28 | Player p = Bukkit.getPlayer(uuid); 29 | if(p != null) 30 | setVersion(PlayerVersionManager.getPlayerVersionAdapter().getPlayerVersion(p)); 31 | } 32 | 33 | public UUID getUUID() { 34 | return uuid; 35 | } 36 | 37 | public Player getPlayer() { 38 | return Bukkit.getPlayer(uuid); 39 | } 40 | 41 | public String getClientName() { 42 | return clientName; 43 | } 44 | 45 | public void setClientName(String clientName) { 46 | this.clientName = clientName; 47 | } 48 | 49 | public int getProtocolVersion() { 50 | if(protocolVersion == 0) 51 | setProtocolVersion(PlayerVersionManager.getPlayerVersionAdapter().getProtocolVersion(getPlayer())); 52 | return protocolVersion; 53 | } 54 | 55 | public void setProtocolVersion(int protocolVersion) { 56 | this.protocolVersion = protocolVersion; 57 | if(version == Version.getVersion()) {// if is default 58 | version = Version.getVersion(protocolVersion); 59 | ChatItem.debug("Detected version " + version.name() + " (protocol: " + protocolVersion + ")"); 60 | } 61 | } 62 | 63 | public Version getVersion() { 64 | if(version == null) 65 | setVersion(PlayerVersionManager.getPlayerVersionAdapter().getPlayerVersion(getPlayer())); 66 | return version; 67 | } 68 | 69 | public void setVersion(Version version) { 70 | this.version = version; 71 | if(protocolVersion == 0) 72 | this.protocolVersion = version.MAX_VER; 73 | } 74 | 75 | public boolean isBuggedClient() { 76 | return (!getVersion().isNewerOrEquals(Version.V1_15) && Version.getVersion().isNewerOrEquals(Version.V1_16)); 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "ItemPlayer[uuid=" + uuid + ",name=" + (getPlayer() != null ? getPlayer().getName() : "-") + ",version=" + version.name() + ",protocol=" + protocolVersion + ",client=" + clientName + "]"; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/ItemSlot.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem; 2 | 3 | import java.util.List; 4 | 5 | import me.dadus33.chatitem.chatmanager.ChatManager; 6 | import me.dadus33.chatitem.utils.Colors; 7 | 8 | public enum ItemSlot { 9 | 10 | HAND("", false), 11 | HELMET("helmet", false), 12 | CHESTPLATE("chestplate", false), 13 | LEGGINGS("leggings", false), 14 | BOOTS("boots", false), 15 | INVENTORY("inventory", true), 16 | ENDERCHEST("enderchest", true); 17 | 18 | private final boolean command; 19 | private final String key; 20 | 21 | private ItemSlot(String key, boolean command) { 22 | this.command = command; 23 | this.key = key; 24 | } 25 | 26 | public String getKey() { 27 | return key; 28 | } 29 | 30 | public boolean isBasic() { 31 | return key.equalsIgnoreCase(""); 32 | } 33 | 34 | public boolean isCommand() { 35 | return command; 36 | } 37 | 38 | public List getPlaceholders() { 39 | return ChatItem.getInstance().getConfig().getStringList(isBasic() ? "general.placeholders" : "general.other-placeholders." + key + ".keys"); 40 | } 41 | 42 | public boolean isEnabled() { 43 | return isBasic() || ChatItem.getInstance().getConfig().getBoolean("general.other-placeholders." + key + ".enabled", true); 44 | } 45 | 46 | public boolean isDenyIfNoItem() { 47 | return ChatItem.getInstance().getConfig().getBoolean("general" + (isBasic() ? "" : ".other-placeholders." + key) + ".deny-if-no-item", true); 48 | } 49 | 50 | public String getShowMessage() { 51 | return Colors.color(ChatItem.getInstance().getConfig().getString("general" + (isBasic() ? "" : ".other-placeholders." + key) + ".show", "")); 52 | } 53 | 54 | public boolean hasPlaceholders(String message) { 55 | for (String rep : getPlaceholders()) { 56 | if (message.contains(rep)) { 57 | return true; 58 | } 59 | } 60 | return false; 61 | } 62 | 63 | public String replacePlaceholdersToSeparator(String message) { 64 | for(String rep : getPlaceholders()) 65 | message = message.replace(rep, Character.toString(ChatManager.SEPARATOR)); 66 | return message; 67 | } 68 | 69 | public static ItemSlot getItemSlotFromMessage(String message) { 70 | for(ItemSlot slot : ItemSlot.values()) { 71 | if(slot.isEnabled() && slot.hasPlaceholders(message)) { 72 | return slot; 73 | } 74 | } 75 | return null; 76 | } 77 | 78 | public static ItemSlot getItemSlotByKey(String key) { 79 | for(ItemSlot slot : ItemSlot.values()) { 80 | if(slot.isEnabled() && slot.getKey().equalsIgnoreCase(key)) { 81 | return slot; 82 | } 83 | } 84 | return null; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/Storage.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | 6 | import org.bukkit.configuration.file.FileConfiguration; 7 | 8 | import me.dadus33.chatitem.utils.Colors; 9 | 10 | public class Storage { 11 | 12 | public String handName, nameFormat, amountFormat, commandFormat, manager, permissionName, buggedClientAction, language; 13 | public final String messageNoPermission, messageDeny, messageReload, messageCooldown, messageLimit, messageIgnoredItem; 14 | public final String SECONDS, minutes, hours; 15 | public final String updateMessage, updateHover; 16 | public final List tooltipHand, tooltipBuggedClient, ignoredItems; 17 | public boolean colorIfColored, addAmountForced, letMessageThrough, debug, handDisabled, showNoPermissionMessage, checkUpdate, permissionEnabled, cmdBroadcast, cmdShow, discordSrvSendMsg, replaceInConsole; 18 | public int configVersion, limit, cooldown; 19 | private FileConfiguration conf; 20 | 21 | public Storage(FileConfiguration cnf) { 22 | this.conf = cnf; 23 | configVersion = conf.getInt("config-version", 13); 24 | checkConfigVersion(); 25 | this.manager = conf.getString("manager", "auto"); 26 | if(manager == "both") 27 | manager = "all"; 28 | language = conf.getString("general.language", "en_gb"); 29 | debug = conf.getBoolean("debug", false); 30 | nameFormat = color(conf.getString("general.name-format", "&b&l&o{name} {amount}&r")); 31 | amountFormat = color(conf.getString("general.amount-format", "x{times}")); 32 | commandFormat = color(conf.getString("general.command-format", "&6%name%'s item is %item%")); 33 | colorIfColored = conf.getBoolean("general.color-if-already-colored", true); 34 | letMessageThrough = conf.getBoolean("general.let-message-through", true); 35 | addAmountForced = conf.getBoolean("general.force-add-amount", true); 36 | limit = conf.getInt("general.limit", 8); 37 | cooldown = conf.getInt("general.cooldown", 60); 38 | showNoPermissionMessage = conf.getBoolean("general.show-no-permission-message.normal", true); 39 | permissionEnabled = conf.getBoolean("general.permission.enabled", false); 40 | permissionName = conf.getString("general.permission.name", "chatitem.use"); 41 | handDisabled = conf.getBoolean("general.hand.disabled", false); 42 | handName = color(conf.getString("general.hand.name", "&b&l&o{display-name}&b&l&o's hand")); 43 | tooltipHand = conf.getStringList("general.hand.tooltip").stream().map(Storage::color).collect(Collectors.toList()); 44 | buggedClientAction = conf.getString("general.bugged_client.action", "show_both"); 45 | tooltipBuggedClient = conf.getStringList("general.bugged_client.tooltip").stream().map(Storage::color).collect(Collectors.toList()); 46 | ignoredItems = conf.getStringList("general.ignored_items"); 47 | checkUpdate = conf.getBoolean("general.check-update", true); 48 | cmdShow = conf.getBoolean("general.sub-commands.broadcast", true); 49 | cmdBroadcast = conf.getBoolean("general.sub-commands.show", true); 50 | replaceInConsole = conf.getBoolean("general.replace-in-console", true); 51 | messageDeny = color(conf.getString("messages.deny-message", "&c&lYou have no item in hand!")); 52 | messageReload = color(conf.getString("messages.reload-success", "&b&lSuccessful reload!")); 53 | messageNoPermission = color(conf.getString("messages.no-permission", "&c&lI'm sorry, but you are not allowed to use the placeholder in chat!")); 54 | messageCooldown = color(conf.getString("messages.cooldown-message", "&c&lYou can only use items in chat once a minute! You have {remaining} left!")); 55 | updateMessage = color(conf.getString("messages.join-update.message", "&cA new version of ChatItem is available. &aClick here to download.")); 56 | updateHover = color(conf.getString("messages.join-update.hover", "&6Click to go to spigot page !")); 57 | messageLimit = color(conf.getString("messages.limit-message", "&c&lYou can only add 8 item placeholders per message!")); 58 | messageIgnoredItem = color(conf.getString("messages.ignored-item", "&cThis item is not allowed to be showed.")); 59 | discordSrvSendMsg = conf.getBoolean("discord-srv-send-our", true); 60 | 61 | SECONDS = color(conf.getString("messages.seconds", " seconds")); 62 | minutes = color(conf.getString("messages.minutes", " minutes")); 63 | hours = color(conf.getString("messages.hours", " hours")); 64 | colorStringList(tooltipHand); 65 | } 66 | 67 | public static String color(String s) { 68 | return s == null || s.isEmpty() ? s : Colors.translateAlternateColorCodes('&', s); 69 | } 70 | 71 | private static void colorStringList(List input) { 72 | for (int i = 0; i < input.size(); ++i) { 73 | input.set(i, color(input.get(i))); 74 | } 75 | } 76 | 77 | private void checkConfigVersion() { 78 | int latestVersion = ChatItem.CFG_VER; 79 | if (latestVersion != configVersion) { 80 | ChatItem pl = ChatItem.getInstance(); 81 | pl.getLogger().warning("ChatItem detected an older or invalid configuration file. Replacing it with the default config..."); 82 | performOverwrite(); 83 | conf = pl.getConfig(); 84 | pl.getLogger().warning("Replacement complete!"); 85 | } 86 | } 87 | 88 | private void performOverwrite() { 89 | ChatItem.getInstance().saveResource("config.yml", true); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/Translation.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem; 2 | 3 | import java.io.File; 4 | import java.io.FileReader; 5 | import java.io.InputStreamReader; 6 | import java.nio.file.Files; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashMap; 10 | import java.util.LinkedHashMap; 11 | import java.util.Map.Entry; 12 | import java.util.stream.Collectors; 13 | 14 | import org.bukkit.configuration.file.YamlConfiguration; 15 | import org.bukkit.inventory.ItemStack; 16 | 17 | import com.google.gson.JsonElement; 18 | import com.google.gson.JsonObject; 19 | import com.google.gson.JsonParser; 20 | 21 | import me.dadus33.chatitem.utils.Utils; 22 | 23 | @SuppressWarnings("deprecation") 24 | public class Translation { 25 | 26 | private static File folder; 27 | private static YamlConfiguration legacy, allLangsConfig; 28 | private static JsonObject messages; 29 | private static HashMap allLangs = new HashMap<>(); 30 | 31 | public static void load(ChatItem pl) { 32 | folder = new File(pl.getDataFolder(), "lang"); 33 | if (!folder.exists()) 34 | folder.mkdir(); 35 | legacy = Utils.copyLoadFile(folder, "legacy.yml", "lang/legacy.yml"); 36 | allLangsConfig = Utils.copyLoadFile(pl.getDataFolder(), "langs.yml", "langs.yml"); 37 | 38 | allLangsConfig.getStringList("all").forEach(langKey -> { 39 | try { 40 | JsonObject content = JsonParser.parseReader(new InputStreamReader(pl.getResource("lang/" + langKey + ".json"))).getAsJsonObject(); 41 | allLangs.put(langKey, content.get("language.name").getAsString() + " (" + content.get("language.region").getAsString() + ")"); 42 | } catch (Exception e) { 43 | pl.getLogger().severe("Failed to load lang with key " + langKey + " : " + e.getMessage() + " (" + e.getStackTrace()[0].toString() + ")"); 44 | } 45 | }); 46 | allLangs = allLangs.entrySet().stream().sorted(Entry.comparingByValue()).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); 47 | loadLang(pl.getStorage().language); 48 | } 49 | 50 | public static HashMap getAllLangs() { 51 | return allLangs; 52 | } 53 | 54 | public static JsonObject getMessages() { 55 | return messages; 56 | } 57 | 58 | public static String getMessage(String key) { 59 | JsonElement result = messages.get(key); 60 | return result == null ? "" : result.getAsString(); 61 | } 62 | 63 | public static void loadLang(String lang) { 64 | ChatItem pl = ChatItem.getInstance(); 65 | File langFile = new File(folder, lang + ".json"); 66 | if (!langFile.exists()) { 67 | if (pl.getResource("lang/" + lang + ".json") != null) { 68 | Utils.copyFile("lang/" + lang + ".json", langFile); 69 | } else { 70 | pl.getLogger().severe("Failed to find lang file for " + lang); 71 | if(lang != "en_gb") 72 | loadLang("en_gb"); 73 | return; 74 | } 75 | } 76 | 77 | try { 78 | messages = JsonParser.parseReader(new FileReader(langFile)).getAsJsonObject(); 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | pl.getLogger().info("Loaded translation for " + lang + "."); 83 | } 84 | 85 | public static String get(ItemStack item) { 86 | String key = (item.getType().isBlock() ? "block" : "item") + ".minecraft." + item.getType().name().toLowerCase(); 87 | if (messages != null && messages.has(key)) { 88 | return messages.get(key).getAsString(); 89 | } else 90 | ChatItem.debug("Failed to find translation for " + key); 91 | return legacy.getString(item.getType().name() + "." + item.getDurability(), item.getType().name().toLowerCase().replace("_", " ")); 92 | } 93 | 94 | public static String getOr(ItemStack item, String def) { 95 | String key = (item.getType().isBlock() ? "block" : "item") + ".minecraft." + item.getType().name().toLowerCase(); 96 | if (messages != null && messages.has(key)) { 97 | return messages.get(key).getAsString(); 98 | } else 99 | ChatItem.debug("Failed to find translation for " + key); 100 | return legacy.getString(item.getType().name() + "." + item.getDurability(), def); 101 | } 102 | 103 | protected void thisMethodShouldNotBeUsed_InsteadToUpdateLangFileFromLocalInstall() throws Exception { 104 | File dir = new File("dir/to/result"); 105 | File folder = new File("C:\\Dir\\To\\AppData\\Roaming\\.minecraft\\assets");// here we are looking for 1.19 106 | JsonObject json = JsonParser.parseReader(new FileReader(new File(folder, "indexes/1.19.json"))).getAsJsonObject().get("objects").getAsJsonObject(); 107 | for (String key : json.keySet()) { 108 | if (key.startsWith("minecraft/lang")) { // only lang files 109 | String lang = key.toString().replace("minecraft/lang/", ""); 110 | String hash = json.get(key).getAsJsonObject().get("hash").getAsString(); 111 | File langFile = new File(folder, "objects/" + hash.substring(0, 2) + "/" + hash); 112 | JsonObject langs = JsonParser.parseReader(new FileReader(langFile)).getAsJsonObject(); 113 | for (String langKey : new ArrayList<>(langs.keySet())) { 114 | if (!(langKey.startsWith("block.") || langKey.startsWith("language"))) { // only what we want 115 | langs.remove(langKey); // removing not needed 116 | } 117 | } 118 | File langDir = new File(dir, lang); 119 | Files.write(langDir.toPath(), Arrays.asList(langs.toString())); 120 | System.out.println("Copied " + lang); // using sysout as it's made for basic java, not mc 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/Chat.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | import org.bukkit.entity.Player; 8 | 9 | import me.dadus33.chatitem.ChatItem; 10 | import me.dadus33.chatitem.ItemPlayer; 11 | import me.dadus33.chatitem.ItemSlot; 12 | import me.dadus33.chatitem.utils.Utils; 13 | 14 | public class Chat { 15 | 16 | private static int actualId = 0; 17 | private static final List CHAT = new ArrayList<>(); 18 | public static Optional getChat(int id) { 19 | synchronized (CHAT) { 20 | CHAT.removeIf(Chat::isOld); 21 | return CHAT.stream().filter(o -> o.getId() == id).findFirst(); 22 | } 23 | } 24 | public static Chat create(Player p, String message, ChatAction action) { 25 | return new Chat(actualId++, p, message, action); 26 | } 27 | public static Chat getFrom(String message) { 28 | boolean found = false; 29 | String id = ""; 30 | for(char c : ChatManager.fixSeparator(message).toCharArray()) { 31 | if(c == ChatManager.SEPARATOR) 32 | found = true; 33 | else if(c == ChatManager.SEPARATOR_END) 34 | break; 35 | else if(found) 36 | id += c; 37 | } 38 | ChatItem.debug("Search in " + message + ", id found: " + id); 39 | return (id != "" && Utils.isInteger(id)) ? Chat.getChat(Integer.parseInt(id)).orElse(null) : null; 40 | } 41 | 42 | private final long time; 43 | private final int id; 44 | private final Player p; 45 | private final String message; 46 | private final ChatAction action; 47 | 48 | public Chat(int id, Player p, String message, ChatAction action) { 49 | this.time = System.currentTimeMillis(); 50 | this.id = id; 51 | this.p = p; 52 | this.message = message; 53 | this.action = action; 54 | CHAT.add(this); 55 | } 56 | 57 | public long getTime() { 58 | return time; 59 | } 60 | 61 | public int getId() { 62 | return id; 63 | } 64 | 65 | public Player getPlayer() { 66 | return p; 67 | } 68 | 69 | public String getMessage() { 70 | return message; 71 | } 72 | 73 | public ItemSlot getSlot() { 74 | return action.getSlot(); 75 | } 76 | 77 | public ChatAction getAction() { 78 | return action; 79 | } 80 | 81 | public ItemPlayer getItemPlayer() { 82 | return ItemPlayer.getPlayer(getPlayer()); 83 | } 84 | 85 | private boolean isOld() { 86 | return System.currentTimeMillis() > time + 10000; 87 | } 88 | 89 | public void remove() { 90 | CHAT.remove(this); 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "Chat{id=" + id + ",message=" + message + ",time=" + time + "}"; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/ChatAction.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.inventory.ItemStack; 6 | 7 | import me.dadus33.chatitem.ItemSlot; 8 | 9 | public class ChatAction { 10 | 11 | private boolean hasItem; 12 | private ItemSlot slot; 13 | private String command; 14 | private ItemStack item; 15 | private Player origin; 16 | 17 | public ChatAction(ItemSlot slot, Player origin, ItemStack item, String command) { 18 | this.slot = slot; 19 | this.item = item == null ? new ItemStack(Material.AIR) : item; 20 | this.command = command; 21 | this.origin = origin; 22 | this.hasItem = true; 23 | } 24 | 25 | public ChatAction(ItemSlot slot, Player origin, String command) { 26 | this.slot = slot; 27 | this.command = command; 28 | this.origin = origin; 29 | this.hasItem = false; 30 | } 31 | 32 | public Player getOrigin() { 33 | return origin; 34 | } 35 | 36 | public ItemSlot getSlot() { 37 | return slot; 38 | } 39 | 40 | public boolean hasItem() { 41 | return hasItem; 42 | } 43 | 44 | public String getCommand() { 45 | return command; 46 | } 47 | 48 | public boolean hasCommand() { 49 | return command != null && command != ""; 50 | } 51 | 52 | public ItemStack getItem() { 53 | return item == null ? new ItemStack(Material.AIR) : item; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "ChatAction[slot=" + slot + ",command=" + command + ",item=" + item + ",origin=" + origin + "]"; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/ChatEventListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager; 2 | 3 | import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR; 4 | import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR_END; 5 | 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.EventPriority; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.player.AsyncPlayerChatEvent; 11 | 12 | import me.dadus33.chatitem.ChatItem; 13 | import me.dadus33.chatitem.ItemSlot; 14 | import me.dadus33.chatitem.Storage; 15 | import me.dadus33.chatitem.utils.Utils; 16 | 17 | @SuppressWarnings("deprecation") 18 | public class ChatEventListener implements Listener { 19 | 20 | private Storage getStorage() { 21 | return ChatItem.getInstance().getStorage(); 22 | } 23 | 24 | @EventHandler(priority = EventPriority.LOWEST) 25 | public void onChat(AsyncPlayerChatEvent e) { 26 | if (ChatManager.containsSeparator(e.getMessage())) { // If the BELL character is found, we have to remove it 27 | e.setMessage(ChatManager.removeSeparator(e.getMessage())); 28 | } 29 | Player p = e.getPlayer(); 30 | String oldMsg = e.getMessage(); 31 | ItemSlot slot = ItemSlot.getItemSlotFromMessage(e.getMessage()); 32 | if (slot == null) { 33 | ChatItem.debug("(general) not found placeholders in: " + e.getMessage()); 34 | return; 35 | } 36 | ChatAction action = ChatManager.getChatAction(slot, p); 37 | if(!ChatManager.canUsePlaceholder(p, action, slot, e)) 38 | return; 39 | String s = slot.replacePlaceholdersToSeparator(e.getMessage()); 40 | if (Utils.countMatches(s, Character.toString(ChatManager.SEPARATOR)) > getStorage().limit) { 41 | e.setCancelled(true); 42 | if (!getStorage().messageLimit.isEmpty()) 43 | p.sendMessage(getStorage().messageLimit); 44 | return; 45 | } 46 | 47 | Chat c = Chat.create(p, oldMsg, action); 48 | ChatItem.debug("(general) Set placeholder to message " + c); 49 | e.setMessage(s.replace(Character.toString(ChatManager.SEPARATOR), SEPARATOR + Integer.toString(c.getId()) + SEPARATOR_END)); 50 | e.setFormat(e.getFormat().replace(oldMsg, e.getMessage())); // set own message for plugin that already put the message into the format 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/HandItem.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.ItemStack; 5 | 6 | import me.dadus33.chatitem.ItemSlot; 7 | import me.dadus33.chatitem.utils.ItemUtils; 8 | import me.dadus33.chatitem.utils.Version; 9 | 10 | public class HandItem { 11 | 12 | @SuppressWarnings("deprecation") 13 | public static ItemStack getBetterItem(Player p, ItemSlot slot) { 14 | switch (slot) { 15 | case HAND: 16 | if(Version.getVersion().isNewerOrEquals(Version.V1_9)) { 17 | ItemStack main = p.getInventory().getItemInMainHand(); 18 | if(!ItemUtils.isEmpty(main)) 19 | return main; 20 | return p.getInventory().getItemInOffHand(); 21 | } 22 | return p.getItemInHand(); 23 | case HELMET: 24 | return p.getInventory().getHelmet(); 25 | case CHESTPLATE: 26 | return p.getInventory().getChestplate(); 27 | case LEGGINGS: 28 | return p.getInventory().getLeggings(); 29 | case BOOTS: 30 | return p.getInventory().getBoots(); 31 | case ENDERCHEST: 32 | break; 33 | case INVENTORY: 34 | break; 35 | } 36 | return null; // should never happen 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/PacketEditingChatManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.util.Arrays; 5 | 6 | import org.bukkit.Bukkit; 7 | 8 | import me.dadus33.chatitem.ChatItem; 9 | import me.dadus33.chatitem.Storage; 10 | import me.dadus33.chatitem.chatmanager.ChatManager; 11 | import me.dadus33.chatitem.chatmanager.v1.listeners.ChatPacketManager; 12 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacketManager; 13 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent; 14 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketManager; 15 | import me.dadus33.chatitem.utils.PacketUtils; 16 | import me.dadus33.chatitem.utils.ReflectionUtils; 17 | import me.dadus33.chatitem.utils.Utils; 18 | 19 | public class PacketEditingChatManager extends ChatManager { 20 | 21 | private boolean baseComponentAvailable = true; 22 | private final ChatItemPacketManager packetManager; 23 | private final ChatPacketManager chatPacketManager; 24 | 25 | public PacketEditingChatManager(ChatItem pl) { 26 | packetManager = new ChatItemPacketManager(pl); 27 | chatPacketManager = new ChatPacketManager(this); 28 | 29 | // Check for existence of BaseComponent class (only on spigot) 30 | try { 31 | Class.forName("net.md_5.bungee.api.chat.BaseComponent"); 32 | } catch (ClassNotFoundException e) { 33 | baseComponentAvailable = false; 34 | } 35 | } 36 | 37 | @Override 38 | public String getName() { 39 | return "PacketEditing"; 40 | } 41 | 42 | @Override 43 | public String getId() { 44 | return "packet"; 45 | } 46 | 47 | @Override 48 | public void load(ChatItem pl, Storage s) { 49 | super.load(pl, s); 50 | 51 | PacketManager pm = packetManager.getPacketManager(); 52 | pm.addHandler(chatPacketManager); 53 | Bukkit.getOnlinePlayers().forEach(pm::addPlayer); // add actual online players 54 | } 55 | 56 | @Override 57 | public void unload(ChatItem pl) { 58 | PacketManager pm = packetManager.getPacketManager(); 59 | pm.removeHandler(chatPacketManager); 60 | pm.stop(); 61 | } 62 | 63 | public boolean supportsChatComponentApi() { 64 | return baseComponentAvailable; 65 | } 66 | 67 | private static String checkPacketSize(String packet, int maxSize) { 68 | int size = packet.getBytes().length; 69 | while(size > maxSize) { 70 | packet = packet.replaceFirst(" ", " "); 71 | if(size == packet.getBytes().length) 72 | break; // could not fix myself 73 | size = packet.getBytes().length; 74 | } 75 | return packet; 76 | } 77 | 78 | public static Object createSystemChatPacket(String json, Object old) throws Exception { 79 | json = checkPacketSize(json, 150000); 80 | if(json.contains("tag:{{")) { // this is to fix for MC 1.20.4 (at least on purpur) 81 | ChatItem.debug("Found strange JSON formatting. Cleaning..."); 82 | boolean replaced = false; 83 | String next = ""; 84 | for(String part : json.split("tag:\\{\\{")) { 85 | if(replaced) { 86 | next += "tag:{"; 87 | next += part.replaceFirst("\\}\\}", "}"); 88 | } else 89 | next += part; 90 | replaced = true; 91 | } 92 | json = next; 93 | } 94 | Object packet = internalCreateSystemChatPacket(json, old); 95 | if(packet != null) 96 | return packet; 97 | Object icb = ChatItem.getPlatform().jsonToBaseComponent(json); 98 | if(icb != null) 99 | packet = internalCreateSystemChatPacket(icb, old); 100 | if(packet != null) 101 | return packet; 102 | ChatItem.getInstance().getLogger().warning("Can't create a new packet for json " + json); 103 | return null; 104 | } 105 | 106 | private static Object internalCreateSystemChatPacket(Object obj, Object old) throws Exception { 107 | ChatItem.debug("Creating internal chat system packet from " + old + " to " + obj); 108 | Class packetClass = PacketUtils.getNmsClass("ClientboundSystemChatPacket", "network.protocol.game.", "ClientboundPlayerChatPacket", "PacketPlayOutChat"); 109 | Class chatMessageTypeClass = Utils.isClassExist("net.minecraft.network.chat.ChatMessageType") ? PacketUtils.getNmsClass("ChatMessageType", "network.chat.") : null; 110 | Constructor betterOne = null; 111 | Object[] betterParam = null; 112 | for (Constructor cons : packetClass.getDeclaredConstructors()) { 113 | if (!cons.isAccessible()) 114 | cons.setAccessible(true); 115 | 116 | // check for basic method 117 | if(obj instanceof String) { 118 | if (cons.getParameterCount() == 2 && cons.getParameterTypes()[0].equals(String.class) && cons.getParameterTypes()[1].equals(int.class)) { // "string, int" 119 | return cons.newInstance(obj, 1); 120 | } else if (cons.getParameterCount() == 2 && cons.getParameterTypes()[0].equals(String.class) && cons.getParameterTypes()[1].equals(boolean.class)) { // "string, boolean" 121 | return cons.newInstance(obj, false); // false for no overlay 122 | } else if (cons.getParameterCount() == 3 && cons.getParameterTypes()[1].equals(String.class)) { // "component", "string", 123 | Class secondParam = cons.getParameterTypes()[2]; 124 | if (secondParam.equals(int.class)) // "component", "string", "int" 125 | return cons.newInstance(null, obj, 1); 126 | else if (secondParam.equals(boolean.class)) // "component", "string", "boolean" 127 | return cons.newInstance(null, obj, false); 128 | } 129 | } else if(obj.getClass().isAssignableFrom(PacketUtils.COMPONENT_CLASS)) { 130 | if (cons.getParameterCount() == 2 && cons.getParameterTypes()[0].isAssignableFrom(PacketUtils.COMPONENT_CLASS) && cons.getParameterTypes()[1].equals(boolean.class)) // "string, boolean" 131 | return cons.newInstance(obj, false); 132 | } 133 | 134 | int nbPut = 0; 135 | Object[] params = new Object[cons.getParameterCount()]; 136 | for(int i = 0; i < params.length; i++) { 137 | Class type = cons.getParameterTypes()[i]; 138 | if(type.isAssignableFrom(obj.getClass())) { 139 | params[i] = obj; 140 | nbPut++; 141 | } else if(chatMessageTypeClass != null && type.isAssignableFrom(chatMessageTypeClass)) { 142 | params[i] = getChatMessageType(); 143 | } else if(type.isAssignableFrom(boolean.class)) // need to set primitives 144 | params[i] = false; 145 | else if(type.isAssignableFrom(int.class)) // need to set primitives 146 | params[i] = 0; 147 | else { 148 | boolean found = false; 149 | for(Class prim : Arrays.asList(float.class, long.class)) { // if not primitive 150 | if(type.isAssignableFrom(prim)) { 151 | found = true; 152 | } 153 | } 154 | if(!found) { 155 | params[i] = new PacketContent(old).getSpecificModifier(type).readSafely(0); 156 | } 157 | } 158 | } 159 | if(nbPut == 1) { 160 | if((betterOne == null && betterParam == null) || betterParam.length > params.length) { 161 | betterOne = cons; 162 | betterParam = params; 163 | if(params.length == 1) // only what we need 164 | break; 165 | continue; // check for something better? 166 | } 167 | } else if(nbPut > 1) 168 | ChatItem.getInstance().getLogger().warning("Some constructor seems to have too many " + obj.getClass().getSimpleName() + ". Class: " + packetClass.getSimpleName()); 169 | } 170 | if(betterOne != null && betterParam != null) { 171 | try { 172 | return betterOne.newInstance(betterParam); 173 | } catch (IllegalArgumentException e) { 174 | ChatItem.getInstance().getLogger().warning("Failed to create a new packet to send. " + betterOne.getParameterCount() + " (" + Utils.arrayToString(betterOne.getParameterTypes()) + "). Params: " + Utils.arrayToString(betterParam)); 175 | return null; 176 | } 177 | } 178 | return null; 179 | } 180 | 181 | private static Object getChatMessageType() throws Exception { 182 | Class c = PacketUtils.getNmsClass("ChatMessageType", "network.chat."); 183 | return ReflectionUtils.getMethod(c, c, byte.class).invoke(null, (byte) 0); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/basecomp/IComponentManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.basecomp; 2 | 3 | import java.util.ArrayList; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | import org.bukkit.entity.Player; 8 | 9 | import com.google.gson.JsonArray; 10 | import com.google.gson.JsonElement; 11 | import com.google.gson.JsonObject; 12 | import com.google.gson.JsonParser; 13 | 14 | import me.dadus33.chatitem.ChatItem; 15 | import me.dadus33.chatitem.Storage; 16 | import me.dadus33.chatitem.chatmanager.Chat; 17 | import me.dadus33.chatitem.chatmanager.ChatManager; 18 | import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator; 19 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 20 | import me.dadus33.chatitem.utils.Utils; 21 | 22 | public interface IComponentManager { 23 | 24 | default boolean hasConditions() { 25 | return true; 26 | } 27 | 28 | String getBaseComponentAsJSON(ChatItemPacket packet); 29 | 30 | void writeJson(ChatItemPacket packet, String json); 31 | 32 | default @Nullable Chat getChat(String json) { 33 | json = ChatManager.fixSeparator(json); 34 | try { 35 | Chat possibleChat = Chat.getFrom(json); 36 | if (possibleChat != null) // found something with basic search 37 | return possibleChat; 38 | Chat chat = new Searching(json).search(); 39 | if (chat == null) 40 | ChatItem.debug("Failed to find chat for JSON " + json); 41 | return chat; 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } // not JSON 45 | return null; 46 | } 47 | 48 | default Object manageContent(Player viewer, Chat chat, ChatItemPacket packet, String json, Storage c) throws Exception { 49 | String message; 50 | if (Utils.isBeforeChatJson(viewer)) 51 | message = JSONManipulator.getInstance().parseEmpty(chat, json, chat.getAction().hasItem() ? ChatManager.getMaxLinesFromItem(viewer, chat.getAction().getItem()) : new ArrayList<>(), chat.getPlayer()); 52 | else 53 | message = JSONManipulator.getInstance().parse(chat, json, chat.getAction(), ChatManager.getNameForChatAction(viewer, chat, c)); 54 | if (message != null) { 55 | ChatItem.debug("(v1) Writing message: " + message); 56 | writeJson(packet, message); 57 | } 58 | return packet.getPacket(); 59 | } 60 | 61 | default Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, String json, Storage c) { 62 | String message = JSONManipulator.getInstance().parseEmpty(chat, json, c.tooltipHand, chat.getPlayer()); 63 | if (message != null) { 64 | ChatItem.debug("(v1) Writing empty message: " + message); 65 | writeJson(packet, message); 66 | } 67 | return packet.getPacket(); 68 | } 69 | 70 | public static class Searching { 71 | 72 | private boolean found = false; 73 | private String id = "", json; 74 | 75 | public Searching(String json) { 76 | this.json = json; 77 | } 78 | 79 | private Chat search() { 80 | JsonObject jsonObj; 81 | try { 82 | jsonObj = JsonParser.parseString(json).getAsJsonObject(); 83 | } catch (Exception e) { 84 | if(searchInString(json)) 85 | return getWithId(); 86 | return null; 87 | } 88 | if (jsonObj.has("extra")) { 89 | if (searchInExtra(jsonObj.getAsJsonArray("extra"))) { 90 | return getWithId(); 91 | } 92 | } 93 | if (jsonObj.has("text")) { 94 | JsonElement text = jsonObj.get("text"); 95 | if (text.isJsonObject() && searchInObject(text.getAsJsonObject())) 96 | return getWithId(); 97 | else if (text.isJsonArray() && searchInExtra(text.getAsJsonArray())) 98 | return getWithId(); 99 | else if (text.isJsonPrimitive() && searchInString(text.getAsString())) 100 | return getWithId(); 101 | } 102 | return null; 103 | } 104 | 105 | private Chat getWithId() { 106 | return id != "" && Utils.isInteger(id) ? Chat.getChat(Integer.parseInt(id)).orElse(null) : null; 107 | } 108 | 109 | private boolean searchInExtra(JsonArray json) { 110 | for (JsonElement element : json) { 111 | if (element.isJsonObject()) { 112 | JsonObject withObj = element.getAsJsonObject(); 113 | if (withObj.has("extra") && searchInExtra(withObj.getAsJsonArray("extra"))) 114 | return true; 115 | else if (withObj.has("text") && searchInObject(withObj)) 116 | return true; 117 | } 118 | } 119 | return false; 120 | } 121 | 122 | private boolean searchInObject(JsonObject json) { 123 | return json.has("text") && json.get("text").isJsonPrimitive() && searchInString(json.get("text").getAsString()); 124 | } 125 | 126 | private boolean searchInString(String s) { 127 | for (char c : ChatManager.fixSeparator(s).toCharArray()) { 128 | if (c == ChatManager.SEPARATOR) 129 | found = true; 130 | else if (c == ChatManager.SEPARATOR_END) 131 | return true; 132 | else if (found) 133 | id += c; 134 | } 135 | return id != "" && Utils.isInteger(id) && Chat.getChat(Integer.parseInt(id)).isPresent(); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/basecomp/hook/AdventureComponentManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.basecomp.hook; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.inventory.ItemStack; 7 | 8 | import com.google.gson.JsonObject; 9 | import com.google.gson.JsonParseException; 10 | 11 | import me.dadus33.chatitem.ChatItem; 12 | import me.dadus33.chatitem.Storage; 13 | import me.dadus33.chatitem.chatmanager.Chat; 14 | import me.dadus33.chatitem.chatmanager.ChatAction; 15 | import me.dadus33.chatitem.chatmanager.ChatManager; 16 | import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager; 17 | import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator; 18 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 19 | import me.dadus33.chatitem.hook.DiscordSrvSupport; 20 | import me.dadus33.chatitem.utils.Messages; 21 | import me.dadus33.chatitem.utils.PacketUtils; 22 | import me.dadus33.chatitem.utils.ReflectionUtils; 23 | import me.dadus33.chatitem.utils.Utils; 24 | import net.kyori.adventure.key.Key; 25 | import net.kyori.adventure.nbt.api.BinaryTagHolder; 26 | import net.kyori.adventure.text.Component; 27 | import net.kyori.adventure.text.TextReplacementConfig; 28 | import net.kyori.adventure.text.event.ClickEvent; 29 | import net.kyori.adventure.text.event.HoverEvent; 30 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 31 | 32 | public class AdventureComponentManager implements IComponentManager { 33 | 34 | @Override 35 | public boolean hasConditions() { 36 | try { 37 | for (String cl : Arrays.asList("net.kyori.adventure.text.Component", "net.kyori.adventure.text.serializer.gson.GsonComponentSerializer")) 38 | Class.forName(cl); 39 | } catch (Throwable e) { // can't support this, adventure comp not found 40 | ChatItem.debug("Can't load AdventureComponentManager : " + e.getMessage()); 41 | return false; 42 | } 43 | return true; 44 | } 45 | 46 | @Override 47 | public void writeJson(ChatItemPacket packet, String json) { 48 | } 49 | 50 | public void writeComponentToPacket(ChatItemPacket packet, Component next) { 51 | if(packet.getContent().getSpecificModifier(Component.class).readSafely(0) == null && ReflectionUtils.hasObject(packet.getPacket(), "unsignedContent")) { // hard way 52 | ReflectionUtils.setField(ReflectionUtils.getObject(packet.getPacket(), "unsignedContent"), "adventure", next); 53 | } else { // easy way 54 | packet.getContent().getSpecificModifier(Component.class).write(0, next); 55 | } 56 | } 57 | 58 | public Component getComponentFromPacket(ChatItemPacket packet) { 59 | Component comp = packet.getContent().getSpecificModifier(Component.class).readSafely(0); 60 | if (comp == null && packet.getPacketName().equalsIgnoreCase("ClientboundPlayerChatPacket") && ReflectionUtils.hasObject(packet.getPacket(), "unsignedContent")) { // if can get one more 61 | comp = (Component) ReflectionUtils.getObject(ReflectionUtils.getObject(packet.getPacket(), "unsignedContent"), "adventure"); 62 | } 63 | return comp; 64 | } 65 | 66 | @Override 67 | public String getBaseComponentAsJSON(ChatItemPacket packet) { 68 | Component comp = getComponentFromPacket(packet); 69 | if(comp == null) // if comp stay null 70 | return null; 71 | try { 72 | String json = GsonComponentSerializer.gson().serialize(comp); 73 | ChatItem.debug("AdventureJSON : " + json); 74 | JsonObject jsonObj = JSONManipulator.parseOrGet(json); 75 | if (jsonObj.has("with")) { 76 | JsonObject next = new JsonObject(); 77 | next.add("extra", jsonObj.get("with")); 78 | return next.toString(); 79 | } 80 | return json; 81 | } catch (JsonParseException e) { // ignore this and just let skip this 82 | e.printStackTrace(); 83 | return null; 84 | } 85 | } 86 | 87 | @SuppressWarnings("deprecation") 88 | @Override 89 | public Object manageContent(Player viewer, Chat chat, ChatItemPacket packet, String json, Storage c) throws Exception { 90 | ChatAction action = chat.getAction(); 91 | if (action.hasItem()) { 92 | ItemStack item = action.getItem(); 93 | String itemName = ChatManager.getNameForChatAction(viewer, chat, c); 94 | ChatItem.debug("NBT tag: " + PacketUtils.getNbtTag(item)); 95 | HoverEvent hover; 96 | if(Utils.IS_PAPER) 97 | hover = item.asHoverEvent(); 98 | else 99 | hover = HoverEvent.showItem(Key.key(item.getType().getKey().getKey()), item.getAmount(), BinaryTagHolder.of(PacketUtils.getNbtTag(item))); 100 | return manage(viewer, chat, packet, itemName, hover, null); 101 | } 102 | return manage(viewer, chat, packet, Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", chat.getPlayer().getName()), 103 | HoverEvent.showText(Component.text(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName()))), 104 | ClickEvent.runCommand(action.getCommand())); 105 | } 106 | 107 | @Override 108 | public Object manageEmpty(Player viewer, Chat chat, ChatItemPacket packet, String json, Storage c) { 109 | Component builder = Component.text(""); 110 | c.tooltipHand.forEach(s -> builder.append(Component.text(s))); 111 | ChatAction action = chat.getAction(); 112 | if (action.hasItem()) { 113 | return manage(viewer, chat, packet, ChatManager.getNameForChatAction(viewer, chat, c), HoverEvent.showText(builder), null); 114 | } 115 | return manage(viewer, chat, packet, Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", chat.getPlayer().getName()), 116 | HoverEvent.showText(Component.text(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName()))), 117 | ClickEvent.runCommand(action.getCommand())); 118 | } 119 | 120 | private Object manage(Player viewer, Chat chat, ChatItemPacket packet, String replacement, HoverEvent hover, ClickEvent click) { 121 | Component comp = getComponentFromPacket(packet); 122 | if (comp == null) { 123 | ChatItem.debug("The component is null."); 124 | return null; 125 | } 126 | comp = comp.replaceText(TextReplacementConfig.builder().matchLiteral(ChatManager.SEPARATOR + "" + chat.getId() + ChatManager.SEPARATOR_END).replacement(Component.text(replacement).hoverEvent(hover).clickEvent(click)).build()); 127 | if(ChatItem.discordSrvSupport && DiscordSrvSupport.isSendingMessage() && viewer == chat.getPlayer()) 128 | DiscordSrvSupport.sendChatMessage(chat.getPlayer(), comp, null); 129 | viewer.sendMessage(comp); 130 | return null; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/basecomp/hook/ComponentNMSManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.basecomp.hook; 2 | 3 | import com.google.gson.JsonParser; 4 | 5 | import me.dadus33.chatitem.ChatItem; 6 | import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager; 7 | import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager; 8 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 9 | import me.dadus33.chatitem.hook.DiscordSrvSupport; 10 | 11 | public class ComponentNMSManager implements IComponentManager { 12 | 13 | @Override 14 | public boolean hasConditions() { 15 | return ChatItem.getPlatform().hasBaseComponentSerializer(); 16 | } 17 | 18 | @Override 19 | public String getBaseComponentAsJSON(ChatItemPacket packet) { 20 | Object chatBaseComp = packet.getContent().getChatComponents().readSafely(0); 21 | if (chatBaseComp != null) { 22 | try { 23 | Object o = ChatItem.getPlatform().baseComponentToJson(chatBaseComp); 24 | if(o != null && o instanceof String && JsonParser.parseString((String) o).isJsonObject()) { 25 | return (String) o; 26 | } 27 | } catch (Exception exc) { 28 | exc.printStackTrace(); 29 | } 30 | } 31 | return null; 32 | } 33 | 34 | @Override 35 | public void writeJson(ChatItemPacket packet, String json) { 36 | // Not compatible with that for now 37 | if(ChatItem.discordSrvSupport && DiscordSrvSupport.isSendingMessage()) 38 | ChatItem.debug("(v1 ComponentNMS) Can't send message to discord"); 39 | // DiscordSrvSupport.sendChatMessage(p, comp, null); 40 | try { 41 | packet.setPacket(PacketEditingChatManager.createSystemChatPacket(json, packet.getPacket())); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/basecomp/hook/IChatBaseComponentManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.basecomp.hook; 2 | 3 | import me.dadus33.chatitem.ChatItem; 4 | import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager; 5 | import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager; 6 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 7 | 8 | public class IChatBaseComponentManager implements IComponentManager { 9 | 10 | @Override 11 | public boolean hasConditions() { 12 | return ChatItem.getPlatform().hasBaseComponentSerializer(); 13 | } 14 | 15 | @Override 16 | public String getBaseComponentAsJSON(ChatItemPacket packet) { 17 | try { 18 | Object obj = packet.getContent().getChatComponents().readSafely(0); 19 | return obj == null ? null : (String) ChatItem.getPlatform().baseComponentToJson(obj); 20 | } catch (Exception exc) { 21 | exc.printStackTrace(); 22 | } 23 | return null; 24 | } 25 | 26 | @Override 27 | public void writeJson(ChatItemPacket packet, String json) { 28 | try { 29 | packet.setPacket(PacketEditingChatManager.createSystemChatPacket(json, packet.getPacket())); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/basecomp/hook/PCMComponentManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.basecomp.hook; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.util.Arrays; 5 | 6 | import me.dadus33.chatitem.ChatItem; 7 | import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager; 8 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 9 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent.ContentModifier; 10 | import me.dadus33.chatitem.utils.PacketUtils; 11 | import me.dadus33.chatitem.utils.ReflectionUtils; 12 | 13 | public class PCMComponentManager implements IComponentManager { 14 | 15 | @Override 16 | public boolean hasConditions() { 17 | try { 18 | for (String cl : Arrays.asList("net.minecraft.network.chat.PlayerChatMessage")) 19 | Class.forName(cl); 20 | } catch (Exception e) { // can't support this 21 | ChatItem.debug("Can't load PCMComponentManager : " + e.getMessage()); 22 | return false; 23 | } 24 | return true; 25 | } 26 | 27 | @Override 28 | public String getBaseComponentAsJSON(ChatItemPacket packet) { 29 | Class pcmClass = PacketUtils.getNmsClass("PlayerChatMessage", "network.chat."); 30 | Object pcm = packet.getContent().getSpecificModifier(pcmClass).readSafely(0); 31 | if (pcm != null) { 32 | try { 33 | Object chatBaseComp = ReflectionUtils.getMethod(pcmClass, PacketUtils.COMPONENT_CLASS).invoke(pcm); 34 | if(chatBaseComp != null) 35 | ChatItem.debug("[PCMManager] Founded " + chatBaseComp.getClass().getSimpleName()); 36 | return chatBaseComp == null ? null : ChatItem.getPlatform().baseComponentToJson(chatBaseComp); 37 | } catch (Exception exc) { 38 | exc.printStackTrace(); 39 | } 40 | } 41 | return null; 42 | } 43 | 44 | @Override 45 | public void writeJson(ChatItemPacket packet, String json) { 46 | try { 47 | Object chatComp = ChatItem.getPlatform().jsonToBaseComponent(json); 48 | Class pcmClass = PacketUtils.getNmsClass("PlayerChatMessage", "network.chat."); 49 | ContentModifier pcmModifier = packet.getContent().getSpecificModifier((Class) pcmClass); 50 | Object pcm = ReflectionUtils.getMethod(pcmClass, pcmClass, PacketUtils.COMPONENT_CLASS).invoke(pcmModifier.readSafely(0), chatComp); 51 | for(Constructor cons : packet.getPacket().getClass().getConstructors()) { 52 | if(cons.getParameterCount() <= 1) 53 | continue; 54 | Object[] params = new Object[cons.getParameterCount()]; 55 | for(int i = 0; i < params.length; i++) { 56 | Class cls = cons.getParameterTypes()[i]; 57 | if(cls.equals(pcmClass)) { 58 | params[i] = pcm; 59 | } else 60 | params[i] = packet.getContent().getSpecificModifier(cls).readSafely(0); 61 | } 62 | packet.setPacket(cons.newInstance(params)); 63 | } 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/basecomp/hook/StringComponentManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.basecomp.hook; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.bukkit.entity.Player; 6 | 7 | import com.google.gson.JsonArray; 8 | import com.google.gson.JsonElement; 9 | import com.google.gson.JsonObject; 10 | import com.google.gson.JsonParser; 11 | 12 | import me.dadus33.chatitem.ChatItem; 13 | import me.dadus33.chatitem.Storage; 14 | import me.dadus33.chatitem.chatmanager.Chat; 15 | import me.dadus33.chatitem.chatmanager.ChatAction; 16 | import me.dadus33.chatitem.chatmanager.ChatManager; 17 | import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager; 18 | import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager; 19 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 20 | import me.dadus33.chatitem.hook.DiscordSrvSupport; 21 | import me.dadus33.chatitem.utils.Messages; 22 | import me.dadus33.chatitem.utils.Utils; 23 | import net.md_5.bungee.api.chat.BaseComponent; 24 | import net.md_5.bungee.api.chat.ClickEvent; 25 | import net.md_5.bungee.api.chat.ComponentBuilder; 26 | import net.md_5.bungee.api.chat.HoverEvent; 27 | import net.md_5.bungee.api.chat.TextComponent; 28 | import net.md_5.bungee.chat.ComponentSerializer; 29 | 30 | public class StringComponentManager implements IComponentManager { 31 | 32 | @Override 33 | public String getBaseComponentAsJSON(ChatItemPacket packet) { 34 | String json = packet.getContent().getStrings().readSafely(0); 35 | if (json != null && json.startsWith("[") && json.endsWith("]")) { // if used as array instead of json obj 36 | JsonArray extra = new JsonArray(); 37 | for (JsonElement element : JsonParser.parseString(json).getAsJsonArray()) { 38 | if (element.isJsonObject()) { // ignore this 39 | extra.add(element); 40 | } else { 41 | ChatItem.debug("Ignoring element " + element); 42 | } 43 | } 44 | JsonObject jsonObject = new JsonObject(); 45 | jsonObject.addProperty("text", ""); 46 | jsonObject.add("extra", extra); 47 | json = jsonObject.toString(); 48 | } else if (json == null) { 49 | BaseComponent[] comp = packet.getContent().getSpecificModifier(BaseComponent[].class).readSafely(0); 50 | if (comp != null) 51 | return ComponentSerializer.toString(comp); 52 | } 53 | return json; 54 | } 55 | 56 | @Override 57 | public void writeJson(ChatItemPacket packet, String json) { 58 | try { 59 | packet.setPacket(PacketEditingChatManager.createSystemChatPacket(json, packet.getPacket())); 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | } 63 | } 64 | 65 | @Override 66 | public Object manageContent(Player viewer, Chat chat, ChatItemPacket packet, String json, Storage c) throws Exception { 67 | ChatAction action = chat.getAction(); 68 | if (action.hasItem()) 69 | return manage(viewer, chat, packet, ChatManager.getNameForChatAction(viewer, chat, c), Utils.createItemHover(action.getItem(), viewer), null); 70 | else 71 | return manage(viewer, chat, packet, ChatManager.getNameForChatAction(viewer, chat, c), 72 | Utils.createTextHover(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName())), Utils.createRunCommand(action.getCommand())); 73 | } 74 | 75 | @Override 76 | public Object manageEmpty(Player viewer, Chat chat, ChatItemPacket packet, String json, Storage c) { 77 | ComponentBuilder builder = new ComponentBuilder(""); 78 | c.tooltipHand.forEach(s -> builder.append(s)); 79 | HoverEvent hover; 80 | ClickEvent click; 81 | String rep; 82 | ChatAction action = chat.getAction(); 83 | if (action.hasItem()) { 84 | hover = Utils.createTextHover(builder.create()); 85 | rep = ChatManager.getHandName(chat); 86 | click = null; 87 | } else { 88 | hover = Utils.createTextHover(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName())); 89 | rep = Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", chat.getPlayer().getName()); 90 | click = Utils.createRunCommand(action.getCommand()); 91 | } 92 | return manage(viewer, chat, packet, rep, hover, click); 93 | } 94 | 95 | private Object manage(Player viewer, Chat chat, ChatItemPacket packet, String replacement, HoverEvent hover, ClickEvent click) { 96 | BaseComponent[] components = packet.getContent().getSpecificModifier(BaseComponent[].class).readSafely(0); 97 | if (components == null) { 98 | String json = packet.getContent().getStrings().readSafely(0); 99 | if (json != null && json.startsWith("[") && json.endsWith("]")) { // if used as array instead of json obj 100 | JsonArray extra = new JsonArray(); 101 | for (JsonElement element : JsonParser.parseString(json).getAsJsonArray()) { 102 | if (element.isJsonObject()) { // ignore this 103 | extra.add(element); 104 | } else { 105 | ChatItem.debug("Ignoring element " + element); 106 | } 107 | } 108 | JsonObject jsonObject = new JsonObject(); 109 | jsonObject.addProperty("text", ""); 110 | jsonObject.add("extra", extra); 111 | json = jsonObject.toString(); 112 | } 113 | ChatItem.debug("[StringComponentManager] Using JSON " + json); 114 | try { 115 | components = ComponentSerializer.parse(json); 116 | } catch (Exception e) { 117 | ChatItem.getInstance().getLogger().severe("Failed to parse JSON: " + json + ". Error:"); 118 | e.printStackTrace(); 119 | return packet.getPacket(); 120 | } 121 | } 122 | ChatItem.debug("Checking for " + components.length + " components"); 123 | Arrays.asList(components).forEach(comp -> checkComponent(comp, hover, click, replacement, chat)); 124 | 125 | if (ChatItem.discordSrvSupport && DiscordSrvSupport.isSendingMessage() && viewer == chat.getPlayer()) 126 | DiscordSrvSupport.sendChatMessage(viewer, TextComponent.toLegacyText(components), null); 127 | try { 128 | packet.setPacket(PacketEditingChatManager.createSystemChatPacket(ComponentSerializer.toString(components), packet.getPacket())); 129 | } catch (Exception e) { 130 | e.printStackTrace(); 131 | } 132 | return packet.getPacket(); 133 | } 134 | 135 | private void checkComponent(BaseComponent comp, HoverEvent hover, ClickEvent click, String itemName, Chat chat) { 136 | if (comp instanceof TextComponent) { 137 | TextComponent tc = (TextComponent) comp; 138 | if (ChatManager.containsSeparator(tc.getText())) { 139 | String oldText = tc.getText(); 140 | ChatItem.debug("Changing text " + oldText + " to " + itemName + ", extra: " + (tc.getExtra() == null ? "-" : tc.getExtra().size())); 141 | tc.setText(ChatManager.replaceSeparator(chat, oldText, itemName)); 142 | tc.setHoverEvent(hover); 143 | if (click != null) 144 | tc.setClickEvent(click); 145 | } else 146 | ChatItem.debug("No insert of text without separator: " + tc.getText() + " (legacy: " + tc.toLegacyText() + ")"); 147 | } 148 | if (comp.getExtra() != null) { 149 | for (BaseComponent extra : comp.getExtra()) { 150 | checkComponent(extra, hover, click, itemName, chat); 151 | } 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/json/Translator.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.json; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | 7 | import me.dadus33.chatitem.ChatItem; 8 | import me.dadus33.chatitem.utils.ColorManager; 9 | import net.md_5.bungee.api.ChatColor; 10 | 11 | //Based on DarkSeraphim's system, but using Gson and supporting some more edge cases 12 | public class Translator { 13 | 14 | private static final String STYLES = "klmnor"; //All style codes 15 | 16 | 17 | public static JsonArray toJson(String old){ 18 | if(old.lastIndexOf(ChatColor.COLOR_CHAR) == -1){ 19 | JsonArray arr = new JsonArray(); 20 | JsonObject obj = new JsonObject(); 21 | obj.addProperty("text", old); 22 | arr.add(obj); 23 | return arr; 24 | } 25 | JsonArray message = new JsonArray(); 26 | JsonObject next = new JsonObject(); 27 | String colorCode = "", text = ""; 28 | boolean waiting = false; 29 | for (char args : old.toCharArray()) { 30 | if (args == '§') { // begin of color 31 | if(!text.isEmpty()) { 32 | next.addProperty("text", text); 33 | message.add(next); 34 | next = new JsonObject(); 35 | text = ""; 36 | } 37 | waiting = true; // waiting for color code 38 | } else if (waiting) { // if waiting for code and valid str 39 | // if it's hexademical value and with enough space for full color 40 | waiting = false; 41 | if(isStyle(args)) { // is style and not making rich color code 42 | next.addProperty(getStyleName(args), true); 43 | continue; 44 | } 45 | if(args == 'x' && !colorCode.isEmpty()) { 46 | if(!text.isEmpty()) // ignore this if no text before 47 | text += ColorManager.getColorString(colorCode); 48 | colorCode = "x"; 49 | } else if(!colorCode.isEmpty() && !colorCode.startsWith("x")) { // already color and not hex 50 | text += ColorManager.COLOR_CHAR + colorCode; // add the color to text 51 | colorCode = args + ""; 52 | } else 53 | colorCode += args; // a color by itself 54 | } else { 55 | if(!colorCode.isEmpty()) { // manage color 56 | if(colorCode.startsWith("x") && colorCode.length() == 7) { // hex color code 57 | next.addProperty("color", ColorManager.getColor(colorCode).getName()); 58 | } else if(colorCode.length() == 1) { // if only one color code 59 | if(next.has("color")) 60 | text += ColorManager.getColor(colorCode); 61 | else 62 | next.addProperty("color", ColorManager.getColor(colorCode).getName()); 63 | } else if(!text.isEmpty()) // no text before -> color will be used as "color" 64 | text += ColorManager.getColorString(colorCode); 65 | 66 | ChatItem.debug("[Translator] Add color code " + colorCode + " to " + text + args + ", msg: " + message); 67 | colorCode = ""; 68 | } 69 | // basic text, not waiting for code after '§' 70 | text += args; 71 | } 72 | } 73 | if(!next.has("color") || colorCode.length() == 1) // if no color or a color that can override it 74 | next.addProperty("color", (colorCode.length() == 1 ? ColorManager.getColor(colorCode).getName() : "white")); 75 | if(!text.isEmpty() || message.isEmpty() || next.size() > 0) { 76 | next.addProperty("text", text); 77 | ChatItem.debug("[Translator] Added content " + next + " to message" + message); 78 | message.add(next); 79 | } 80 | return message; 81 | } 82 | 83 | public static JsonArray toJsonOld(String old){ 84 | if(old.lastIndexOf(ChatColor.COLOR_CHAR) == -1){ 85 | JsonArray arr = new JsonArray(); 86 | JsonObject obj = new JsonObject(); 87 | obj.addProperty("text", old); 88 | arr.add(obj); 89 | return arr; 90 | } 91 | boolean startsWithCode = old.startsWith(Character.toString(ChatColor.COLOR_CHAR)); 92 | JsonArray message = new JsonArray(); 93 | String[] parts = old.split(Character.toString(ChatColor.COLOR_CHAR)); 94 | JsonObject next = null; //refers to the object we created before (in time) but next in the message, as we're going from end to start 95 | for(int i = parts.length-1; i >= 0; --i){ //We go in reverse order 96 | String part = parts[i]; 97 | 98 | if(part.isEmpty()){ 99 | continue; 100 | } 101 | 102 | if(i == 0 && !startsWithCode){ 103 | JsonObject toAdd = new JsonObject(); 104 | toAdd.addProperty("text", part); 105 | message.add(toAdd); 106 | break; 107 | } 108 | 109 | char code = Character.toLowerCase(part.charAt(0)); 110 | 111 | if(!isColorOrStyle(code)){ 112 | if(next != null){ 113 | String text = next.get("text").getAsString(); 114 | text = ChatColor.COLOR_CHAR + part + text; 115 | next.addProperty("text", text); 116 | }else{ 117 | JsonObject added = new JsonObject(); 118 | added.addProperty("text", ChatColor.COLOR_CHAR + part); 119 | message.add(added); 120 | next = added; 121 | } 122 | continue; 123 | } 124 | 125 | if(part.length() == 1){ //If it's just format and no text, we try to format the next element, if it wasn't formatted already (and it's not null) 126 | if(next == null){ 127 | continue; 128 | } 129 | 130 | if(isStyle(code)){ 131 | next.addProperty(getStyleName(code), true); 132 | }else{ //it's a color 133 | if(isAlreadyColored(next)){ 134 | continue; 135 | } 136 | next.addProperty("color", getColorName(code)); 137 | } 138 | continue; 139 | } 140 | //Last possibility that remains is that we have a normal color/format + text situation 141 | JsonObject added = new JsonObject(); 142 | added.addProperty("text", part.substring(1)); 143 | if(isStyle(code)){ 144 | added.addProperty(getStyleName(code), true); 145 | message.add(added); 146 | next = added; 147 | continue; 148 | } 149 | //else it can only be a color 150 | added.addProperty("color", getColorName(code)); 151 | //also try to color the next element if not colored already 152 | if(next != null){ 153 | if(!isAlreadyColored(next)){ 154 | next.addProperty("color", getColorName(code)); 155 | } 156 | } 157 | message.add(added); 158 | next = added; 159 | } 160 | 161 | int i = message.size()-1; 162 | JsonArray orderedMessage = new JsonArray();//This is where we'll store the reverted message (in proper order for being sent to the client) 163 | //First we have to copy all elements 164 | for(JsonElement el : message){ 165 | orderedMessage.add(el); 166 | } 167 | for(JsonElement element : message){ 168 | JsonObject obj = (JsonObject) element; 169 | orderedMessage.set(i, obj); //And then we add the object to the properly ordered array 170 | --i; 171 | } 172 | 173 | return orderedMessage; 174 | } 175 | 176 | private static String getColorName(char code){ 177 | return ChatColor.getByChar(code).getName().toLowerCase(); 178 | } 179 | 180 | private static String getStyleName(char code){ 181 | switch(code){ 182 | case 'k': return "obfuscated"; 183 | case 'l': return "bold"; 184 | case 'm': return "strikethrough"; 185 | case 'n': return "underlined"; 186 | case 'o': return "italic"; 187 | case 'r': return "reset"; 188 | default: 189 | ChatItem.getInstance().getLogger().severe("Can't find code for style " + code); 190 | return null; //Should never happen. Made it return null to throw errors if a new format pops up and it really happens 191 | } 192 | } 193 | 194 | private static boolean isColorOrStyle(char code){ 195 | return ChatColor.getByChar(code) != null; 196 | } 197 | 198 | private static boolean isStyle(char c){ 199 | return STYLES.indexOf(c) != -1; 200 | } 201 | 202 | private static boolean isAlreadyColored(JsonObject obj){ 203 | return obj.has("color"); 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/ChatItemPacket.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | public class ChatItemPacket { 6 | 7 | protected final Player player; 8 | protected Object packet; 9 | protected PacketType type; 10 | protected boolean cancel = false; 11 | 12 | public ChatItemPacket(PacketType type, Object packet, Player player) { 13 | this.player = player; 14 | this.packet = packet; 15 | this.type = type; 16 | } 17 | 18 | public Player getPlayer() { 19 | return player; 20 | } 21 | 22 | public boolean hasPlayer() { 23 | return player != null; 24 | } 25 | 26 | public String getPlayername() { 27 | return getPlayer().getName(); 28 | } 29 | 30 | public Object getPacket() { 31 | return packet; 32 | } 33 | 34 | public void setPacket(Object packet) { 35 | this.packet = packet; 36 | } 37 | 38 | public String getPacketName() { 39 | return packet.getClass().getSimpleName(); 40 | } 41 | 42 | public PacketType getPacketType() { 43 | return type; 44 | } 45 | 46 | public boolean isCancelled() { 47 | return cancel; 48 | } 49 | 50 | public void setCancelled(boolean cancel) { 51 | this.cancel = cancel; 52 | } 53 | 54 | public PacketContent getContent() { 55 | return new PacketContent(this); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/ChatItemPacketManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.plugin.Plugin; 7 | 8 | import me.dadus33.chatitem.ChatItem; 9 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager; 10 | import me.dadus33.chatitem.chatmanager.v1.packets.protocollib.ProtocollibPacketManager; 11 | 12 | public class ChatItemPacketManager { 13 | 14 | private PacketManager packetManager; 15 | 16 | public ChatItemPacketManager(ChatItem pl) { 17 | Plugin protocolLibPlugin = Bukkit.getPluginManager().getPlugin("ProtocolLib"); 18 | if (protocolLibPlugin != null) { 19 | if(checkProtocollibConditions()) { 20 | pl.getLogger().info("The plugin ProtocolLib has been detected. Loading Protocollib support ..."); 21 | packetManager = new ProtocollibPacketManager(pl); 22 | } else { 23 | pl.getLogger().warning("The plugin ProtocolLib has been detected but you have an old or too new version, so we cannot use it."); 24 | pl.getLogger().warning("Fallback to default Packet system ..."); 25 | packetManager = new CustomPacketManager(pl); 26 | } 27 | } else { 28 | pl.getLogger().info("Loading own packet system."); 29 | packetManager = new CustomPacketManager(pl); 30 | } 31 | } 32 | 33 | public PacketManager getPacketManager() { 34 | return packetManager; 35 | } 36 | 37 | private boolean checkProtocollibConditions() { 38 | for(String searchedClass : Arrays.asList("com.comphenix.protocol.injector.server.TemporaryPlayer", "com.comphenix.protocol.injector.temporary.TemporaryPlayer")) { // class since 4.4.0 until 4.8.0, then the new one 39 | try { 40 | Class.forName(searchedClass); 41 | return true; // class found 42 | } catch (ClassNotFoundException e) {} 43 | } 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/PacketContent.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.NoSuchElementException; 7 | import java.util.Objects; 8 | import java.util.stream.Collectors; 9 | 10 | import me.dadus33.chatitem.utils.PacketUtils; 11 | 12 | public class PacketContent { 13 | 14 | 15 | private final ChatItemPacket packet; 16 | private final Object obj; 17 | 18 | /** 19 | * Create a PacketContent to easily read and write value in it 20 | * 21 | * @param packet the Negativity's packet 22 | */ 23 | public PacketContent(ChatItemPacket packet) { 24 | this.packet = packet; 25 | this.obj = packet.getPacket(); 26 | } 27 | 28 | /** 29 | * Create a PacketContent to easily read and write to the specified object 30 | * 31 | * @param obj the object that will be read or edit 32 | */ 33 | public PacketContent(Object obj) { 34 | this.packet = null; 35 | this.obj = obj; 36 | } 37 | 38 | public ChatItemPacket getPacket() { 39 | return packet; 40 | } 41 | 42 | public ContentModifier getSpecificModifier(T type){ 43 | return new ContentModifier(obj, type.getClass()); 44 | } 45 | 46 | public ContentModifier getSpecificModifier(Class clazz){ 47 | return new ContentModifier(obj, clazz); 48 | } 49 | 50 | public ContentModifier getStrings(){ 51 | return new ContentModifier(obj, String.class); 52 | } 53 | 54 | public ContentModifier getBytes(){ 55 | return new ContentModifier(obj, byte.class); 56 | } 57 | 58 | public ContentModifier getBooleans(){ 59 | return new ContentModifier(obj, boolean.class); 60 | } 61 | 62 | public ContentModifier getIntegers(){ 63 | return new ContentModifier(obj, int.class); 64 | } 65 | 66 | public ContentModifier getByteArrays(){ 67 | return new ContentModifier(obj, byte[].class); 68 | } 69 | 70 | public ContentModifier getChatComponents() { 71 | return (ContentModifier) getSpecificModifier(PacketUtils.COMPONENT_CLASS); 72 | } 73 | 74 | public static class ContentModifier { 75 | 76 | private Object obj; 77 | private HashMap content = new HashMap<>(); 78 | 79 | public ContentModifier(Object obj, Class clazz) { 80 | this.obj = obj; 81 | 82 | for(Field f : obj.getClass().getDeclaredFields()) { 83 | try { 84 | if(f.getType().isAssignableFrom(clazz)) { 85 | f.setAccessible(true); 86 | content.put(f, (T) f.get(obj)); 87 | } 88 | } catch (Exception e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | if(!obj.getClass().getSuperclass().equals(Object.class)) { 93 | for(Field f : obj.getClass().getSuperclass().getDeclaredFields()) { 94 | try { 95 | if(f.getType().isAssignableFrom(clazz)) { 96 | f.setAccessible(true); 97 | content.put(f, (T) f.get(obj)); 98 | } 99 | } catch (Exception e) { 100 | e.printStackTrace(); 101 | } 102 | } 103 | } 104 | } 105 | 106 | public Object getObj() { 107 | return obj; 108 | } 109 | 110 | /** 111 | * Get the size of the Map of content 112 | * 113 | * @return the number of content 114 | */ 115 | public int size() { 116 | return content.size(); 117 | } 118 | 119 | /** 120 | * Get the value of the field which is named by the given one 121 | * 122 | * @param fieldName the name of the needed field 123 | * @return the value of the field 124 | */ 125 | public T read(String fieldName) { 126 | for(Field field : content.keySet()) 127 | if(field.getName().equalsIgnoreCase(fieldName)) 128 | return content.get(field); 129 | return null; 130 | } 131 | 132 | /** 133 | * Get the value of the field which is named by the given one 134 | * 135 | * @param fieldName the name of the needed field 136 | * @param defaultValue the returned value if there is no value 137 | * @return the value of the field 138 | */ 139 | public T read(String fieldName, T defaultValue) { 140 | for(Field field : content.keySet()) 141 | if(field.getName().equalsIgnoreCase(fieldName)) 142 | return content.get(field); 143 | return defaultValue; 144 | } 145 | 146 | /** 147 | * Read the specified value. 148 | * 149 | * @param i the number of the value to get getted. Start at 0. 150 | * @return the requested value. 151 | * 152 | * @throws NoSuchElementException if the value doesn't exist 153 | */ 154 | public T read(int i) { 155 | return content.values().stream().filter(Objects::nonNull).collect(Collectors.toList()).get(i); 156 | } 157 | 158 | /** 159 | * Read the specified value. 160 | * 161 | * @param i the number of the value to get getted. Start at 0. 162 | * @return the requested value, or null if it doesn't exist. 163 | */ 164 | public T readSafely(int i) { 165 | return readSafely(i, null); 166 | } 167 | 168 | /** 169 | * Read the specified value. 170 | * 171 | * @param i the number of the value to get getted. Start at 0. 172 | * @param defaultValue the value which is return if the key doesn't exist 173 | * @return the requested value. 174 | */ 175 | public T readSafely(int i, T defaultValue) { 176 | List vals = content.values().stream().filter(Objects::nonNull).collect(Collectors.toList()); 177 | return vals.size() <= i ? defaultValue : vals.get(i); 178 | } 179 | 180 | /** 181 | * Set the value in the specified object. 182 | * 183 | * @param i the key of the value to set 184 | * @param value the new value which will be set 185 | */ 186 | public void write(int i, T value) { 187 | Field key = content.keySet().toArray(new Field[] {})[i]; 188 | if(key == null) { 189 | new NoSuchFieldException("Not enough value in " + obj.getClass() + ".").printStackTrace(); 190 | } else { 191 | content.put(key, value); 192 | try { 193 | key.setAccessible(true); 194 | key.set(obj, value); 195 | } catch (Exception e) { 196 | e.printStackTrace(); 197 | } 198 | } 199 | } 200 | 201 | /** 202 | * Get field which her value 203 | * 204 | * @return all content 205 | */ 206 | public HashMap getContent(){ 207 | return content; 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/PacketHandler.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets; 2 | 3 | public abstract class PacketHandler { 4 | 5 | public void onReceive(ChatItemPacket packet) {} 6 | public void onSend(ChatItemPacket packet) {} 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/PacketManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets; 2 | 3 | import java.util.ArrayList; 4 | 5 | import org.bukkit.entity.Player; 6 | 7 | public abstract class PacketManager { 8 | 9 | public void addPlayer(Player p) {} 10 | public void removePlayer(Player p) {} 11 | public abstract void stop(); 12 | 13 | private final ArrayList handlers = new ArrayList<>(); 14 | public boolean addHandler(PacketHandler handler) { 15 | return !handlers.add(handler); 16 | } 17 | 18 | public boolean removeHandler(PacketHandler handler) { 19 | return handlers.remove(handler); 20 | } 21 | 22 | public void notifyHandlersSent(ChatItemPacket packet) { 23 | handlers.forEach((handler) -> handler.onSend(packet)); 24 | } 25 | 26 | public ChatItemPacket onPacketSent(PacketType type, Player sender, Object packet) { 27 | if(type == null) { 28 | return null; 29 | } 30 | ChatItemPacket customPacket = new ChatItemPacket(type, packet, sender); 31 | notifyHandlersSent(customPacket); 32 | return customPacket; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/PacketType.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | public interface PacketType { 8 | 9 | String name(); 10 | String getPacketName(); 11 | String getFullName(); 12 | List getAlias(); 13 | 14 | public static List values() { 15 | List list = new ArrayList<>(); 16 | list.addAll(Arrays.asList(Server.values())); 17 | list.addAll(Arrays.asList(Handshake.values())); 18 | return list; 19 | } 20 | 21 | static final String SERVER_PREFIX = "PacketPlayOut", HANDSHAKE_PREFIX = "PacketHandshaking"; 22 | 23 | public static PacketType getType(String packetName) { 24 | if(packetName.startsWith(SERVER_PREFIX)) { 25 | return getPacketTypeFor(packetName, Server.values(), Server.UNSET); 26 | } else if(packetName.startsWith(HANDSHAKE_PREFIX)) { 27 | return getPacketTypeFor(packetName, Handshake.values(), Handshake.UNSET); 28 | } else { 29 | for(PacketType types : values()) { 30 | if(types.getFullName().equalsIgnoreCase(packetName) || types.getAlias().contains(packetName)) 31 | return types; 32 | } 33 | return null; 34 | } 35 | } 36 | 37 | static PacketType getPacketTypeFor(String packetName, PacketType[] types, PacketType unset) { 38 | for(PacketType packet : types) 39 | if(packet.getFullName().equalsIgnoreCase(packetName) || packet.getPacketName().equalsIgnoreCase(packetName) || packet.getAlias().contains(packetName)) 40 | return packet; 41 | return unset; 42 | } 43 | 44 | public static enum Server implements PacketType { 45 | 46 | CHAT("Chat", "ClientboundPlayerChatPacket", "ClientboundSystemChatPacket"), 47 | UNSET("Unset"); 48 | 49 | private final String packetName, fullName; 50 | private List alias = new ArrayList<>(); 51 | 52 | private Server(String packetName, String... alias) { 53 | this.packetName = packetName; 54 | this.fullName = SERVER_PREFIX + packetName; 55 | for(String al : alias) 56 | this.alias.add(al); 57 | } 58 | 59 | @Override 60 | public String getPacketName() { 61 | return packetName; 62 | } 63 | 64 | @Override 65 | public String getFullName() { 66 | return fullName; 67 | } 68 | 69 | @Override 70 | public List getAlias() { 71 | return alias; 72 | } 73 | } 74 | 75 | public static enum Handshake implements PacketType { 76 | 77 | IS_SET_PROTOCOL("InSetProtocol"), 78 | UNSET("Unset"); 79 | 80 | private final String packetName, fullName; 81 | private List alias = new ArrayList<>(); 82 | 83 | private Handshake(String packetName, String... alias) { 84 | this.packetName = packetName; 85 | for(String al : alias) 86 | this.alias.add(HANDSHAKE_PREFIX + al); 87 | this.fullName = HANDSHAKE_PREFIX + packetName; 88 | } 89 | 90 | @Override 91 | public String getPacketName() { 92 | return packetName; 93 | } 94 | 95 | @Override 96 | public String getFullName() { 97 | return fullName; 98 | } 99 | 100 | @Override 101 | public List getAlias() { 102 | return alias; 103 | } 104 | 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/custom/CustomPacketManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets.custom; 2 | 3 | import java.util.HashMap; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.player.PlayerJoinEvent; 10 | import org.bukkit.event.player.PlayerQuitEvent; 11 | import org.bukkit.plugin.Plugin; 12 | 13 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketManager; 14 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.channel.ChannelAbstract; 15 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.channel.INC2Channel; 16 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.channel.INCChannel; 17 | import me.dadus33.chatitem.utils.Utils; 18 | import me.dadus33.chatitem.utils.Version; 19 | 20 | public class CustomPacketManager extends PacketManager implements Listener { 21 | 22 | private ChannelAbstract channel; 23 | private Plugin pl; 24 | public HashMap protocolVersionPerChannel = new HashMap<>(); 25 | private boolean isStarted = false; 26 | 27 | public CustomPacketManager(Plugin pl) { 28 | this.pl = pl; 29 | Version version = Version.getVersion(); 30 | if (version.isNewerOrEquals(Version.V1_17)) 31 | channel = new INC2Channel(this); 32 | else 33 | channel = new INCChannel(this); 34 | pl.getServer().getPluginManager().registerEvents(this, pl); 35 | 36 | // we wait the start server 37 | CompletableFuture.runAsync(() -> { 38 | isStarted = true; 39 | for(Player p : Utils.getOnlinePlayers()) 40 | addPlayer(p); 41 | }); 42 | } 43 | 44 | public Plugin getPlugin() { 45 | return pl; 46 | } 47 | 48 | @EventHandler 49 | public void onJoin(PlayerJoinEvent e) { 50 | addPlayer(e.getPlayer()); 51 | } 52 | 53 | @EventHandler 54 | public void onQuit(PlayerQuitEvent e) { 55 | removePlayer(e.getPlayer()); 56 | } 57 | 58 | @Override 59 | public void addPlayer(Player p) { 60 | if(isStarted) 61 | channel.addPlayer(p); 62 | } 63 | 64 | @Override 65 | public void removePlayer(Player p) { 66 | channel.removePlayer(p); 67 | } 68 | 69 | @Override 70 | public void stop() { 71 | for(Player player : Utils.getOnlinePlayers()) 72 | removePlayer(player); 73 | if(channel.getAddChannelExecutor() != null) 74 | channel.getAddChannelExecutor().shutdownNow(); 75 | if(channel.getRemoveChannelExecutor() != null) 76 | channel.getRemoveChannelExecutor().shutdownNow(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/custom/channel/ChannelAbstract.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets.custom.channel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.UUID; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.entity.Player; 11 | 12 | import me.dadus33.chatitem.ItemPlayer; 13 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager; 14 | 15 | public abstract class ChannelAbstract { 16 | 17 | private ExecutorService addChannelExecutor, removeChannelExecutor; 18 | static final String KEY_HANDSHAKE = "packet_handshake_chatitem", KEY_HANDLER_SERVER = "packet_handler", KEY_SERVER = "packet_server_chatitem"; 19 | 20 | private CustomPacketManager customPacketManager; 21 | private HashSet players = new HashSet<>(); 22 | 23 | protected ChannelAbstract(CustomPacketManager customPacketManager) { 24 | this.customPacketManager = customPacketManager; 25 | } 26 | 27 | public CustomPacketManager getPacketManager() { 28 | return customPacketManager; 29 | } 30 | 31 | public ExecutorService getAddChannelExecutor() { 32 | return addChannelExecutor; 33 | } 34 | 35 | public ExecutorService getOrCreateAddChannelExecutor() { 36 | if(addChannelExecutor == null || addChannelExecutor.isTerminated()) 37 | addChannelExecutor = Executors.newSingleThreadExecutor(); 38 | return addChannelExecutor; 39 | } 40 | 41 | public ExecutorService getRemoveChannelExecutor() { 42 | return removeChannelExecutor; 43 | } 44 | 45 | public ExecutorService getOrCreateRemoveChannelExecutor() { 46 | if(removeChannelExecutor == null || removeChannelExecutor.isTerminated()) 47 | removeChannelExecutor = Executors.newSingleThreadExecutor(); 48 | return removeChannelExecutor; 49 | } 50 | 51 | public void addPlayer(Player p) { 52 | if(players.add(p.getUniqueId())) { 53 | addChannel(p, p.getUniqueId().toString()); 54 | try { 55 | Integer protocol = customPacketManager.protocolVersionPerChannel.remove(getChannel(p)); 56 | if(protocol != null) 57 | ItemPlayer.getPlayer(p).setProtocolVersion(protocol); 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | } 63 | 64 | public void removePlayer(Player p) { 65 | if(players.remove(p.getUniqueId())) 66 | removeChannel(p, p.getUniqueId().toString()); 67 | } 68 | 69 | public void removeAllPlayers() { 70 | new ArrayList<>(players).forEach((uuid) -> { 71 | Player p = Bukkit.getPlayer(uuid); 72 | if(p != null) // player don't left 73 | removeChannel(Bukkit.getPlayer(uuid), uuid.toString()); 74 | }); 75 | players.clear(); 76 | } 77 | 78 | protected abstract void stopPipelines(); 79 | 80 | public abstract void addChannel(Player player, String endChannelName); 81 | 82 | public abstract void removeChannel(Player player, String endChannelName); 83 | 84 | public abstract Object getChannel(Player p) throws Exception; 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/custom/channel/ChannelInboundHandler.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets.custom.channel; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.logging.Level; 6 | 7 | import org.bukkit.Bukkit; 8 | 9 | import io.netty.channel.Channel; 10 | import io.netty.channel.ChannelHandler; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.channel.ChannelInboundHandlerAdapter; 13 | import io.netty.channel.ChannelInitializer; 14 | import io.netty.channel.ChannelPipeline; 15 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent; 16 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketType; 17 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent.ContentModifier; 18 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager; 19 | 20 | public class ChannelInboundHandler extends ChannelInboundHandlerAdapter { 21 | 22 | private CustomPacketManager packetManager; 23 | private List pipelines = new ArrayList<>(); 24 | 25 | public ChannelInboundHandler(CustomPacketManager packetManager) { 26 | this.packetManager = packetManager; 27 | } 28 | 29 | public void clean() { 30 | pipelines.forEach(ChannelPipeline::removeFirst); 31 | pipelines.clear(); 32 | } 33 | 34 | @Override 35 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 36 | ctx.fireChannelRead(msg); 37 | ChannelPipeline pipe = ((Channel) msg).pipeline(); 38 | pipelines.add(pipe); 39 | pipe.addFirst(new ChannelInitializer() { 40 | @Override 41 | protected void initChannel(Channel channel) { 42 | try { 43 | channel.eventLoop().submit(() -> { 44 | try { 45 | ChannelHandler interceptor = channel.pipeline().get(ChannelAbstract.KEY_HANDSHAKE); 46 | // Inject our packet interceptor 47 | if (interceptor == null) { 48 | interceptor = new ChannelHandlerHandshakeReceive(channel); 49 | channel.pipeline().addBefore("packet_handler", ChannelAbstract.KEY_HANDSHAKE, interceptor); 50 | } 51 | return interceptor; 52 | } catch (IllegalArgumentException e) { 53 | // Try again 54 | return channel.pipeline().get(ChannelAbstract.KEY_HANDSHAKE); 55 | } 56 | }); 57 | } catch (Exception e) { 58 | packetManager.getPlugin().getLogger().log(Level.SEVERE, "Cannot inject incoming channel " + channel, e); 59 | } 60 | } 61 | }); 62 | } 63 | 64 | public class ChannelHandlerHandshakeReceive extends ChannelInboundHandlerAdapter { 65 | 66 | private Channel channel; 67 | 68 | public ChannelHandlerHandshakeReceive(Channel channel) { 69 | this.channel = channel; 70 | } 71 | 72 | @Override 73 | public void channelRead(ChannelHandlerContext ctx, Object packet) { 74 | try { 75 | PacketType packetType = PacketType.getType(packet.getClass().getSimpleName()); 76 | if(packetType != null && packetType == PacketType.Handshake.IS_SET_PROTOCOL) { 77 | ContentModifier ints = new PacketContent(packet).getIntegers(); 78 | int possibleProtocol = ints.readSafely(0, 0); 79 | if(possibleProtocol == Bukkit.getPort()) 80 | possibleProtocol = ints.readSafely(1, 0); 81 | if(possibleProtocol == -1 || possibleProtocol == 255 || possibleProtocol == Bukkit.getPort()) 82 | possibleProtocol = ints.readSafely(2, 0); 83 | packetManager.protocolVersionPerChannel.put(channel, possibleProtocol); 84 | } 85 | super.channelRead(ctx, packet); 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/custom/channel/INC2Channel.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets.custom.channel; 2 | 3 | import static me.dadus33.chatitem.utils.PacketUtils.getPlayerConnection; 4 | 5 | import java.util.List; 6 | import java.util.NoSuchElementException; 7 | 8 | import org.bukkit.entity.Player; 9 | 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelFuture; 12 | import io.netty.channel.ChannelHandlerContext; 13 | import io.netty.channel.ChannelOutboundHandlerAdapter; 14 | import io.netty.channel.ChannelPipeline; 15 | import io.netty.channel.ChannelPromise; 16 | import me.dadus33.chatitem.ChatItem; 17 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 18 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketType; 19 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager; 20 | import me.dadus33.chatitem.utils.PacketUtils; 21 | import me.dadus33.chatitem.utils.ReflectionUtils; 22 | import me.dadus33.chatitem.utils.Version; 23 | 24 | public class INC2Channel extends ChannelAbstract { 25 | 26 | private final ChannelInboundHandler boundHandler; 27 | private ChannelPipeline pipeline; 28 | 29 | public INC2Channel(CustomPacketManager customPacketManager) { 30 | super(customPacketManager); 31 | boundHandler = new ChannelInboundHandler(customPacketManager); 32 | try { 33 | Object mcServer = ReflectionUtils.callMethod(PacketUtils.getCraftServer(), Version.getVersion().equals(Version.V1_17) ? "getServer" : "b"); 34 | Object co = ReflectionUtils.getFirstWith(mcServer, PacketUtils.getNmsClass("MinecraftServer", "server."), PacketUtils.getNmsClass("ServerConnection", "server.network.")); 35 | ((List) ReflectionUtils.getObject(co, "f")).forEach((channelFuture) -> { 36 | pipeline = channelFuture.channel().pipeline(); 37 | pipeline.addFirst(boundHandler); 38 | }); 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | @Override 45 | protected void stopPipelines() { 46 | pipeline.remove(boundHandler); 47 | boundHandler.clean(); 48 | } 49 | 50 | @Override 51 | public void addChannel(final Player player, String endChannelName) { 52 | getOrCreateAddChannelExecutor().execute(() -> { 53 | if(!player.isOnline()) 54 | return; 55 | try { 56 | Channel channel = getChannel(player); 57 | // Managing outgoing packet (to the player) 58 | channel.pipeline().addAfter(KEY_HANDLER_SERVER, KEY_SERVER + endChannelName, new ChannelHandlerSent(player)); 59 | } catch (NoSuchElementException e) { 60 | // appear when the player's channel isn't accessible because of reload. 61 | getPacketManager().getPlugin().getLogger().warning("Please, don't use reload, this can produce some problem. Currently, " + player.getName() + " isn't fully checked because of that. More details: " + e.getMessage() + " (NoSuchElementException)"); 62 | } catch (IllegalArgumentException e) { 63 | if(e.getMessage().contains("Duplicate handler")) { 64 | removeChannel(player, endChannelName); 65 | addChannel(player, endChannelName); 66 | } else 67 | getPacketManager().getPlugin().getLogger().severe("Error while loading Packet channel. " + e.getMessage() + ". Please, prefer restart than reload."); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | }); 72 | } 73 | 74 | @Override 75 | public void removeChannel(Player player, String endChannelName) { 76 | getOrCreateRemoveChannelExecutor().execute(() -> { 77 | try { 78 | final Channel channel = getChannel(player); 79 | if(channel.pipeline().get(KEY_SERVER + endChannelName) != null) 80 | channel.pipeline().remove(KEY_SERVER + endChannelName); 81 | } catch (Exception e) { 82 | ChatItem.getInstance().getLogger().warning("Failed to remove channel for " + player.getName() + ". Reason: " + e.getMessage() + " (" + e.getStackTrace()[0].toString() + ")"); 83 | } 84 | }); 85 | } 86 | 87 | @Override 88 | public Channel getChannel(Player p) throws Exception { 89 | Object playerConnection = getPlayerConnection(p); 90 | Object networkManager = ReflectionUtils.getFirstWith(playerConnection, PacketUtils.getNmsClass("NetworkManager", "network.")); 91 | return ReflectionUtils.getFirstWith(networkManager, Channel.class); 92 | } 93 | 94 | private class ChannelHandlerSent extends ChannelOutboundHandlerAdapter { 95 | 96 | private final Player owner; 97 | 98 | public ChannelHandlerSent(Player player) { 99 | this.owner = player; 100 | } 101 | 102 | @Override 103 | public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { 104 | ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet); 105 | if(nextPacket != null && nextPacket.isCancelled()) 106 | return; 107 | super.write(ctx, nextPacket == null ? packet : nextPacket.getPacket(), promise); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/custom/channel/INCChannel.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets.custom.channel; 2 | 3 | import static me.dadus33.chatitem.utils.PacketUtils.getPlayerConnection; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.NoSuchElementException; 8 | 9 | import org.bukkit.entity.Player; 10 | 11 | import io.netty.channel.Channel; 12 | import io.netty.channel.ChannelFuture; 13 | import io.netty.channel.ChannelHandlerContext; 14 | import io.netty.channel.ChannelOutboundHandlerAdapter; 15 | import io.netty.channel.ChannelPipeline; 16 | import io.netty.channel.ChannelPromise; 17 | import me.dadus33.chatitem.ChatItem; 18 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 19 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent; 20 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketType; 21 | import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager; 22 | import me.dadus33.chatitem.utils.PacketUtils; 23 | import me.dadus33.chatitem.utils.ReflectionUtils; 24 | 25 | public class INCChannel extends ChannelAbstract { 26 | 27 | private final ChannelInboundHandler boundHandler; 28 | private ChannelPipeline pipeline; 29 | 30 | public INCChannel(CustomPacketManager customPacketManager) { 31 | super(customPacketManager); 32 | boundHandler = new ChannelInboundHandler(customPacketManager); 33 | getFuturChannel().forEach((channelFuture) -> { 34 | pipeline = channelFuture.channel().pipeline(); 35 | pipeline.addFirst(boundHandler); 36 | }); 37 | } 38 | 39 | public List getFuturChannel() { 40 | try { 41 | Object dedicatedSrv = PacketUtils.getCraftServer(); 42 | Object mcServer = dedicatedSrv.getClass().getMethod("getServer").invoke(dedicatedSrv); 43 | Object co = ReflectionUtils.getFirstWith(mcServer, PacketUtils.getNmsClass("MinecraftServer", "server."), PacketUtils.getNmsClass("ServerConnection", "network.")); 44 | try { 45 | return (List) ReflectionUtils.getPrivateField(co, "g"); 46 | } catch (NoSuchFieldException e) { 47 | return (List) ReflectionUtils.getPrivateField(co, "listeningChannels"); 48 | } 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | return new ArrayList<>(); 52 | } 53 | } 54 | 55 | @Override 56 | protected void stopPipelines() { 57 | pipeline.remove(boundHandler); 58 | boundHandler.clean(); 59 | } 60 | 61 | @Override 62 | public void addChannel(final Player player, String endChannelName) { 63 | getOrCreateAddChannelExecutor().execute(() -> { 64 | if(!player.isOnline()) 65 | return; 66 | try { 67 | Channel channel = getChannel(player); 68 | // Managing outgoing packet (to the player) 69 | channel.pipeline().addAfter(KEY_HANDLER_SERVER, KEY_SERVER + endChannelName, new ChannelHandlerSent(player)); 70 | } catch (NoSuchElementException e) { 71 | // appear when the player's channel isn't accessible because of reload. 72 | getPacketManager().getPlugin().getLogger().warning("Please, don't use reload, this can produce some problem. Currently, " + player.getName() + " isn't fully checked because of that. More details: " + e.getMessage() + " (NoSuchElementException)"); 73 | } catch (IllegalArgumentException e) { 74 | if(e.getMessage().contains("Duplicate handler")) { 75 | removeChannel(player, endChannelName); 76 | addChannel(player, endChannelName); 77 | } else 78 | getPacketManager().getPlugin().getLogger().severe("Error while loading Packet channel. " + e.getMessage() + ". Please, prefer restart than reload."); 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | }); 83 | } 84 | 85 | @Override 86 | public void removeChannel(Player player, String endChannelName) { 87 | getOrCreateRemoveChannelExecutor().execute(() -> { 88 | try { 89 | final Channel channel = getChannel(player); 90 | 91 | if(channel.pipeline().get(KEY_SERVER + endChannelName) != null) 92 | channel.pipeline().remove(KEY_SERVER + endChannelName); 93 | } catch (Exception e) { 94 | ChatItem.getInstance().getLogger().warning("Failed to remove channel for " + player.getName() + ". Reason: " + e.getMessage() + " (" + e.getStackTrace()[0].toString() + ")"); 95 | } 96 | }); 97 | } 98 | 99 | @Override 100 | public Channel getChannel(Player p) throws Exception { 101 | Object playerConnection = getPlayerConnection(p); 102 | Object networkManager = playerConnection.getClass().getField("networkManager").get(playerConnection); 103 | return new PacketContent(networkManager).getSpecificModifier(Channel.class).readSafely(0);//(Channel) networkManager.getClass().getDeclaredField("channel").get(networkManager); 104 | } 105 | 106 | private class ChannelHandlerSent extends ChannelOutboundHandlerAdapter { 107 | 108 | private final Player owner; 109 | 110 | public ChannelHandlerSent(Player player) { 111 | this.owner = player; 112 | } 113 | 114 | @Override 115 | public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception { 116 | ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet); 117 | if(nextPacket != null && nextPacket.isCancelled()) 118 | return; 119 | super.write(ctx, nextPacket == null ? packet : nextPacket.getPacket(), promise); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/packets/protocollib/ProtocollibPacketManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.packets.protocollib; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.entity.Player; 7 | 8 | import com.comphenix.protocol.PacketType.Play; 9 | import com.comphenix.protocol.ProtocolLibrary; 10 | import com.comphenix.protocol.ProtocolManager; 11 | import com.comphenix.protocol.events.ListenerPriority; 12 | import com.comphenix.protocol.events.PacketAdapter; 13 | import com.comphenix.protocol.events.PacketEvent; 14 | 15 | import me.dadus33.chatitem.ChatItem; 16 | import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket; 17 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketManager; 18 | import me.dadus33.chatitem.chatmanager.v1.packets.PacketType; 19 | 20 | public class ProtocollibPacketManager extends PacketManager { 21 | 22 | private final ProtocolManager protocolManager; 23 | 24 | public ProtocollibPacketManager(ChatItem pl) { 25 | protocolManager = ProtocolLibrary.getProtocolManager(); 26 | List list = new ArrayList<>(); 27 | list.add(Play.Server.CHAT); 28 | try { 29 | list.add((com.comphenix.protocol.PacketType) Play.Server.class.getDeclaredField("SYSTEM_CHAT").get(null)); 30 | } catch (Exception e) { 31 | // ignore because using old version 32 | } 33 | protocolManager.addPacketListener(new PacketAdapter(pl, ListenerPriority.LOWEST, list) { 34 | @Override 35 | public void onPacketSending(PacketEvent e) { 36 | Player p = e.getPlayer(); 37 | if (p == null || e.isPlayerTemporary()) 38 | return; 39 | ChatItemPacket packet = onPacketSent(PacketType.getType(e.getPacket().getHandle().getClass().getSimpleName()), p, e.getPacket().getHandle()); 40 | if(packet == null) { 41 | ChatItem.debug("Can't find packet: " + e.getPacket().getHandle().getClass().getName()); 42 | return; 43 | } 44 | if(!e.isCancelled()) 45 | e.setCancelled(packet.isCancelled()); 46 | } 47 | }); 48 | } 49 | 50 | @Override 51 | public void stop() { 52 | protocolManager.removePacketListeners(ChatItem.getInstance()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/utils/Item.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.utils; 2 | 3 | 4 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 5 | 6 | @Deprecated 7 | public class Item { 8 | private String id; 9 | private byte amount; 10 | private short data; 11 | private CompoundTag tag; 12 | 13 | public CompoundTag getTag(){ 14 | return tag; 15 | } 16 | 17 | public void setTag(CompoundTag newTag){ 18 | this.tag = newTag; 19 | } 20 | 21 | public void setId(String newId){ 22 | this.id = newId; 23 | } 24 | 25 | public void setData(short newData){ 26 | data = newData; 27 | } 28 | 29 | public String getId(){ 30 | return id; 31 | } 32 | 33 | public short getData(){ 34 | return data; 35 | } 36 | 37 | public void setAmount(byte newAmount){ 38 | this.amount = newAmount; 39 | } 40 | 41 | public byte getAmount(){ 42 | return amount; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/utils/ItemRewriter.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.utils; 2 | 3 | import static me.dadus33.chatitem.utils.Version.V1_10; 4 | import static me.dadus33.chatitem.utils.Version.V1_11; 5 | import static me.dadus33.chatitem.utils.Version.V1_8; 6 | import static me.dadus33.chatitem.utils.Version.V1_9; 7 | 8 | import org.bukkit.inventory.ItemStack; 9 | 10 | @Deprecated 11 | public class ItemRewriter { 12 | 13 | public static String remapIds(int server, int player, ItemStack is) { 14 | Item item = new Item(); 15 | item.setAmount((byte)is.getAmount()); 16 | //item.setData(is.getDurability()); 17 | //item.setId(id); 18 | //item.setTag(tag); 19 | if (areIdsCompatible(server, player)) { 20 | return item.getId(); 21 | } 22 | if ((server >= V1_9.MIN_VER && player <= V1_8.MAX_VER) || (player >= V1_9.MIN_VER && server <= V1_8.MAX_VER)) { 23 | if ((server >= V1_9.MIN_VER && player <= V1_8.MAX_VER)) { 24 | ItemRewriter_1_9_TO_1_8.reversedToClient(item); 25 | } else 26 | ItemRewriter_1_9_TO_1_8.toClient(item); 27 | } 28 | if ((server <= V1_10.MAX_VER && player >= V1_11.MIN_VER) 29 | || (player <= V1_10.MAX_VER && server >= V1_11.MIN_VER)) { 30 | if (server <= V1_10.MAX_VER && player >= V1_11.MIN_VER) { 31 | ItemRewriter_1_11_TO_1_10.toClient(item); 32 | } else { 33 | ItemRewriter_1_11_TO_1_10.reverseToClient(item); 34 | } 35 | } 36 | return item.getId(); 37 | } 38 | 39 | public static boolean areIdsCompatible(int version1, int version2) { 40 | if ((version1 >= V1_9.MIN_VER && version2 <= V1_8.MAX_VER) 41 | || (version2 >= V1_9.MIN_VER && version1 <= V1_8.MAX_VER)) { 42 | return false; 43 | } 44 | if ((version1 <= V1_10.MAX_VER && version2 >= V1_11.MIN_VER) 45 | || (version1 <= V1_10.MAX_VER && version2 >= V1_11.MIN_VER)) { 46 | return false; 47 | } 48 | return true; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v1/utils/ItemRewriter_1_11_TO_1_10.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v1.utils; 2 | 3 | 4 | import com.github.steveice10.opennbt.tag.builtin.CompoundTag; 5 | import com.github.steveice10.opennbt.tag.builtin.StringTag; 6 | import com.google.common.collect.BiMap; 7 | import com.google.common.collect.HashBiMap; 8 | 9 | 10 | /** 11 | * Thanks to the developers of ViaVersion for this! 12 | */ 13 | @Deprecated 14 | public class ItemRewriter_1_11_TO_1_10 { 15 | private static BiMap oldToNewNames = HashBiMap.create(); 16 | 17 | static { 18 | oldToNewNames.put("AreaEffectCloud", "minecraft:area_effect_cloud"); 19 | oldToNewNames.put("ArmorStand", "minecraft:armor_stand"); 20 | oldToNewNames.put("Arrow", "minecraft:arrow"); 21 | oldToNewNames.put("Bat", "minecraft:bat"); 22 | oldToNewNames.put("Blaze", "minecraft:blaze"); 23 | oldToNewNames.put("Boat", "minecraft:boat"); 24 | oldToNewNames.put("CaveSpider", "minecraft:cave_spider"); 25 | oldToNewNames.put("Chicken", "minecraft:chicken"); 26 | oldToNewNames.put("Cow", "minecraft:cow"); 27 | oldToNewNames.put("Creeper", "minecraft:creeper"); 28 | oldToNewNames.put("Donkey", "minecraft:donkey"); 29 | oldToNewNames.put("DragonFireball", "minecraft:dragon_fireball"); 30 | oldToNewNames.put("ElderGuardian", "minecraft:elder_guardian"); 31 | oldToNewNames.put("EnderCrystal", "minecraft:ender_crystal"); 32 | oldToNewNames.put("EnderDragon", "minecraft:ender_dragon"); 33 | oldToNewNames.put("Enderman", "minecraft:enderman"); 34 | oldToNewNames.put("Endermite", "minecraft:endermite"); 35 | oldToNewNames.put("EntityHorse", "minecraft:horse"); 36 | oldToNewNames.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); 37 | oldToNewNames.put("FallingSand", "minecraft:falling_block"); 38 | oldToNewNames.put("Fireball", "minecraft:fireball"); 39 | oldToNewNames.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); 40 | oldToNewNames.put("Ghast", "minecraft:ghast"); 41 | oldToNewNames.put("Giant", "minecraft:giant"); 42 | oldToNewNames.put("Guardian", "minecraft:guardian"); 43 | oldToNewNames.put("Husk", "minecraft:husk"); 44 | oldToNewNames.put("Item", "minecraft:item"); 45 | oldToNewNames.put("ItemFrame", "minecraft:item_frame"); 46 | oldToNewNames.put("LavaSlime", "minecraft:magma_cube"); 47 | oldToNewNames.put("LeashKnot", "minecraft:leash_knot"); 48 | oldToNewNames.put("MinecartChest", "minecraft:chest_minecart"); 49 | oldToNewNames.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); 50 | oldToNewNames.put("MinecartFurnace", "minecraft:furnace_minecart"); 51 | oldToNewNames.put("MinecartHopper", "minecraft:hopper_minecart"); 52 | oldToNewNames.put("MinecartRideable", "minecraft:minecart"); 53 | oldToNewNames.put("MinecartSpawner", "minecraft:spawner_minecart"); 54 | oldToNewNames.put("MinecartTNT", "minecraft:tnt_minecart"); 55 | oldToNewNames.put("Mule", "minecraft:mule"); 56 | oldToNewNames.put("MushroomCow", "minecraft:mooshroom"); 57 | oldToNewNames.put("Ozelot", "minecraft:ocelot"); 58 | oldToNewNames.put("Painting", "minecraft:painting"); 59 | oldToNewNames.put("Pig", "minecraft:pig"); 60 | oldToNewNames.put("PigZombie", "minecraft:zombie_pigman"); 61 | oldToNewNames.put("PolarBear", "minecraft:polar_bear"); 62 | oldToNewNames.put("PrimedTnt", "minecraft:tnt"); 63 | oldToNewNames.put("Rabbit", "minecraft:rabbit"); 64 | oldToNewNames.put("Sheep", "minecraft:sheep"); 65 | oldToNewNames.put("Shulker", "minecraft:shulker"); 66 | oldToNewNames.put("ShulkerBullet", "minecraft:shulker_bullet"); 67 | oldToNewNames.put("Silverfish", "minecraft:silverfish"); 68 | oldToNewNames.put("Skeleton", "minecraft:skeleton"); 69 | oldToNewNames.put("SkeletonHorse", "minecraft:skeleton_horse"); 70 | oldToNewNames.put("Slime", "minecraft:slime"); 71 | oldToNewNames.put("SmallFireball", "minecraft:small_fireball"); 72 | oldToNewNames.put("Snowball", "minecraft:snowball"); 73 | oldToNewNames.put("SnowMan", "minecraft:snowman"); 74 | oldToNewNames.put("SpectralArrow", "minecraft:spectral_arrow"); 75 | oldToNewNames.put("Spider", "minecraft:spider"); 76 | oldToNewNames.put("Squid", "minecraft:squid"); 77 | oldToNewNames.put("Stray", "minecraft:stray"); 78 | oldToNewNames.put("ThrownEgg", "minecraft:egg"); 79 | oldToNewNames.put("ThrownEnderpearl", "minecraft:ender_pearl"); 80 | oldToNewNames.put("ThrownExpBottle", "minecraft:xp_bottle"); 81 | oldToNewNames.put("ThrownPotion", "minecraft:potion"); 82 | oldToNewNames.put("Villager", "minecraft:villager"); 83 | oldToNewNames.put("VillagerGolem", "minecraft:villager_golem"); 84 | oldToNewNames.put("Witch", "minecraft:witch"); 85 | oldToNewNames.put("WitherBoss", "minecraft:wither"); 86 | oldToNewNames.put("WitherSkeleton", "minecraft:wither_skeleton"); 87 | oldToNewNames.put("WitherSkull", "minecraft:wither_skull"); 88 | oldToNewNames.put("Wolf", "minecraft:wolf"); 89 | oldToNewNames.put("XPOrb", "minecraft:xp_orb"); 90 | oldToNewNames.put("Zombie", "minecraft:zombie"); 91 | oldToNewNames.put("ZombieHorse", "minecraft:zombie_horse"); 92 | oldToNewNames.put("ZombieVillager", "minecraft:zombie_villager"); 93 | } 94 | 95 | static void toClient(Item item) { 96 | if (hasEntityTag(item)) { 97 | CompoundTag entityTag = item.getTag().get("EntityTag"); 98 | if (entityTag.get("id") instanceof StringTag) { 99 | StringTag id = entityTag.get("id"); 100 | if (oldToNewNames.containsKey(id.getValue())) { 101 | id.setValue(oldToNewNames.get(id.getValue())); 102 | } 103 | } 104 | } 105 | } 106 | 107 | 108 | static void reverseToClient(Item item) { 109 | if (hasEntityTag(item)) { 110 | CompoundTag entityTag = item.getTag().get("EntityTag"); 111 | if (entityTag.get("id") instanceof StringTag) { 112 | StringTag id = entityTag.get("id"); 113 | if (oldToNewNames.containsKey(id.getValue())) { 114 | id.setValue(oldToNewNames.get(id.getValue())); 115 | } 116 | } 117 | } 118 | } 119 | 120 | 121 | private static boolean hasEntityTag(Item item) { 122 | if (item != null && item.getId().equals("minecraft:spawn_egg")) { // Monster Egg 123 | CompoundTag tag = item.getTag(); 124 | if (tag != null && tag.contains("EntityTag") && tag.get("EntityTag") instanceof CompoundTag) { 125 | if (((CompoundTag) tag.get("EntityTag")).get("id") instanceof StringTag) { 126 | return true; 127 | } 128 | } 129 | } 130 | return false; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v2/ChatListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v2; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.EventPriority; 10 | import org.bukkit.event.Listener; 11 | import org.bukkit.event.player.AsyncPlayerChatEvent; 12 | 13 | import me.dadus33.chatitem.ChatItem; 14 | import me.dadus33.chatitem.ItemSlot; 15 | import me.dadus33.chatitem.Storage; 16 | import me.dadus33.chatitem.chatmanager.Chat; 17 | import me.dadus33.chatitem.chatmanager.ChatAction; 18 | import me.dadus33.chatitem.chatmanager.ChatManager; 19 | import me.dadus33.chatitem.hook.DiscordSrvSupport; 20 | import me.dadus33.chatitem.playernamer.PlayerNamerManager; 21 | import me.dadus33.chatitem.utils.Utils; 22 | import net.md_5.bungee.api.ChatColor; 23 | 24 | @SuppressWarnings("deprecation") 25 | public class ChatListener implements Listener { 26 | 27 | private ChatListenerChatManager manage; 28 | 29 | public ChatListener(ChatListenerChatManager manage) { 30 | this.manage = manage; 31 | } 32 | 33 | public Storage getStorage() { 34 | return manage.getStorage(); 35 | } 36 | 37 | @EventHandler(priority = EventPriority.HIGH) 38 | public void onChat(AsyncPlayerChatEvent e) { 39 | if(ChatManager.isTestingEnabled() && !ChatManager.isTesting("chat")) 40 | return; 41 | if(!ChatManager.isSelected("chat")) 42 | return; 43 | Storage c = getStorage(); 44 | if (e.isCancelled()) { 45 | if (ChatItem.getInstance().getChatManager().size() == 1) { // only chat 46 | String msg = e.getMessage().toLowerCase(); 47 | for(ItemSlot slot : ItemSlot.values()) { 48 | for (String rep : slot.getPlaceholders()) { 49 | if (msg.contains(rep)) { 50 | ChatItem.debug("You choose 'chat' manager but it seems to don't be the good choice. More informations here: https://github.com/dadus33-plugins/ChatItem/wiki"); 51 | return; 52 | } 53 | } 54 | } 55 | } 56 | ChatItem.debug("Chat cancelled for " + e.getPlayer().getName()); 57 | return; 58 | } 59 | Player p = e.getPlayer(); 60 | String targetReplace = ChatManager.SEPARATOR + ""; 61 | if(ChatManager.containsSeparator(e.getMessage())) { // fix for v1 62 | Chat chat = Chat.getFrom(e.getMessage()); 63 | if(chat != null) { 64 | targetReplace = ChatManager.SEPARATOR + "" + chat.getId() + ChatManager.SEPARATOR_END; 65 | e.setMessage(ChatManager.replaceSeparator(chat, e.getMessage(), chat.getSlot().getPlaceholders().get(0))); 66 | } 67 | } 68 | ItemSlot slot = ItemSlot.getItemSlotFromMessage(e.getMessage()); 69 | if (slot == null) { // if not found 70 | ChatItem.debug("(v2) Can't found placeholder in: " + e.getMessage() + " > " + PlayerNamerManager.getPlayerNamer().getName(p)); 71 | return; 72 | } 73 | ChatAction action = ChatManager.getChatAction(slot, p); 74 | if(!ChatManager.canUsePlaceholder(p, action, slot, e)) 75 | return; 76 | e.setCancelled(true); 77 | String format = e.getFormat().replace(targetReplace, slot.getPlaceholders().get(0)); 78 | ChatItem.debug("(v2) Using format: " + format + " and message: " + e.getMessage()); 79 | String defMsg = slot.replacePlaceholdersToSeparator(e.getMessage()); 80 | if (Utils.countMatches(defMsg, Character.toString(ChatManager.SEPARATOR)) > c.limit) { 81 | if (!c.messageLimit.isEmpty()) 82 | p.sendMessage(c.messageLimit); 83 | return; 84 | } 85 | String msg; 86 | if (format.contains("%1$s") || format.contains("%2$s")) { 87 | msg = (format.contains("%2$s") ? String.format(format, p.getDisplayName(), defMsg) : String.format(format, p.getDisplayName())); 88 | } else { 89 | msg = format.replace(e.getMessage(), defMsg); 90 | } 91 | String itemName = ChatManager.getNameForChatAction(p, action, c); 92 | String loggedMessage = msg.replace(ChatManager.SEPARATOR + "", itemName); 93 | Bukkit.getConsoleSender().sendMessage(c.replaceInConsole ? loggedMessage : msg); // show in log 94 | if (ChatItem.discordSrvSupport) 95 | DiscordSrvSupport.sendChatMessage(p, defMsg.replace(ChatManager.SEPARATOR + "", itemName), e); 96 | Set recipients = e.getRecipients().isEmpty() ? new HashSet<>(Bukkit.getOnlinePlayers()) : e.getRecipients(); 97 | ChatItem.debug("(v2) Msg: " + ChatItem.replace(p, msg).replace(ChatColor.COLOR_CHAR, '&') + ", format: " + format + " to " + recipients.size() + " players"); 98 | recipients.forEach((pl) -> ChatItem.getPlatform().sendMessage(pl, p, action, ChatItem.replace(p, msg))); 99 | if (c.cooldown > 0 && !p.hasPermission("chatitem.ignore-cooldown")) 100 | ChatManager.applyCooldown(p); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v2/ChatListenerChatManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v2; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import me.dadus33.chatitem.ChatItem; 7 | import me.dadus33.chatitem.Storage; 8 | import me.dadus33.chatitem.chatmanager.ChatManager; 9 | 10 | public class ChatListenerChatManager extends ChatManager { 11 | 12 | private final ChatListener chatListener; 13 | private boolean baseComponentAvailable = true; 14 | 15 | public ChatListenerChatManager(ChatItem pl) { 16 | chatListener = new ChatListener(this); 17 | 18 | //Check for existence of BaseComponent class (only on spigot) 19 | try { 20 | Class.forName("net.md_5.bungee.api.chat.BaseComponent"); 21 | } catch (ClassNotFoundException e) { 22 | baseComponentAvailable = false; 23 | } 24 | } 25 | 26 | @Override 27 | public String getName() { 28 | return "ChatListener"; 29 | } 30 | 31 | @Override 32 | public String getId() { 33 | return "chat"; 34 | } 35 | 36 | @Override 37 | public void load(ChatItem pl, Storage s) { 38 | super.load(pl, s); 39 | 40 | Bukkit.getPluginManager().registerEvents(chatListener, pl); 41 | } 42 | 43 | @Override 44 | public void unload(ChatItem pl) { 45 | HandlerList.unregisterAll(chatListener); 46 | } 47 | 48 | public boolean supportsChatComponentApi(){ 49 | return baseComponentAvailable; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v3/PaperChatManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v3; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import me.dadus33.chatitem.ChatItem; 7 | import me.dadus33.chatitem.Storage; 8 | import me.dadus33.chatitem.chatmanager.ChatManager; 9 | 10 | public class PaperChatManager extends ChatManager { 11 | 12 | private PaperListener paperListener; 13 | 14 | public PaperChatManager(ChatItem pl) { 15 | paperListener = new PaperListener(this); 16 | } 17 | 18 | @Override 19 | public String getName() { 20 | return "Paper"; 21 | } 22 | 23 | @Override 24 | public String getId() { 25 | return "paper"; 26 | } 27 | 28 | @Override 29 | public void load(ChatItem pl, Storage s) { 30 | super.load(pl, s); 31 | 32 | Bukkit.getPluginManager().registerEvents(paperListener, pl); 33 | } 34 | 35 | @Override 36 | public void unload(ChatItem pl) { 37 | HandlerList.unregisterAll(paperListener); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v3/PaperListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v3; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.Material; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.EventPriority; 8 | import org.bukkit.event.Listener; 9 | 10 | import io.papermc.paper.event.player.AsyncChatEvent; 11 | import me.dadus33.chatitem.C; 12 | import me.dadus33.chatitem.ChatItem; 13 | import me.dadus33.chatitem.ItemSlot; 14 | import me.dadus33.chatitem.Storage; 15 | import me.dadus33.chatitem.chatmanager.Chat; 16 | import me.dadus33.chatitem.chatmanager.ChatAction; 17 | import me.dadus33.chatitem.chatmanager.ChatManager; 18 | import me.dadus33.chatitem.utils.Messages; 19 | import net.kyori.adventure.audience.Audience; 20 | import net.kyori.adventure.text.Component; 21 | import net.kyori.adventure.text.TextComponent; 22 | import net.kyori.adventure.text.TextReplacementConfig; 23 | import net.kyori.adventure.text.event.ClickEvent; 24 | import net.kyori.adventure.text.event.HoverEvent; 25 | import net.kyori.adventure.text.event.HoverEventSource; 26 | 27 | public class PaperListener implements Listener { 28 | 29 | private PaperChatManager manage; 30 | 31 | public PaperListener(PaperChatManager manage) { 32 | this.manage = manage; 33 | } 34 | 35 | public Storage getStorage() { 36 | return manage.getStorage(); 37 | } 38 | 39 | @EventHandler(priority = EventPriority.HIGHEST) 40 | public void onChat(AsyncChatEvent e) { 41 | if (ChatManager.isTestingEnabled() && !ChatManager.isTesting("paper")) 42 | return; 43 | if (!ChatManager.isSelected("paper")) 44 | return; 45 | 46 | Player p = e.getPlayer(); 47 | Component message = e.message(); 48 | String rawMessage = C.string(message); 49 | if (ChatManager.containsSeparator(rawMessage)) { // fix for v1 50 | Chat chat = Chat.getFrom(rawMessage); 51 | if (chat != null) { 52 | message = message.replaceText(TextReplacementConfig.builder().matchLiteral(ChatManager.addSeparator(chat.getId())) 53 | .replacement(C.text(chat.getSlot().getPlaceholders().get(0))).build()); 54 | rawMessage = C.string(message); 55 | } 56 | } 57 | ItemSlot slot = ItemSlot.getItemSlotFromMessage(rawMessage); 58 | ChatItem.debug("(v3) Raw message: " + rawMessage + ", slot: " + slot); 59 | if (slot == null) // if not found 60 | return; 61 | ChatAction action = ChatManager.getChatAction(slot, p); 62 | if (!ChatManager.canUsePlaceholder(p, action, slot, e)) 63 | return; 64 | HoverEventSource hoverEvent = null; 65 | if(action.hasItem()) { 66 | if(!action.getItem().getType().equals(Material.AIR)) 67 | hoverEvent = action.getItem().asHoverEvent(); 68 | else { 69 | Component t = null; 70 | for(String line : Messages.getMessageList("general.hand.tooltip", "%cible%", p.getName())) { 71 | if(t == null) { 72 | t = Component.text(""); 73 | } else 74 | t.append(Component.newline()); 75 | t.append(C.text(line)); 76 | } 77 | hoverEvent = HoverEvent.showText(t); 78 | } 79 | } else 80 | hoverEvent = HoverEvent.showText(C.text(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", p.getName()))); 81 | TextComponent like = C.text(ChatManager.getNameForChatAction(p, action, getStorage())).hoverEvent(hoverEvent); 82 | if (action.hasCommand()) 83 | like.clickEvent(ClickEvent.runCommand(action.getCommand())); 84 | for (String s : slot.getPlaceholders()) { 85 | message = message.replaceText(TextReplacementConfig.builder().matchLiteral(s).replacement(like).build()); 86 | } 87 | if (ChatItem.getInstance().getConfig().getBoolean("manager-config.paper.send-ourself", true)) { 88 | for (Audience a : e.viewers().isEmpty() ? Bukkit.getOnlinePlayers() : e.viewers()) 89 | a.sendMessage(e.renderer().render(p, p.displayName(), message, a)); 90 | e.setCancelled(true); 91 | ChatItem.debug("Sent message by ourself : " + C.string(message)); 92 | } else { 93 | e.message(message); 94 | ChatItem.debug("Changed message to " + C.string(message)); 95 | } 96 | if (getStorage().cooldown > 0 && !p.hasPermission("chatitem.ignore-cooldown")) 97 | ChatManager.applyCooldown(p); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v4/OwnListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v4; 2 | 3 | import org.bukkit.event.EventHandler; 4 | import org.bukkit.event.EventPriority; 5 | import org.bukkit.event.Listener; 6 | 7 | import io.papermc.paper.event.player.AsyncChatEvent; 8 | import me.dadus33.chatitem.chatmanager.ChatManager; 9 | 10 | public class OwnListener implements Listener { 11 | 12 | @EventHandler(priority = EventPriority.MONITOR) 13 | public void onChat(AsyncChatEvent e) { 14 | if (ChatManager.isTestingEnabled() && !ChatManager.isTesting("ownformatter")) 15 | return; 16 | if (!ChatManager.isSelected("ownformatter")) 17 | return; 18 | if (e.isCancelled()) 19 | return; 20 | e.setCancelled(true); 21 | /*Player p = e.getPlayer(); 22 | Component msg = e.message();*/ 23 | 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/chatmanager/v4/OwnManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.chatmanager.v4; 2 | 3 | import me.dadus33.chatitem.ChatItem; 4 | import me.dadus33.chatitem.chatmanager.ChatManager; 5 | 6 | public class OwnManager extends ChatManager { 7 | 8 | @Override 9 | public String getName() { 10 | return "Own Formatter"; 11 | } 12 | 13 | @Override 14 | public String getId() { 15 | return "ownformatter"; 16 | } 17 | 18 | @Override 19 | public void unload(ChatItem pl) { 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/commands/CIReloadCommand.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.commands; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | 7 | import me.dadus33.chatitem.ChatItem; 8 | 9 | public class CIReloadCommand implements CommandExecutor { 10 | 11 | @Override 12 | public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { 13 | ChatItem.reload(sender); 14 | return false; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/ChatControlSupport.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook; 2 | 3 | import me.dadus33.chatitem.ChatItem; 4 | 5 | public class ChatControlSupport { 6 | 7 | public static void init(ChatItem pl) { 8 | try { 9 | Class clz = Class.forName("org.mineacademy.chatcontrol.settings.Settings$Chat$Grammar"); 10 | clz.getField("CAPITALIZE").setBoolean(null, false); 11 | clz.getField("INSERT_DOT").setBoolean(null, false); 12 | pl.getLogger().info("Loaded ChatControl support by disabling 2 options in 'Chat.Grammar' config."); 13 | } catch (Exception e) { 14 | e.printStackTrace(); 15 | } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/ChatManagerSupport.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook; 2 | 3 | import java.util.List; 4 | 5 | import me.dadus33.chatitem.ChatItem; 6 | import me.dadus33.chatitem.chatmanager.ChatManager; 7 | import me.h1dd3nxn1nja.chatmanager.Main; 8 | 9 | public class ChatManagerSupport { 10 | 11 | public static void init(ChatItem pl) { 12 | List whitelist = Main.settings.getConfig().getStringList("Anti_Unicode.Whitelist"); 13 | whitelist.add(ChatManager.SEPARATOR_STR); 14 | whitelist.add(ChatManager.SEPARATOR_END_STR); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/DiscordSrvSupport.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Event; 5 | 6 | import github.scarsz.discordsrv.DiscordSRV; 7 | import me.dadus33.chatitem.ChatItem; 8 | import net.kyori.adventure.text.Component; 9 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 10 | 11 | public class DiscordSrvSupport { 12 | 13 | public static boolean isSendingMessage() { 14 | return ChatItem.getInstance().getStorage().discordSrvSendMsg; 15 | } 16 | 17 | public static void sendChatMessage(Player p, String message, Event e) { 18 | DiscordSRV pl = DiscordSRV.getPlugin(); 19 | pl.processChatMessage(p, message, pl.getOptionalChannel("global"), false, e); 20 | } 21 | 22 | public static void sendChatMessage(Player p, Component message, Event e) { 23 | DiscordSRV pl = DiscordSRV.getPlugin(); 24 | pl.processChatMessage(p, github.scarsz.discordsrv.dependencies.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(GsonComponentSerializer.gson().serialize(message)), pl.getOptionalChannel("global"), false, e); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/ecoenchants/EcoEnchantsSupport.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.ecoenchants; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.meta.ItemMeta; 9 | 10 | import me.dadus33.chatitem.ChatItem; 11 | 12 | public class EcoEnchantsSupport { 13 | 14 | private static int supportedVersion = 0; 15 | 16 | public static boolean hasSupport() { 17 | return supportedVersion > 0; 18 | } 19 | 20 | public static boolean load() { 21 | String ver = ChatItem.getPlatform().getPluginVersion(Bukkit.getPluginManager().getPlugin("EcoEnchants")); 22 | if(ver.startsWith("8.")) 23 | supportedVersion = 8; 24 | else if(ver.startsWith("10.")) 25 | supportedVersion = 10; 26 | else if(ver.startsWith("11.")) 27 | supportedVersion = 11; 28 | else if(ver.startsWith("12.")) 29 | supportedVersion = 12; 30 | else { 31 | ChatItem.getInstance().getLogger().warning("Failed to find support version for EcoEnchants " + ver); 32 | return false; 33 | } 34 | return true; 35 | } 36 | 37 | @SuppressWarnings("deprecation") 38 | public static ItemStack manageItem(ItemStack item) { 39 | if(supportedVersion == 8) { 40 | List addLore = EcoEnchantsV8Support.getLores(item); 41 | if (!addLore.isEmpty()) { 42 | ItemMeta meta = item.getItemMeta(); 43 | List lores = meta.hasLore() ? meta.getLore() : new ArrayList<>(); 44 | for (int i = 0; i < addLore.size(); i++) 45 | lores.add(i, addLore.get(i)); 46 | 47 | meta.setLore(lores); 48 | item.setItemMeta(meta); 49 | ChatItem.debug("Added " + addLore.size() + " lores from EcoEnchants"); 50 | } else 51 | ChatItem.debug("No lore to add from EcoEnchants"); 52 | } else if(supportedVersion >= 10) { 53 | EcoEnchantsV10Support.display(item); 54 | } 55 | return item; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/ecoenchants/EcoEnchantsV10Support.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.ecoenchants; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.inventory.ItemStack; 6 | 7 | import com.willfp.eco.core.display.DisplayProperties; 8 | import com.willfp.ecoenchants.EcoEnchantsPlugin; 9 | import com.willfp.ecoenchants.display.EnchantDisplay; 10 | 11 | public class EcoEnchantsV10Support { 12 | 13 | private static EnchantDisplay enchantDisplay; 14 | 15 | public static EnchantDisplay getEnchantDisplay() { 16 | if (enchantDisplay == null) { 17 | try { 18 | enchantDisplay = EnchantDisplay.class.getConstructor(EcoEnchantsPlugin.class).newInstance(Bukkit.getPluginManager().getPlugin("EcoEnchants")); 19 | } catch (Exception e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | return enchantDisplay; 24 | } 25 | 26 | public static void display(ItemStack item) { 27 | try { 28 | DisplayProperties display = DisplayProperties.class.getDeclaredConstructor(boolean.class, boolean.class, ItemStack.class).newInstance(false, false, item); 29 | getEnchantDisplay().display(item, (Player) null, display, new Object[] { false }); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/ecoenchants/EcoEnchantsV8Support.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.ecoenchants; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.inventory.ItemStack; 7 | 8 | import com.willfp.ecoenchants.display.EnchantmentCache; 9 | import com.willfp.ecoenchants.enchantments.util.EnchantChecks; 10 | 11 | public class EcoEnchantsV8Support { 12 | 13 | public static List getLores(ItemStack item) { 14 | List lores = new ArrayList<>(); 15 | EnchantChecks.getEnchantsOnItem(item).forEach((en, lvl) -> { 16 | lores.add(EnchantmentCache.getEntry(en).getNameWithLevel(lvl)); 17 | }); 18 | return lores; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/placeholders/EssentialsPlaceholdersHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.placeholders; 2 | 3 | import java.util.Locale; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.scoreboard.Team; 8 | 9 | import com.earth2me.essentials.Essentials; 10 | import com.earth2me.essentials.User; 11 | import com.earth2me.essentials.utils.FormatUtil; 12 | 13 | public class EssentialsPlaceholdersHook implements IPlaceholders { 14 | 15 | private Essentials getEssentials() { 16 | return ((Essentials) Bukkit.getPluginManager().getPlugin("Essentials")); 17 | } 18 | 19 | @SuppressWarnings("deprecation") 20 | @Override 21 | public String replace(Player p, String text) { 22 | User user = getEssentials().getUser(p); 23 | if (user == null) { 24 | return null; 25 | } 26 | String world = user.getWorld().getName(); 27 | String username = user.getName(); 28 | String nickname = user.getFormattedNickname(); 29 | Player player = user.getBase(); 30 | Team team = player.getScoreboard().getPlayerTeam(player); 31 | 32 | return text.replace("{GROUP}", user.getGroup()).replace("{WORLD}", getEssentials().getSettings().getWorldAlias(world)).replace("{WORLDNAME}", world) 33 | .replace("{SHORTWORLDNAME}", world.substring(0, 1).toUpperCase(Locale.ENGLISH)).replace("{TEAMNAME}", team == null ? "" : team.getDisplayName()) 34 | .replace("{TEAMPREFIX}", team == null ? "" : team.getPrefix()).replace("{TEAMSUFFIX}", team == null ? "" : team.getSuffix()) 35 | .replace("{PREFIX}", FormatUtil.replaceFormat(getEssentials().getPermissionsHandler().getPrefix(player))) 36 | .replace("{SUFFIX}", FormatUtil.replaceFormat(getEssentials().getPermissionsHandler().getSuffix(player))).replace("{USERNAME}", username) 37 | .replace("{NICKNAME}", nickname == null ? username : nickname); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/placeholders/IPlaceholders.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.placeholders; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | public interface IPlaceholders { 6 | 7 | String replace(Player p, String text); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/placeholders/MVdWPlaceholderAPIHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.placeholders; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import be.maximvdw.placeholderapi.PlaceholderAPI; 6 | 7 | public class MVdWPlaceholderAPIHook implements IPlaceholders { 8 | 9 | @Override 10 | public String replace(Player p, String text) { 11 | return PlaceholderAPI.replacePlaceholders(p, text); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/placeholders/OwnPlaceholder.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.placeholders; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | public class OwnPlaceholder implements IPlaceholders { 6 | 7 | @Override 8 | public String replace(Player p, String text) { 9 | return text.replace("{name}", p.getName()).replace("%name%", p.getName()); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/placeholders/PlaceholderAPIHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.placeholders; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import me.clip.placeholderapi.PlaceholderAPI; 6 | 7 | public class PlaceholderAPIHook implements IPlaceholders { 8 | 9 | @Override 10 | public String replace(Player p, String text) { 11 | return PlaceholderAPI.setPlaceholders(p, text); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/hook/placeholders/VaultPlaceholderHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.hook.placeholders; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.plugin.RegisteredServiceProvider; 6 | 7 | import net.milkbowl.vault.chat.Chat; 8 | 9 | public class VaultPlaceholderHook implements IPlaceholders { 10 | 11 | private Chat chat = null; 12 | 13 | public Chat getChat() { 14 | if (chat == null) { 15 | RegisteredServiceProvider rs = Bukkit.getServicesManager().getRegistration(Chat.class); 16 | if (rs != null) // chat well setup 17 | chat = rs.getProvider(); 18 | } 19 | return chat; 20 | } 21 | 22 | @Override 23 | public String replace(Player p, String text) { 24 | Chat chat = getChat(); 25 | if (chat == null) 26 | return text; 27 | return text.replace("{prefix}", chat.getPlayerPrefix(p)).replace("{suffix}", chat.getPlayerSuffix(p)).replace("%prefix%", chat.getPlayerPrefix(p)).replace("%suffix%", chat.getPlayerSuffix(p)); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/invsee/InvShower.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.invsee; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map.Entry; 5 | import java.util.UUID; 6 | 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.entity.Player; 9 | 10 | import me.dadus33.chatitem.ChatItem; 11 | 12 | public abstract class InvShower { 13 | 14 | private static final HashMap INV_SHOWER = new HashMap<>(); 15 | public static InvShower get(String s) { 16 | return INV_SHOWER.get(s); 17 | } 18 | public static void add(String s, InvShower shower) { 19 | INV_SHOWER.put(s, shower); 20 | } 21 | public static HashMap getInvShower() { 22 | return INV_SHOWER; 23 | } 24 | 25 | static { 26 | Bukkit.getScheduler().runTaskTimer(ChatItem.getInstance(), () -> { 27 | for(Entry entries : new HashMap<>(INV_SHOWER).entrySet()) 28 | if(entries.getValue().hasExpired()) 29 | INV_SHOWER.remove(entries.getKey()); 30 | }, 200, 200); 31 | } 32 | 33 | protected final long time; 34 | protected final UUID uuid; 35 | protected final String name; 36 | 37 | public InvShower(String id, Player cible) { 38 | this.time = System.currentTimeMillis() + ChatItem.getInstance().getConfig().getInt("general.other-placeholders." + id + ".time-expire", 1800) * 1000; 39 | this.uuid = cible.getUniqueId(); 40 | this.name = cible.getName(); 41 | } 42 | 43 | public UUID getUuid() { 44 | return uuid; 45 | } 46 | 47 | public long getTimeExpire() { 48 | return time; 49 | } 50 | 51 | public boolean hasExpired() { 52 | return System.currentTimeMillis() > time || Bukkit.getPlayer(uuid) == null || !Bukkit.getPlayer(uuid).isOnline(); 53 | } 54 | 55 | public abstract void open(Player p); 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/invsee/hook/EnderChestShower.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.invsee.hook; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.Inventory; 5 | import org.bukkit.inventory.ItemStack; 6 | 7 | import me.dadus33.chatitem.ChatItem; 8 | import me.dadus33.chatitem.invsee.InvShower; 9 | import me.dadus33.chatitem.listeners.holder.CustomInventoryHolder; 10 | import me.dadus33.chatitem.utils.ItemUtils; 11 | import me.dadus33.chatitem.utils.Messages; 12 | 13 | public class EnderChestShower extends InvShower { 14 | 15 | private final ItemStack[] items; 16 | 17 | public EnderChestShower(Player cible) { 18 | super("enderchest", cible); 19 | 20 | Inventory ec = cible.getEnderChest(); 21 | ItemStack[] tmp = ec.getContents(); 22 | items = new ItemStack[tmp.length]; 23 | for(int i = 0; i < ec.getSize(); i++) 24 | items[i] = ItemUtils.copyIfExist(tmp[i]); 25 | } 26 | 27 | @Override 28 | public void open(Player p) { 29 | Inventory inv = ChatItem.getPlatform().createInventory(new CustomInventoryHolder(), items.length, Messages.getMessage("enderchest.name", "%cible%", name)); 30 | 31 | for(int i = 0; i < items.length; i++) 32 | inv.setItem(i, items[i]); 33 | 34 | p.openInventory(inv); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/invsee/hook/OneItemShower.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.invsee.hook; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.Inventory; 5 | import org.bukkit.inventory.ItemStack; 6 | 7 | import me.dadus33.chatitem.ChatItem; 8 | import me.dadus33.chatitem.invsee.InvShower; 9 | import me.dadus33.chatitem.listeners.holder.CustomInventoryHolder; 10 | import me.dadus33.chatitem.utils.ItemUtils; 11 | import me.dadus33.chatitem.utils.Messages; 12 | 13 | public class OneItemShower extends InvShower { 14 | 15 | private final ItemStack item; 16 | 17 | public OneItemShower(Player cible, ItemStack item) { 18 | super("one_item", cible); 19 | 20 | this.item = item.clone(); 21 | } 22 | 23 | @Override 24 | public void open(Player p) { 25 | Inventory inv = ChatItem.getPlatform().createInventory(new CustomInventoryHolder(), 9, Messages.getMessage("inventory.name", "%cible%", name)); 26 | 27 | for(int i = 0; i < 9; i++) 28 | inv.setItem(i, ItemUtils.ITEM_EMPTY_BROWN); 29 | 30 | inv.setItem(4, item); 31 | 32 | p.openInventory(inv); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/invsee/hook/PlayerInventoryShower.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.invsee.hook; 2 | 3 | import java.util.HashMap; 4 | 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.inventory.Inventory; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.PlayerInventory; 9 | 10 | import me.dadus33.chatitem.ChatItem; 11 | import me.dadus33.chatitem.invsee.InvShower; 12 | import me.dadus33.chatitem.listeners.holder.CustomInventoryHolder; 13 | import me.dadus33.chatitem.utils.ItemUtils; 14 | import me.dadus33.chatitem.utils.Messages; 15 | 16 | public class PlayerInventoryShower extends InvShower { 17 | 18 | private final HashMap items = new HashMap<>(); 19 | private final int level; 20 | 21 | public PlayerInventoryShower(Player cible) { 22 | super("inventory", cible); 23 | this.level = cible.getLevel(); 24 | 25 | PlayerInventory pi = cible.getInventory(); 26 | items.put(4, ItemUtils.copyIfExist(pi.getHelmet())); 27 | items.put(5, ItemUtils.copyIfExist(pi.getChestplate())); 28 | items.put(6, ItemUtils.copyIfExist(pi.getLeggings())); 29 | items.put(7, ItemUtils.copyIfExist(pi.getBoots())); 30 | 31 | for(int i = 0; i < pi.getContents().length && i < (54 - 18); i++) 32 | items.put(i + 18, ItemUtils.copyIfExist(pi.getContents()[i])); 33 | } 34 | 35 | @Override 36 | public void open(Player p) { 37 | Inventory inv = ChatItem.getPlatform().createInventory(new CustomInventoryHolder(), 54, Messages.getMessage("inventory.name", "%cible%", name)); 38 | 39 | for(int i = 0; i < 18; i++) 40 | inv.setItem(i, ItemUtils.ITEM_EMPTY_BROWN); 41 | 42 | inv.setItem(2, new ItemStack(ItemUtils.getMaterialWithCompatibility("EXPERIENCE_BOTTLE", "EXP_BOTTLE"), level == 0 ? 1 : (level >= 64 ? 64 : level))); 43 | 44 | items.forEach(inv::setItem); 45 | 46 | p.openInventory(inv); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/itemnamer/INamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.itemnamer; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.ItemStack; 9 | 10 | import me.dadus33.chatitem.Storage; 11 | 12 | public interface INamer { 13 | 14 | /** 15 | * Get priority of this namer.
16 | * Get first name that is not null, with this order: 17 | * - MAJOR 18 | * 19 | * 20 | * @return priority 21 | */ 22 | Priority getPriority(); 23 | 24 | /** 25 | * Get the name of the item thanks to this namer. 26 | * 27 | * @param item the item to get the name 28 | * @param storage the actual config 29 | * @return the name or null if can't find a name 30 | */ 31 | String getName(Player p, ItemStack item, Storage storage); 32 | 33 | public enum Priority { 34 | MAJOR(4), 35 | IMPORTANT(3), 36 | MEDIUM(2), 37 | SMALL(1), 38 | MINOR(0); 39 | 40 | private final int priority; 41 | 42 | Priority(int priority) { 43 | this.priority = priority; 44 | } 45 | 46 | public int getPriority() { 47 | return priority; 48 | } 49 | 50 | public static List getOrderedPriorities() { 51 | return Arrays.stream(values()).sorted((p1, p2) -> p2.getPriority() - p1.getPriority()).collect(Collectors.toList()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/itemnamer/NamerManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.itemnamer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.StringJoiner; 7 | 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.plugin.PluginManager; 12 | 13 | import me.dadus33.chatitem.ChatItem; 14 | import me.dadus33.chatitem.Storage; 15 | import me.dadus33.chatitem.itemnamer.INamer.Priority; 16 | import me.dadus33.chatitem.itemnamer.hook.ChatItemTranslationNamer; 17 | import me.dadus33.chatitem.itemnamer.hook.DefaultNamer; 18 | import me.dadus33.chatitem.itemnamer.hook.ItemDisplayNamer; 19 | import me.dadus33.chatitem.itemnamer.hook.LangUtilsNamer; 20 | 21 | public class NamerManager { 22 | 23 | private static final HashMap> NAMER_PER_PRIORITY = new HashMap<>(); 24 | 25 | public static void load(ChatItem pl) { 26 | NAMER_PER_PRIORITY.clear(); 27 | 28 | StringJoiner sj = new StringJoiner(", "); 29 | PluginManager pm = Bukkit.getPluginManager(); 30 | if(pm.getPlugin("LangUtils") != null) { 31 | addNamer(new LangUtilsNamer()); 32 | sj.add("LangUtils"); 33 | } 34 | if(sj.length() > 0) 35 | pl.getLogger().info("Loaded namer for plugin " + sj.toString() + "."); 36 | 37 | addNamer(new ChatItemTranslationNamer()); 38 | addNamer(new ItemDisplayNamer()); 39 | addNamer(new DefaultNamer()); 40 | } 41 | 42 | /** 43 | * Add namer according to his {@link INamer#getPriority()}'s value 44 | * 45 | * @param namer the namer to add 46 | */ 47 | public static void addNamer(INamer namer) { 48 | getOrCreate(namer.getPriority()).add(namer); 49 | } 50 | 51 | private static List getOrCreate(Priority p){ 52 | return NAMER_PER_PRIORITY.computeIfAbsent(p, (a) -> new ArrayList<>()); 53 | } 54 | 55 | /** 56 | * Get the name of this item, according to this storage. 57 | * 58 | * @param p the player that will see the name 59 | * @param item the item to show 60 | * @param storage the storage 61 | * @return the name (should NOT return null) 62 | */ 63 | public static String getName(Player p, ItemStack item, Storage storage) { 64 | for(Priority pr : Priority.getOrderedPriorities()) { 65 | List allNamers = NAMER_PER_PRIORITY.get(pr); 66 | if(allNamers == null || allNamers.isEmpty()) 67 | continue; 68 | for(INamer namer : allNamers) { 69 | String tmpName = namer.getName(p, item, storage); 70 | if(tmpName != null && tmpName != "") { 71 | ChatItem.debug("Using namer " + namer.getClass().getSimpleName() + ", value: " + tmpName); 72 | return tmpName; 73 | } 74 | } 75 | } 76 | return null; // this should NEVER append 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/itemnamer/hook/ChatItemTranslationNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.itemnamer.hook; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.ItemStack; 5 | 6 | import me.dadus33.chatitem.Storage; 7 | import me.dadus33.chatitem.Translation; 8 | import me.dadus33.chatitem.itemnamer.INamer; 9 | 10 | public class ChatItemTranslationNamer implements INamer { 11 | 12 | @Override 13 | public Priority getPriority() { 14 | return Priority.SMALL; 15 | } 16 | 17 | @Override 18 | public String getName(Player p, ItemStack item, Storage storage) { 19 | return Translation.getOr(item, null); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/itemnamer/hook/DefaultNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.itemnamer.hook; 2 | 3 | import org.apache.commons.lang.WordUtils; 4 | import org.bukkit.Material; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.inventory.ItemStack; 7 | 8 | import me.dadus33.chatitem.Storage; 9 | import me.dadus33.chatitem.itemnamer.INamer; 10 | 11 | public class DefaultNamer implements INamer { 12 | 13 | @Override 14 | public Priority getPriority() { 15 | return Priority.MINOR; 16 | } 17 | 18 | @Override 19 | public String getName(Player p, ItemStack item, Storage storage) { 20 | Material m = item.getType(); 21 | return m.equals(Material.TNT) ? "TNT" : WordUtils.capitalize(m.name().replaceAll("_", " ").toLowerCase()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/itemnamer/hook/ItemDisplayNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.itemnamer.hook; 2 | 3 | import org.bukkit.ChatColor; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.inventory.ItemStack; 6 | 7 | import me.dadus33.chatitem.ChatItem; 8 | import me.dadus33.chatitem.Storage; 9 | import me.dadus33.chatitem.itemnamer.INamer; 10 | 11 | @SuppressWarnings("deprecation") 12 | public class ItemDisplayNamer implements INamer { 13 | 14 | @Override 15 | public Priority getPriority() { 16 | return Priority.MEDIUM; 17 | } 18 | 19 | @Override 20 | public String getName(Player p, ItemStack item, Storage storage) { 21 | String name = ChatItem.getPlatform().getItemDisplayName(item); 22 | if(name != null && name != "") 23 | return storage.colorIfColored ? ChatColor.stripColor(name) : name; 24 | return null; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/itemnamer/hook/LangUtilsNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.itemnamer.hook; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.ItemStack; 5 | 6 | import com.meowj.langutils.lang.LanguageHelper; 7 | 8 | import me.dadus33.chatitem.Storage; 9 | import me.dadus33.chatitem.itemnamer.INamer; 10 | 11 | public class LangUtilsNamer implements INamer { 12 | 13 | @Override 14 | public Priority getPriority() { 15 | return Priority.IMPORTANT; 16 | } 17 | 18 | @Override 19 | public String getName(Player p, ItemStack item, Storage storage) { 20 | return LanguageHelper.getItemName(item, p); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/InventoryListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.bukkit.Material; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.inventory.ClickType; 10 | import org.bukkit.event.inventory.InventoryClickEvent; 11 | import org.bukkit.inventory.Inventory; 12 | import org.bukkit.inventory.InventoryHolder; 13 | import org.bukkit.inventory.ItemStack; 14 | 15 | import me.dadus33.chatitem.ChatItem; 16 | import me.dadus33.chatitem.Storage; 17 | import me.dadus33.chatitem.Translation; 18 | import me.dadus33.chatitem.listeners.holder.AdminHolder; 19 | import me.dadus33.chatitem.listeners.holder.ChatItemHolder; 20 | import me.dadus33.chatitem.listeners.holder.CustomInventoryHolder; 21 | import me.dadus33.chatitem.utils.ItemUtils; 22 | import me.dadus33.chatitem.utils.Messages; 23 | import me.dadus33.chatitem.utils.Utils; 24 | 25 | public class InventoryListener implements Listener { 26 | 27 | @EventHandler 28 | public void onClick(InventoryClickEvent e) { 29 | if (!(e.getWhoClicked() instanceof Player)) 30 | return; 31 | Player p = (Player) e.getWhoClicked(); 32 | 33 | Inventory topInventory = Utils.getTopInventory(e); 34 | InventoryHolder openInventoryHolder = topInventory == null ? null : topInventory.getHolder(); 35 | 36 | if (openInventoryHolder != null && openInventoryHolder instanceof CustomInventoryHolder) { 37 | e.setCancelled(true); 38 | return; 39 | } 40 | if (e.getClickedInventory() == null) 41 | return; 42 | 43 | InventoryHolder holder = e.getClickedInventory().getHolder(); 44 | if (holder == null || !(holder instanceof ChatItemHolder)) { 45 | if (e.getClick().equals(ClickType.DOUBLE_CLICK) && topInventory != null) { 46 | if (openInventoryHolder != null && openInventoryHolder instanceof ChatItemHolder) { 47 | e.setCancelled(true); 48 | } 49 | } 50 | return; 51 | } 52 | if (holder instanceof CustomInventoryHolder) { 53 | e.setCancelled(true); 54 | return; 55 | } 56 | if (!(holder instanceof AdminHolder)) 57 | return; 58 | e.setCancelled(true); 59 | if (e.getCurrentItem() == null) 60 | return; 61 | ItemStack item = e.getCurrentItem(); 62 | Material type = item.getType(); 63 | Storage c = ChatItem.getInstance().getStorage(); 64 | if (type.equals(ItemUtils.MATERIAL_CLOSE)) { 65 | p.closeInventory(); 66 | } else if (type.equals(Material.BOOK)) { 67 | TranslationInventoryListener.open(p, 0); 68 | } else if (type.equals(Material.PAPER)) { 69 | String key = ((AdminHolder) holder).keyBySlot.get(e.getSlot()); 70 | if (key != null) { 71 | setInConfig("manager", key); 72 | p.closeInventory(); 73 | ChatItem.reload(p); 74 | } 75 | } else if (type.equals(ItemUtils.INK_SAC)) { 76 | setInConfig("general.color-if-already-colored", c.colorIfColored = !c.colorIfColored); 77 | open(p); 78 | } else if (type.equals(Material.STICK)) { 79 | setInConfig("general.hand.disabled", c.handDisabled = !c.handDisabled); 80 | open(p); 81 | } else if (type.equals(Material.BLAZE_ROD)) { 82 | setInConfig("general.check-update", c.checkUpdate = !c.checkUpdate); 83 | open(p); 84 | } else if (type.equals(ItemUtils.FIREWORK_CHARGE)) { 85 | setInConfig("debug", c.debug = !c.debug); 86 | open(p); 87 | } else if (type.equals(Material.IRON_DOOR)) { 88 | if (e.getClick().equals(ClickType.RIGHT)) 89 | c.limit--; 90 | else if (e.getClick().equals(ClickType.LEFT)) 91 | c.limit++; 92 | setInConfig("general.limit-per-message", c.limit); 93 | open(p); 94 | } else if (type.equals(Material.APPLE)) { 95 | if (e.getClick().equals(ClickType.RIGHT)) 96 | c.cooldown--; 97 | else if (e.getClick().equals(ClickType.LEFT)) 98 | c.cooldown++; 99 | setInConfig("general.cooldown", c.cooldown); 100 | open(p); 101 | } 102 | } 103 | 104 | public static void setInConfig(String key, Object val) { 105 | ChatItem pl = ChatItem.getInstance(); 106 | pl.getConfig().set(key, val); 107 | pl.saveConfig(); 108 | } 109 | 110 | public static void open(Player p) { 111 | AdminHolder holder = new AdminHolder(); 112 | Storage c = ChatItem.getInstance().getStorage(); 113 | Inventory inv = ChatItem.getPlatform().createInventory(holder, 27, Messages.getMessage("admin-inv.name")); 114 | for (int i = 0; i < inv.getSize(); i++) 115 | inv.setItem(i, ChatItem.getPlatform().createItemStack(ItemUtils.WHITE_STAINED_GLASS, "-")); 116 | 117 | int slot = 0; 118 | for (String manager : Arrays.asList("all", "packet", "chat", "paper")) { //, "ownformatter")) { 119 | if ((manager == "paper" || manager == "ownformatter") && !Utils.IS_PAPER) 120 | continue; 121 | holder.keyBySlot.put(slot, manager); 122 | inv.setItem(slot++, getManagerItem(manager)); 123 | } 124 | inv.setItem(slot + 1, getManagerItem("actual", "%manager%", Messages.getMessage("admin-inv.manager." + c.manager + ".name"))); 125 | 126 | inv.setItem(8, getBoolChangeItem(ItemUtils.FIREWORK_CHARGE, "debug", c.debug)); 127 | 128 | inv.setItem(18, getBoolChangeItem(ItemUtils.INK_SAC, "color-if-already-colored", c.colorIfColored)); 129 | inv.setItem(20, getBoolChangeItem(Material.STICK, "hand-disabled", c.handDisabled)); 130 | inv.setItem(21, getAmountChangeItem(Material.IRON_DOOR, "limit-per-message", c.limit)); 131 | inv.setItem(22, getAmountChangeItem(Material.APPLE, "cooldown", c.cooldown)); 132 | inv.setItem(23, getBoolChangeItem(Material.BLAZE_ROD, "check-update", c.checkUpdate)); 133 | inv.setItem(24, ChatItem.getPlatform().createTranslatedItemStack(Material.BOOK, "admin-inv.language", "%name%", Translation.getMessage("language.name"))); 134 | 135 | inv.setItem(26, ChatItem.getPlatform().createItemStack(ItemUtils.MATERIAL_CLOSE, Messages.getMessage("admin-inv.close"))); 136 | p.openInventory(inv); 137 | } 138 | 139 | private static ItemStack getBoolChangeItem(Material type, String key, boolean b) { 140 | return ChatItem.getPlatform().createItemStack(type, Messages.getMessage("admin-inv." + key, "%state%", Messages.getMessage(b ? "enabled" : "disabled")), 141 | Messages.getMessageList("admin-inv.bool-lore")); 142 | } 143 | 144 | private static ItemStack getAmountChangeItem(Material type, String key, int amount) { 145 | return ChatItem.getPlatform().createItemStack(type, Messages.getMessage("admin-inv." + key, "%state%", amount), Messages.getMessageList("admin-inv.amount-lore")); 146 | } 147 | 148 | private static ItemStack getManagerItem(String manager, Object... placeholders) { 149 | return ChatItem.getPlatform().createTranslatedItemStack(Material.PAPER, "admin-inv.manager." + manager, placeholders); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/JoinListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.Listener; 6 | import org.bukkit.event.player.PlayerJoinEvent; 7 | import org.bukkit.event.player.PlayerQuitEvent; 8 | 9 | import me.dadus33.chatitem.ChatItem; 10 | import me.dadus33.chatitem.chatmanager.ChatManager; 11 | import me.dadus33.chatitem.utils.Utils; 12 | import net.md_5.bungee.api.chat.ClickEvent; 13 | import net.md_5.bungee.api.chat.TextComponent; 14 | 15 | public class JoinListener implements Listener { 16 | 17 | @SuppressWarnings("deprecation") 18 | @EventHandler 19 | public void onJoin(PlayerJoinEvent e) { 20 | Player p = e.getPlayer(); 21 | if(!p.isOp()) 22 | return; 23 | ChatItem pl = ChatItem.getInstance(); 24 | if(pl.isHasNewVersion()) { 25 | TextComponent text = new TextComponent(pl.getStorage().updateMessage); 26 | text.setHoverEvent(Utils.createTextHover(pl.getStorage().updateHover)); 27 | text.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.spigotmc.org/resources/19064/")); 28 | p.spigot().sendMessage(text); 29 | } 30 | } 31 | 32 | @EventHandler 33 | public void onLeft(PlayerQuitEvent e) { 34 | ChatManager.clear(e.getPlayer()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/TranslationInventoryListener.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.inventory.InventoryClickEvent; 11 | import org.bukkit.inventory.Inventory; 12 | import org.bukkit.inventory.ItemFlag; 13 | import org.bukkit.inventory.ItemStack; 14 | import org.bukkit.inventory.meta.ItemMeta; 15 | 16 | import me.dadus33.chatitem.ChatItem; 17 | import me.dadus33.chatitem.Translation; 18 | import me.dadus33.chatitem.listeners.holder.TranslationHolder; 19 | import me.dadus33.chatitem.utils.Colors; 20 | import me.dadus33.chatitem.utils.ItemUtils; 21 | import me.dadus33.chatitem.utils.Messages; 22 | 23 | public class TranslationInventoryListener implements Listener { 24 | 25 | @EventHandler 26 | public void onClick(InventoryClickEvent e) { 27 | if(e.getClickedInventory() == null || !(e.getWhoClicked() instanceof Player) || e.getCurrentItem() == null 28 | || !(e.getClickedInventory().getHolder() instanceof TranslationHolder)) 29 | return; 30 | e.setCancelled(true); 31 | Player p = (Player) e.getWhoClicked(); 32 | ItemStack item = e.getCurrentItem(); 33 | Material type = item.getType(); 34 | TranslationHolder holder = (TranslationHolder) e.getClickedInventory().getHolder(); 35 | if(type.equals(Material.ARROW)) { 36 | if(e.getSlot() == 0) 37 | InventoryListener.open(p); 38 | else if(e.getSlot() == 3) 39 | open(p, holder.getPage() - 1); 40 | else if(e.getSlot() == 5) 41 | open(p, holder.getPage() + 1); 42 | } else if(type.equals(ItemUtils.MATERIAL_CLOSE)) 43 | p.closeInventory(); 44 | else if(type.equals(Material.PAPER)) { 45 | String lang = holder.langBySlot.get(e.getSlot()); 46 | if(lang == null) 47 | return; 48 | p.closeInventory(); 49 | ChatItem pl = ChatItem.getInstance(); 50 | pl.getStorage().language = lang; 51 | pl.getConfig().set("general.language", lang); 52 | pl.saveConfig(); 53 | Translation.loadLang(lang); 54 | p.sendMessage(Colors.GREEN + "Language changed to " + Translation.getMessages().get("language.name").getAsString()); 55 | } 56 | } 57 | 58 | 59 | public static void open(Player p, int page) { 60 | int perPage = 45; 61 | List langs = new ArrayList<>(Translation.getAllLangs().keySet()); 62 | TranslationHolder holder = new TranslationHolder(page); 63 | Inventory inv = ChatItem.getPlatform().createInventory(holder, 54, "Change language - " + Colors.GOLD + " Page " + (page + 1) + " / " + ((langs.size() / perPage) + 1)); 64 | for(int i = 0; i < 9; i ++) 65 | inv.setItem(i, new ItemStack(ItemUtils.GRAY_STAINED_GLASS_PANE)); 66 | inv.setItem(0, ChatItem.getPlatform().createItemStack(Material.ARROW, Colors.GRAY + "Back")); 67 | 68 | if(page > 0) 69 | inv.setItem(3, ChatItem.getPlatform().createItemStack(Material.ARROW, Colors.RED + "Previous page")); 70 | if(langs.size() > (perPage * (page + 1))) 71 | inv.setItem(5, ChatItem.getPlatform().createItemStack(Material.ARROW, Colors.GREEN + "Next page")); 72 | 73 | inv.setItem(8, ChatItem.getPlatform().createItemStack(ItemUtils.MATERIAL_CLOSE, Messages.getMessage("admin-inv.close"))); 74 | 75 | int slot = 9; 76 | for(int i = (page * perPage); i < langs.size() && (i < ((page + 1) * perPage)); i++) { 77 | String lang = langs.get(i); 78 | holder.langBySlot.put(slot, lang); 79 | ItemStack item = ChatItem.getPlatform().createItemStack(Material.PAPER, Colors.GOLD + Translation.getAllLangs().get(lang), Colors.GRAY + "Clic to select this language"); 80 | if(lang.equalsIgnoreCase(ChatItem.getInstance().getStorage().language)) { 81 | item.addUnsafeEnchantment(ItemUtils.getEnchant("DURABILITY", "UNBREAKING"), 1); 82 | ItemMeta meta = item.getItemMeta(); 83 | meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); 84 | item.setItemMeta(meta); 85 | } 86 | inv.setItem(slot++, item); 87 | } 88 | 89 | p.openInventory(inv); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/holder/AdminHolder.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners.holder; 2 | 3 | import java.util.HashMap; 4 | 5 | public class AdminHolder extends ChatItemHolder { 6 | 7 | public final HashMap keyBySlot = new HashMap<>(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/holder/ChatItemHolder.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners.holder; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | import org.bukkit.inventory.InventoryHolder; 5 | 6 | public abstract class ChatItemHolder implements InventoryHolder { 7 | 8 | @Override 9 | public Inventory getInventory() { 10 | return null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/holder/CustomInventoryHolder.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners.holder; 2 | 3 | public class CustomInventoryHolder extends ChatItemHolder { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/listeners/holder/TranslationHolder.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.listeners.holder; 2 | 3 | import java.util.HashMap; 4 | 5 | public class TranslationHolder extends ChatItemHolder { 6 | 7 | public final HashMap langBySlot = new HashMap<>(); 8 | private final int page; 9 | 10 | public TranslationHolder(int page) { 11 | this.page = page; 12 | } 13 | 14 | public int getPage() { 15 | return page; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/platform/IPlatform.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.platform; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.Inventory; 9 | import org.bukkit.inventory.InventoryHolder; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.plugin.Plugin; 12 | 13 | import me.dadus33.chatitem.chatmanager.ChatAction; 14 | import me.dadus33.chatitem.utils.Messages; 15 | import me.dadus33.chatitem.utils.Version; 16 | 17 | public interface IPlatform { 18 | 19 | String getName(); 20 | 21 | Inventory createInventory(InventoryHolder holder, int slot, String name); 22 | 23 | ItemStack createItemStack(Material type, String name); 24 | 25 | default ItemStack createTranslatedItemStack(Material type, String key, Object... placeholders) { 26 | return createItemStack(type, Messages.getMessage(key + ".name", placeholders), Messages.getMessageList(key + ".lore", placeholders)); 27 | } 28 | 29 | default ItemStack createItemStack(Material type, String name, String... lore) { 30 | return createItemStack(type, name, Arrays.asList(lore)); 31 | } 32 | 33 | ItemStack createItemStack(Material type, String name, List lore); 34 | 35 | String getItemDisplayName(ItemStack item); 36 | 37 | String getPluginVersion(Plugin plugin); 38 | 39 | Version getMinecraftVersion(); 40 | 41 | String getNMSVersion(); 42 | 43 | boolean hasBaseComponentSerializer(); 44 | 45 | String baseComponentToJson(Object obj); 46 | 47 | Object jsonToBaseComponent(String json); 48 | 49 | void sendMessage(Player to, Player origin, ChatAction action, String msg); 50 | 51 | String stringifyItem(ItemStack item); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/platform/hook/PaperPlatform.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.platform.hook; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.Material; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.Inventory; 11 | import org.bukkit.inventory.InventoryHolder; 12 | import org.bukkit.inventory.ItemStack; 13 | import org.bukkit.inventory.meta.ItemMeta; 14 | import org.bukkit.plugin.Plugin; 15 | 16 | import me.dadus33.chatitem.C; 17 | import me.dadus33.chatitem.ChatItem; 18 | import me.dadus33.chatitem.chatmanager.ChatAction; 19 | import me.dadus33.chatitem.chatmanager.ChatManager; 20 | import me.dadus33.chatitem.platform.IPlatform; 21 | import me.dadus33.chatitem.utils.Messages; 22 | import me.dadus33.chatitem.utils.ReflectionUtils; 23 | import me.dadus33.chatitem.utils.Version; 24 | import net.kyori.adventure.text.Component; 25 | import net.kyori.adventure.text.TextComponent; 26 | import net.kyori.adventure.text.TextReplacementConfig; 27 | import net.kyori.adventure.text.event.ClickEvent; 28 | import net.kyori.adventure.text.event.HoverEvent; 29 | import net.kyori.adventure.text.event.HoverEvent.ShowItem; 30 | import net.kyori.adventure.text.event.HoverEventSource; 31 | import net.kyori.adventure.text.format.NamedTextColor; 32 | 33 | public class PaperPlatform implements IPlatform { 34 | 35 | @Override 36 | public String getName() { 37 | return "PaperMC"; 38 | } 39 | 40 | @Override 41 | public Inventory createInventory(InventoryHolder holder, int slot, String name) { 42 | return Bukkit.createInventory(holder, slot, C.text(name)); 43 | } 44 | 45 | @Override 46 | public ItemStack createItemStack(Material type, String name) { 47 | ItemStack item = new ItemStack(type); 48 | ItemMeta meta = (ItemMeta) item.getItemMeta(); 49 | meta.displayName(C.text(name).color(NamedTextColor.WHITE)); 50 | item.setItemMeta(meta); 51 | return item; 52 | } 53 | 54 | @Override 55 | public ItemStack createItemStack(Material type, String name, List lore) { 56 | ItemStack item = new ItemStack(type); 57 | ItemMeta meta = (ItemMeta) item.getItemMeta(); 58 | meta.displayName(C.text(name).color(NamedTextColor.WHITE)); 59 | meta.lore(lore.stream().map(C::text).collect(Collectors.toList())); 60 | item.setItemMeta(meta); 61 | return item; 62 | } 63 | 64 | @SuppressWarnings("deprecation") 65 | @Override 66 | public String getItemDisplayName(ItemStack item) { 67 | // actually the get Displayname for better ... See: 68 | // https://github.com/KyoriPowered/adventure-platform/issues/185 69 | // return 70 | // LegacyComponentSerializer.legacySection().serialize(item.displayName()); 71 | return item.hasItemMeta() && item.getItemMeta().hasDisplayName() ? item.getItemMeta().getDisplayName() : null; 72 | } 73 | 74 | @Override 75 | public String getPluginVersion(Plugin plugin) { 76 | return plugin.getPluginMeta().getVersion(); 77 | } 78 | 79 | @Override 80 | public Version getMinecraftVersion() { 81 | return Version.getVersionByName("v" + Bukkit.getMinecraftVersion().replace(".", "_")); 82 | } 83 | 84 | @Override 85 | public String getNMSVersion() { 86 | String[] parts = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(","); 87 | return parts.length <= 3 ? "" : parts[3]; 88 | } 89 | 90 | @Override 91 | public boolean hasBaseComponentSerializer() { 92 | return SpigotPlatform.getBaseComponentToJsonMethod() != null; 93 | } 94 | 95 | private Object getRegistry() throws Exception { 96 | Class serverClass = Class.forName("net.minecraft.server.MinecraftServer"); 97 | return serverClass.getDeclaredMethod("registryAccess").invoke(serverClass.getDeclaredMethod("getServer").invoke(null)); 98 | } 99 | 100 | @Override 101 | public String baseComponentToJson(Object obj) { 102 | Method m = SpigotPlatform.getBaseComponentToJsonMethod(); 103 | if (m == null) 104 | return null; 105 | try { 106 | Object[] args = new Object[m.getParameterCount()]; 107 | args[0] = obj; 108 | if (args.length > 1 && ReflectionUtils.isClassExist("net.minecraft.core.HolderLookup$Provider")) { 109 | Class c = Class.forName("net.minecraft.core.HolderLookup$Provider"); 110 | if (m.getParameterTypes()[1].isAssignableFrom(c)) { 111 | args[1] = getRegistry(); 112 | } 113 | } 114 | return (String) m.invoke(null, args); 115 | } catch (Exception e) { 116 | e.printStackTrace(); 117 | } 118 | return null; 119 | } 120 | 121 | @Override 122 | public Object jsonToBaseComponent(String json) { 123 | Method m = SpigotPlatform.getJsonToBaseComponentMethod(); 124 | try { 125 | Object[] args = new Object[m.getParameterCount()]; 126 | args[0] = json; 127 | if (args.length > 1 && ReflectionUtils.isClassExist("net.minecraft.core.HolderLookup$Provider")) { 128 | Class c = Class.forName("net.minecraft.core.HolderLookup$Provider"); 129 | if (m.getParameterTypes()[1].isAssignableFrom(c)) { 130 | args[1] = getRegistry(); 131 | } 132 | } 133 | return m.invoke(null, args); 134 | } catch (Exception e) { 135 | e.printStackTrace(); 136 | } 137 | return null; 138 | } 139 | 140 | @Override 141 | public void sendMessage(Player to, Player origin, ChatAction action, String msg) { 142 | HoverEventSource hoverEvent = null; 143 | if (action.hasItem()) { 144 | if (!action.getItem().getType().equals(Material.AIR)) 145 | hoverEvent = action.getItem().asHoverEvent(); 146 | else { 147 | Component t = null; 148 | for (String line : Messages.getMessageList("general.hand.tooltip", "%cible%", origin.getName())) { 149 | if (t == null) { 150 | t = Component.text(""); 151 | } else 152 | t.append(Component.newline()); 153 | t.append(C.text(line)); 154 | } 155 | hoverEvent = HoverEvent.showText(t); 156 | } 157 | } else 158 | hoverEvent = HoverEvent.showText(C.text(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", origin.getName()))); 159 | TextComponent like = Component.text(ChatManager.getNameForChatAction(origin, action, ChatItem.getInstance().getStorage())).hoverEvent(hoverEvent); 160 | if (action.hasCommand()) 161 | like = like.clickEvent(ClickEvent.runCommand(action.getCommand())); 162 | 163 | to.sendMessage(C.text(msg).replaceText(TextReplacementConfig.builder().matchLiteral(ChatManager.SEPARATOR + "").replacement(like).build())); 164 | } 165 | 166 | @SuppressWarnings("deprecation") 167 | @Override 168 | public String stringifyItem(ItemStack item) { 169 | ShowItem si = item.asHoverEvent().value(); 170 | String json = "{id:\"" + si.item().asString() + "\",count:" + item.getAmount(); 171 | if(si.nbt() != null) { 172 | json += ",tag:{" + si.nbt().string() + "}"; 173 | } else if(Version.getVersion().isNewerOrEquals(Version.V1_20_6)) { // since MC 1.20.5 in fact 174 | json += ",components:" + (item.hasItemMeta() ? item.getItemMeta().getAsString() : "{}"); 175 | } 176 | json += "}"; 177 | ChatItem.debug("Item stringified: " + json); 178 | return json; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playernamer/IPlayerNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playernamer; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import net.md_5.bungee.api.chat.BaseComponent; 6 | 7 | public interface IPlayerNamer { 8 | 9 | public BaseComponent[] getName(Player p); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playernamer/PlayerNamerManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playernamer; 2 | 3 | import me.dadus33.chatitem.playernamer.hook.HexNicksV3PlayerNamer; 4 | import org.bukkit.Bukkit; 5 | 6 | import me.dadus33.chatitem.ChatItem; 7 | import me.dadus33.chatitem.playernamer.hook.DefaultPlayerNamer; 8 | import me.dadus33.chatitem.playernamer.hook.HexNicksV2PlayerNamer; 9 | import org.bukkit.plugin.Plugin; 10 | 11 | public class PlayerNamerManager { 12 | 13 | private static IPlayerNamer playerNamer; 14 | public static IPlayerNamer getPlayerNamer() { 15 | return playerNamer; 16 | } 17 | public static void setPlayerNamer(IPlayerNamer playerNamer) { 18 | PlayerNamerManager.playerNamer = playerNamer; 19 | } 20 | 21 | public static void load(ChatItem pl) { 22 | Plugin plugin = Bukkit.getPluginManager().getPlugin("HexNicks"); 23 | 24 | 25 | if (plugin != null) { 26 | char majorVersion = ChatItem.getPlatform().getPluginVersion(plugin).charAt(0); 27 | 28 | if (majorVersion == '3') 29 | setPlayerNamer(new HexNicksV3PlayerNamer()); 30 | else 31 | setPlayerNamer(new HexNicksV2PlayerNamer()); 32 | 33 | pl.getLogger().info("Enable support for HexNicks plugin v" + majorVersion); 34 | return; 35 | } 36 | 37 | 38 | 39 | setPlayerNamer(new DefaultPlayerNamer()); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playernamer/hook/DefaultPlayerNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playernamer.hook; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import me.dadus33.chatitem.playernamer.IPlayerNamer; 6 | import net.md_5.bungee.api.chat.BaseComponent; 7 | import net.md_5.bungee.api.chat.ComponentBuilder; 8 | 9 | public class DefaultPlayerNamer implements IPlayerNamer { 10 | 11 | @Override 12 | public BaseComponent[] getName(Player p) { 13 | return new ComponentBuilder(p.getName()).create(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playernamer/hook/HexNicksV2PlayerNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playernamer.hook; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import org.bukkit.entity.Player; 6 | 7 | import me.dadus33.chatitem.playernamer.IPlayerNamer; 8 | import net.kyori.adventure.text.Component; 9 | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; 10 | import net.md_5.bungee.api.chat.BaseComponent; 11 | 12 | public class HexNicksV2PlayerNamer implements IPlayerNamer { 13 | 14 | @Override 15 | public BaseComponent[] getName(Player p) { 16 | try { 17 | Object api = Class.forName("dev.majek.hexnicks.Nicks").getDeclaredMethod("api").invoke(null); 18 | CompletableFuture storedNick = (CompletableFuture) api.getClass().getDeclaredMethod("getStoredNick", Player.class).invoke(api, p); 19 | return BungeeComponentSerializer.get().serialize(storedNick.join()); 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | } 23 | return new BaseComponent[0]; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playernamer/hook/HexNicksV3PlayerNamer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playernamer.hook; 2 | 3 | import dev.majek.hexnicks.HexNicks; 4 | import org.bukkit.entity.Player; 5 | 6 | import me.dadus33.chatitem.playernamer.IPlayerNamer; 7 | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; 8 | import net.md_5.bungee.api.chat.BaseComponent; 9 | 10 | public class HexNicksV3PlayerNamer implements IPlayerNamer { 11 | 12 | @Override 13 | public BaseComponent[] getName(Player p) { 14 | return BungeeComponentSerializer.get().serialize(HexNicks.api().getStoredNick(p).join()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playerversion/IPlayerVersion.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playerversion; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import me.dadus33.chatitem.utils.Version; 6 | 7 | public interface IPlayerVersion { 8 | 9 | public int getProtocolVersion(Player p); 10 | 11 | default Version getPlayerVersion(Player p) { 12 | return Version.getVersion(getProtocolVersion(p), Version.getVersion()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playerversion/PlayerVersionManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playerversion; 2 | 3 | import me.dadus33.chatitem.ChatItem; 4 | import me.dadus33.chatitem.playerversion.hooks.DefaultVersionHook; 5 | import me.dadus33.chatitem.playerversion.hooks.ProtocolSupportHook; 6 | import me.dadus33.chatitem.playerversion.hooks.ViaVersionHook; 7 | import org.bukkit.Bukkit; 8 | 9 | public class PlayerVersionManager { 10 | 11 | private static final IPlayerVersion playerVersionAdapter; 12 | 13 | static { 14 | ChatItem pl = ChatItem.getInstance(); 15 | if (Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null) { 16 | playerVersionAdapter = new ProtocolSupportHook(); 17 | pl.getLogger().info("Loading ProtocolSupport support ..."); 18 | } else if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) { 19 | playerVersionAdapter = new ViaVersionHook(); 20 | pl.getLogger().info("Loading ViaVersion support ..."); 21 | } else { 22 | playerVersionAdapter = new DefaultVersionHook(); 23 | } 24 | } 25 | 26 | public static IPlayerVersion getPlayerVersionAdapter() { 27 | return playerVersionAdapter; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playerversion/hooks/DefaultVersionHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playerversion.hooks; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import me.dadus33.chatitem.playerversion.IPlayerVersion; 6 | import me.dadus33.chatitem.utils.Version; 7 | 8 | public class DefaultVersionHook implements IPlayerVersion { 9 | 10 | @Override 11 | public int getProtocolVersion(Player p) { 12 | return Version.getVersion().MAX_VER; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playerversion/hooks/ProtocolSupportHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playerversion.hooks; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import me.dadus33.chatitem.playerversion.IPlayerVersion; 6 | import protocolsupport.api.ProtocolSupportAPI; 7 | 8 | public class ProtocolSupportHook implements IPlayerVersion { 9 | 10 | @Override 11 | public int getProtocolVersion(Player p) { 12 | return ProtocolSupportAPI.getProtocolVersion(p).getId(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/playerversion/hooks/ViaVersionHook.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.playerversion.hooks; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | import com.viaversion.viaversion.api.Via; 6 | 7 | import me.dadus33.chatitem.playerversion.IPlayerVersion; 8 | 9 | public class ViaVersionHook implements IPlayerVersion { 10 | 11 | @Override 12 | public int getProtocolVersion(Player p) { 13 | return Via.getAPI().getPlayerVersion(p.getUniqueId()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/ColorManager.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import me.dadus33.chatitem.ChatItem; 7 | import net.md_5.bungee.api.ChatColor; 8 | 9 | public class ColorManager { 10 | 11 | public static final char COLOR_CHAR = '§'; 12 | public static final List COLORS = Arrays.asList("4", "c", "6", "e", "2", "a", "b", "3", "1", "9", "d", "5", "f", "7", "8", "0", "k", "l", "m", "n", "o", "r"); 13 | 14 | public static boolean isHexColor(ChatColor c) { 15 | return Version.getVersion().isNewerOrEquals(Version.V1_16) && c.getName().startsWith("#"); 16 | } 17 | 18 | public static boolean isHexColor(String c) { 19 | return Version.getVersion().isNewerOrEquals(Version.V1_16) && c.startsWith("x"); 20 | } 21 | 22 | public static String removeColorAtBegin(String s) { 23 | if(s == null || s.isEmpty()) 24 | return ""; 25 | boolean wasColorChar = s.startsWith(Character.toString(ChatColor.COLOR_CHAR)); 26 | if(!wasColorChar) 27 | return s; 28 | String next = ""; 29 | for(int i = 1; i < s.length(); i++) { 30 | char c = s.charAt(i); 31 | if(wasColorChar) { 32 | if(!COLORS.contains(Character.toString(c))) 33 | next = next + ChatColor.COLOR_CHAR + "" + c; 34 | wasColorChar = false; 35 | } else { 36 | wasColorChar = c == ChatColor.COLOR_CHAR; 37 | if(!wasColorChar) { // something other than color code 38 | next += s.substring(i); 39 | break; 40 | } 41 | } 42 | } 43 | if(next.isEmpty()) 44 | next = s; 45 | return next; 46 | } 47 | 48 | public static String getColorString(String input) { 49 | if (input == null || input.isEmpty()) 50 | return ""; 51 | StringBuilder str = new StringBuilder(); 52 | if (isHexColor(input)) { // x mean it's an hex 53 | input = input.substring(1); 54 | if (input.length() >= 6) { // at least hex 55 | str.append(ChatColor.of("#" + input.substring(0, 6))); // get first hex color code 56 | ChatItem.debug("Str with hex: " + str); 57 | if (input.length() > 6) // if as another color code 58 | str.append(getColorString(input.substring(6))); // get color for after 59 | return str.toString(); 60 | } else 61 | ChatItem.debug("Low len: " + input.length()); 62 | } 63 | // not hex 64 | for (char c : input.toCharArray()) 65 | str.append(ChatColor.getByChar(c)); 66 | return str.toString(); 67 | } 68 | 69 | public static ChatColor getColor(String input) { 70 | if (input == null || input.isEmpty()) 71 | return ChatColor.RESET; 72 | if (isHexColor(input)) { // x mean it's an hex 73 | if (input.length() >= 7) { // at least hex, and 7 because we count the "x" 74 | return ChatColor.of("#" + input.substring(1, 7)); // get first hex color code 75 | } else 76 | ChatItem.debug("Low len: " + input.length()); 77 | } 78 | // not hex 79 | return ChatColor.getByChar(input.charAt(0)); 80 | } 81 | 82 | public static String fixColor(String message) { 83 | String colorCode = "", text = ""; 84 | boolean waiting = false; 85 | for (char args : message.toCharArray()) { 86 | if (args == COLOR_CHAR) { // begin of color 87 | waiting = true; // waiting for color code 88 | } else if (waiting) { // if waiting for code and valid str 89 | // if it's hexademical value and with enough space for full color 90 | waiting = false; 91 | if (args == 'r' && colorCode.isEmpty()) { 92 | text += ChatColor.RESET; 93 | continue; 94 | } 95 | if (args == 'x' && !colorCode.isEmpty()) { 96 | text += ColorManager.getColorString(colorCode); 97 | colorCode = "x"; 98 | } else if(Character.digit(Character.toLowerCase(args), 16) != -1) 99 | colorCode += args; // a color by itself 100 | } else { 101 | waiting = false; 102 | if (!colorCode.isEmpty()) { 103 | if (isHexColor(colorCode) && colorCode.length() >= 7) { 104 | if (colorCode.length() == 7) 105 | text += ColorManager.getColor(colorCode); 106 | else { 107 | text += ColorManager.getColor(colorCode.substring(0, 7)); // only the hex code 108 | text += ColorManager.getColorString(colorCode.substring(7, colorCode.length())); 109 | } 110 | } else if (colorCode.length() == 1) // if only one color code 111 | text += ColorManager.getColor(colorCode); 112 | else 113 | text += ColorManager.getColorString(colorCode); 114 | colorCode = ""; 115 | } 116 | // basic text, not waiting for code after '§' 117 | text += args; 118 | } 119 | } 120 | return text; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/Colors.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import com.google.common.base.Preconditions; 8 | 9 | import net.md_5.bungee.api.ChatColor; 10 | 11 | public class Colors { 12 | 13 | public static final String YELLOW = ColorManager.COLOR_CHAR + "e"; 14 | public static final String AQUA = ColorManager.COLOR_CHAR + "b"; 15 | public static final String GOLD = ColorManager.COLOR_CHAR + "6"; 16 | public static final String GRAY = ColorManager.COLOR_CHAR + "7"; 17 | public static final String RED = ColorManager.COLOR_CHAR + "c"; 18 | public static final String GREEN = ColorManager.COLOR_CHAR + "a"; 19 | public static final String RESET = ColorManager.COLOR_CHAR + "r"; 20 | 21 | 22 | public static String color(String s) { 23 | return s == null || s.isEmpty() ? s : translateAlternateColorCodes('&', s); 24 | } 25 | 26 | public static String translateAlternateColorCodes(char altColorChar, @NotNull String textToTranslate) { 27 | Preconditions.checkArgument(textToTranslate != null, "Cannot translate null text"); 28 | 29 | char[] b = textToTranslate.toCharArray(); 30 | for (int i = 0; i < b.length - 1; i++) { 31 | if (b[i] == altColorChar && ColorManager.COLORS.contains(b[i + 1] + "")) { 32 | b[i] = ColorManager.COLOR_CHAR; 33 | b[i + 1] = Character.toLowerCase(b[i + 1]); 34 | } 35 | } 36 | return new String(b); 37 | } 38 | 39 | public static boolean isFormatting(ChatColor c) { 40 | return Arrays.asList(ChatColor.RESET, ChatColor.BOLD, ChatColor.MAGIC, ChatColor.UNDERLINE, ChatColor.ITALIC, ChatColor.STRIKETHROUGH).contains(c); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/ItemUtils.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.Material; 5 | import org.bukkit.enchantments.Enchantment; 6 | import org.bukkit.inventory.ItemFlag; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.meta.ItemMeta; 9 | 10 | import me.dadus33.chatitem.ChatItem; 11 | 12 | public class ItemUtils { 13 | 14 | public static final Material MATERIAL_CLOSE = getMaterialWithCompatibility("BARRIER", "REDSTONE_BLOCK"); 15 | 16 | // items 17 | public static final Material EMPTY_MAP = getMaterialWithCompatibility("EMPTY_MAP", "MAP"); 18 | public static final Material BOOK_AND_QUILL = getMaterialWithCompatibility("BOOK_AND_QUILL", "WRITTEN_BOOK"); 19 | public static final Material WEB = getMaterialWithCompatibility("WEB", "COBWEB"); 20 | public static final Material FIREBALL = getMaterialWithCompatibility("FIREBALL", "FIRE_CHARGE"); 21 | public static final Material INK_SAC = getMaterialWithCompatibility("INK_SAC", "INK_SACK", "DYE", "GRAY_DYE"); 22 | public static final Material FIREWORK_CHARGE = getMaterialWithCompatibility("FIREWORK_CHARGE", "FIRE_CHARGE"); 23 | 24 | public static final Material BIRCH_WOOD_STAIRS = getMaterialWithCompatibility("BIRCH_WOOD_STAIRS", "BIRCH_STAIRS"); 25 | 26 | // colored items 27 | public static final Material BROWN_STAINED_GLASS_PANE = getMaterialWithCompatibility("BROWN_STAINED_GLASS_PANE", "STAINED_GLASS_PANE"); 28 | public static final Material GRAY_STAINED_GLASS_PANE = getMaterialWithCompatibility("GRAY_STAINED_GLASS_PANE", "STAINED_GLASS_PANE"); 29 | public static final Material WHITE_STAINED_GLASS = getMaterialWithCompatibility("WHITE_STAINED_GLASS_PANE", "STAINED_GLASS_PANE"); 30 | 31 | public static final ItemStack ITEM_EMPTY_BROWN = ChatItem.getPlatform().createItemStack(BROWN_STAINED_GLASS_PANE, ""); 32 | 33 | public static Material getMaterialWithCompatibility(String... tempMat) { 34 | for(String s : tempMat) { 35 | try { 36 | Material m = (Material) Material.class.getField(s).get(Material.class); 37 | if(m != null) 38 | return m; 39 | } catch (IllegalArgumentException | IllegalAccessException | SecurityException e2) { 40 | e2.printStackTrace(); 41 | } catch (NoSuchFieldException e) {} 42 | } 43 | return null; 44 | } 45 | 46 | public static ItemStack hideAttributes(ItemStack stack) { 47 | ItemMeta meta = stack.getItemMeta(); 48 | // All ItemFlags are used to hide attributes, their javadoc says so too. 49 | meta.addItemFlags(ItemFlag.values()); 50 | stack.setItemMeta(meta); 51 | return stack; 52 | } 53 | 54 | public static ItemStack copyIfExist(ItemStack item) { 55 | return isEmpty(item) ? null : item.clone(); 56 | } 57 | 58 | public static boolean isEmpty(ItemStack item) { 59 | return item == null || item.getType().equals(Material.AIR); 60 | } 61 | 62 | @SuppressWarnings("deprecation") 63 | public static void stripData(ItemStack i) { 64 | if (i == null) { 65 | return; 66 | } 67 | if (i.getType().equals(Material.AIR)) { 68 | return; 69 | } 70 | if (!i.hasItemMeta()) { 71 | return; 72 | } 73 | ItemMeta im = Bukkit.getItemFactory().getItemMeta(i.getType()); 74 | ItemMeta original = i.getItemMeta(); 75 | if (original.hasDisplayName()) { 76 | im.setDisplayName(original.getDisplayName()); 77 | } 78 | i.setItemMeta(im); 79 | } 80 | 81 | @SuppressWarnings("deprecation") 82 | public static Enchantment getEnchant(String... names) { 83 | for(String name : names) { 84 | Enchantment possible = Enchantment.getByName(name); 85 | if(possible != null) 86 | return possible; 87 | } 88 | return null; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/Messages.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | import org.bukkit.command.CommandSender; 8 | 9 | import me.dadus33.chatitem.ChatItem; 10 | import me.dadus33.chatitem.Storage; 11 | 12 | public class Messages { 13 | 14 | public static void sendMessage(CommandSender p, String key, Object... placeholders) { 15 | getMessageList(key, placeholders).forEach(p::sendMessage); 16 | } 17 | 18 | public static String getMessage(String key, Object... placeholders) { 19 | return colorAndPlaceholders(ChatItem.getInstance().getConfig().getString("messages." + key, key), placeholders); 20 | } 21 | 22 | public static List getMessageList(String key, Object... placeholders) { 23 | Object obj = ChatItem.getInstance().getConfig().get("messages." + key); 24 | if(obj == null) 25 | return Arrays.asList(key); 26 | if(obj instanceof List) { 27 | return ((List) obj).stream().map((s) -> colorAndPlaceholders(s, placeholders)).collect(Collectors.toList()); 28 | } else if(obj instanceof String) 29 | return Arrays.asList(colorAndPlaceholders((String) obj, placeholders)); 30 | else 31 | return Arrays.asList(colorAndPlaceholders(obj.toString(), placeholders)); 32 | } 33 | 34 | private static String colorAndPlaceholders(String msg, Object... placeholders) { 35 | if(msg == null) 36 | return ""; 37 | for (int index = 0; index <= placeholders.length - 1; index += 2) { 38 | msg = msg.replace(String.valueOf(placeholders[index]), String.valueOf(placeholders[index + 1])); 39 | } 40 | return Storage.color(msg); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/PacketUtils.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | import java.util.Collections; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.inventory.ItemStack; 12 | 13 | import me.dadus33.chatitem.ChatItem; 14 | import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator; 15 | 16 | public class PacketUtils { 17 | 18 | public static final String NMS_PREFIX; 19 | public static final String OBC_PREFIX; 20 | public static final boolean IS_THERMOS = Utils.isClassExist("thermos.Thermos"); 21 | public static final Class COMPONENT_CLASS; 22 | 23 | private static Method getNbtMethod, sendPacketMethod; 24 | 25 | /** 26 | * This Map is to reduce Reflection action which take more resources than just 27 | * RAM action 28 | */ 29 | private static final Map> ALL_CLASS = Collections.synchronizedMap(new HashMap>()); 30 | 31 | static { 32 | String version = ChatItem.getPlatform().getNMSVersion(); 33 | NMS_PREFIX = Version.getVersion().isNewerOrEquals(Version.V1_17) || IS_THERMOS ? "net.minecraft." : "net.minecraft.server." + (version == "" ? "" : version + "."); 34 | OBC_PREFIX = "org.bukkit.craftbukkit." + (version == "" ? "" : version + "."); 35 | COMPONENT_CLASS = getNmsClass("IChatBaseComponent", "network.chat."); 36 | } 37 | 38 | /** 39 | * Get the Class in NMS, with a processing reducer 40 | * 41 | * @param name of the NMS class (in net.minecraft.server package ONLY, because it's NMS) 42 | * @return clazz the searched class 43 | */ 44 | public static Class getNmsClass(String name, String packagePrefix, String... alias) { 45 | return ALL_CLASS.computeIfAbsent(name, (a) -> { 46 | String fullPrefix = NMS_PREFIX + (Version.getVersion().isNewerOrEquals(Version.V1_17) || IS_THERMOS ? packagePrefix : ""); 47 | try { 48 | Class clazz = Class.forName(fullPrefix + name); 49 | if (clazz != null) 50 | return clazz; 51 | } catch (ClassNotFoundException e) {} 52 | 53 | for (String className : alias) { 54 | try { 55 | Class clazz = Class.forName(fullPrefix + className); 56 | if (clazz != null) 57 | return clazz; 58 | } catch (ClassNotFoundException e) {} 59 | } 60 | return null; 61 | }); 62 | } 63 | 64 | /** 65 | * Get the Class in NMS, with a processing reducer 66 | * 67 | * @param name of the NMS class (in net.minecraft.server package ONLY, because 68 | * it's NMS) 69 | * @return clazz the searched class 70 | */ 71 | public static Class getObcClass(String name, String... alias) { 72 | return ALL_CLASS.computeIfAbsent(name, (a) -> { 73 | try { 74 | Class clazz = Class.forName(OBC_PREFIX + name); 75 | if (clazz != null) 76 | return clazz; 77 | } catch (ClassNotFoundException e) { 78 | if (alias.length == 0) 79 | e.printStackTrace(); // no alias, print error 80 | // else ignore and go check for alias 81 | } 82 | 83 | for (String className : alias) { 84 | try { 85 | Class clazz = Class.forName(OBC_PREFIX + className); 86 | if (clazz != null) 87 | return clazz; 88 | } catch (ClassNotFoundException e) { 89 | if (className == alias[alias.length - 1]) // if it's last alias, print error 90 | e.printStackTrace(); 91 | } 92 | } 93 | return null; 94 | }); 95 | } 96 | 97 | /** 98 | * Get NMS entity player of specified one 99 | * 100 | * @param p the player that we want the NMS entity player 101 | * @return the entity player 102 | */ 103 | public static Object getEntityPlayer(Player p) { 104 | try { 105 | return getObcClass("entity.CraftPlayer").getMethod("getHandle").invoke(p); 106 | } catch (Exception e) { 107 | e.printStackTrace(); 108 | return null; 109 | } 110 | } 111 | 112 | /** 113 | * Get NMS player connection of specified player 114 | * 115 | * @param p Player of which we want to get the player connection 116 | * @return the NMS player connection 117 | */ 118 | public static Object getPlayerConnection(Player p) { 119 | try { 120 | Object entityPlayer = getEntityPlayer(p); 121 | return ReflectionUtils.getFirstWith(entityPlayer, entityPlayer.getClass(), getNmsClass("PlayerConnection", "server.network.")); 122 | } catch (Exception e) { 123 | e.printStackTrace(); 124 | return null; 125 | } 126 | } 127 | 128 | /** 129 | * Get NMS entity player of specified one 130 | * 131 | * @param p the player that we want the NMS entity player 132 | * @return the entity player 133 | */ 134 | public static Object getCraftServer() { 135 | try { 136 | return getObcClass("CraftServer").getMethod("getHandle").invoke(Bukkit.getServer()); 137 | } catch (Exception e) { 138 | e.printStackTrace(); 139 | return null; 140 | } 141 | } 142 | 143 | /** 144 | * Send the packet to the specified player 145 | * 146 | * @param p which will receive the packet 147 | * @param packet the packet to sent 148 | */ 149 | public static void sendPacket(Player p, Object packet) { 150 | try { 151 | Object playerConnection = getPlayerConnection(p); 152 | if(sendPacketMethod == null) { 153 | Version v = Version.getVersion(); 154 | if(v.isNewerOrEquals(Version.V1_20)) { 155 | Class packetSrvClass = getNmsClass("ServerCommonPacketListenerImpl", "server.network."); 156 | if(packetSrvClass != null) 157 | sendPacketMethod = packetSrvClass.getDeclaredMethod("b", getNmsClass("Packet", "network.protocol.")); 158 | } 159 | if(sendPacketMethod == null) 160 | sendPacketMethod = playerConnection.getClass().getMethod(Version.getVersion().isNewerOrEquals(Version.V1_18) ? "a" : "sendPacket", getNmsClass("Packet", "network.protocol.")); 161 | } 162 | sendPacketMethod.invoke(playerConnection, packet); 163 | } catch (Exception e) { 164 | e.printStackTrace(); 165 | } 166 | } 167 | 168 | /** 169 | * Converts an {@link org.bukkit.inventory.ItemStack} to a Json string for 170 | * sending with {@link net.md_5.bungee.api.chat.BaseComponent}'s. 171 | * 172 | * @param item the item to convert 173 | * @return the Json string representation of the item 174 | */ 175 | public static String getNbtTag(ItemStack item) { 176 | try { 177 | if (getNbtMethod == null) { 178 | Class itemClass = getNmsClass("ItemStack", "world.item."); 179 | Version v = Version.getVersion(); 180 | if(v.isNewerOrEquals(Version.V1_20_6)) 181 | getNbtMethod = itemClass.getDeclaredMethod("d"); // return DataComponentPatch's object 182 | else if (v.equals(Version.V1_20)) 183 | getNbtMethod = itemClass.getDeclaredMethod("w"); 184 | else if (v.equals(Version.V1_19)) 185 | getNbtMethod = itemClass.getDeclaredMethod("u"); 186 | else if (v.equals(Version.V1_18)) 187 | getNbtMethod = itemClass.getDeclaredMethod("t"); 188 | else 189 | getNbtMethod = itemClass.getDeclaredMethod("getTag"); 190 | 191 | getNbtMethod.setAccessible(true); 192 | } 193 | Object tag = getNbtMethod.invoke(JSONManipulator.AS_NMS_COPY.invoke(null, item)); 194 | return tag == null ? "{}" : tag.toString(); 195 | } catch (Exception e) { 196 | e.printStackTrace(); 197 | } 198 | return "{}"; 199 | } 200 | 201 | public static void printPacketToDebug(Object packet) { 202 | if(!ChatItem.hasDebug()) 203 | return; 204 | if(packet == null) { 205 | ChatItem.debug("Packet is null"); 206 | return; 207 | } 208 | ChatItem.debug("Packet with Class: " + packet.getClass().getSimpleName()); 209 | for (Field f : packet.getClass().getDeclaredFields()) { 210 | f.setAccessible(true); 211 | try { 212 | ChatItem.debug(f.getName() + ": " + f.get(packet)); 213 | } catch (Exception exc) { 214 | exc.printStackTrace(); 215 | } 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.Field; 5 | import java.lang.reflect.Method; 6 | import java.lang.reflect.Modifier; 7 | import java.util.Arrays; 8 | 9 | import me.dadus33.chatitem.ChatItem; 10 | 11 | public class ReflectionUtils { 12 | 13 | public static Method getMethod(Class clazz, String methodName, Class... params) { 14 | try { 15 | return clazz.getMethod(methodName, params); 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | return null; 19 | } 20 | } 21 | 22 | public static Method getMethodByName(Class clazz, String methodName) { 23 | try { 24 | for(Method m : clazz.getDeclaredMethods()) 25 | if(m.getName().equals(methodName)) 26 | return m; 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | return null; 31 | } 32 | 33 | public static Method getMethod(Class clazz, Class returned, Class... params) { 34 | try { 35 | for(Method m : clazz.getDeclaredMethods()) { 36 | if(returned.equals(m.getReturnType()) && areParamsEquals(m.getParameterTypes(), params)) 37 | return m; 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | return null; 43 | } 44 | 45 | private static boolean areParamsEquals(Class[] p1, Class[] p2) { 46 | if(p1.length != p2.length) 47 | return false; 48 | for(int i = 0; i < p1.length; i++) { 49 | if(!p1[i].equals(p2[i])) 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | public static Field getField(Class clazz, String... fieldNames){ 56 | for(String field : fieldNames) { 57 | try{ 58 | Field f = clazz.getDeclaredField(field); 59 | f.setAccessible(true); 60 | return f; 61 | } catch (NoSuchFieldException e) { 62 | // go to next 63 | } 64 | } 65 | ChatItem.getInstance().getLogger().severe("Failed to find field: " + Arrays.asList(fieldNames) + " in class: " + clazz.getCanonicalName()); 66 | return null; 67 | } 68 | 69 | public static Object getPrivateField(Object object, String field) 70 | throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { 71 | Field objectField = object.getClass().getDeclaredField(field); 72 | objectField.setAccessible(true); 73 | return objectField.get(object); 74 | } 75 | 76 | public static void setField(Object src, String fieldName, Object value) { 77 | try { 78 | Field field = src.getClass().getDeclaredField(fieldName); 79 | field.setAccessible(true); 80 | field.set(src, value); 81 | } catch (Exception e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | 86 | public static boolean hasObject(Object source, String... field) { 87 | if(source == null) 88 | return false; 89 | for(String fieldName : field) { 90 | try { 91 | source.getClass().getDeclaredField(fieldName); 92 | return true; 93 | } catch (NoSuchFieldException e) { 94 | // ignore because going to next item 95 | } 96 | } 97 | return false; 98 | } 99 | 100 | /** 101 | * Get the specified field name in the object source 102 | * 103 | * @param source where we will find the field 104 | * @param field the name of the field 105 | * @return the requested object of the field 106 | */ 107 | public static Object getObject(Object source, String... field) { 108 | if(source == null) 109 | return null; 110 | try { 111 | for(String fieldName : field) { 112 | try { 113 | Field f = source.getClass().getDeclaredField(fieldName); 114 | f.setAccessible(true); 115 | return f.get(source); 116 | } catch (NoSuchFieldException e) { 117 | // ignore because going to next item 118 | } 119 | } 120 | ChatItem.getInstance().getLogger().severe("Failed to find fields: " + String.join(", ", field) + " in " + source.getClass().getSimpleName()); 121 | } catch (Exception e) { 122 | e.printStackTrace(); 123 | } 124 | return null; 125 | } 126 | 127 | /** 128 | * Get the specified field name in the object source 129 | * 130 | * @param source where we will find the field 131 | * @param field the name of the field 132 | * @return the requested field 133 | */ 134 | public static Field getField(Object source, String field) { 135 | if(source == null) 136 | return null; 137 | try { 138 | Field f = source.getClass().getDeclaredField(field); 139 | f.setAccessible(true); 140 | return f; 141 | } catch (Exception e) { 142 | e.printStackTrace(); 143 | return null; 144 | } 145 | } 146 | 147 | /** 148 | * Call method. Return the method return. 149 | * 150 | * @param source the object where we want to run the method 151 | * @param method the name of the method to call 152 | * @return the return of the method called 153 | */ 154 | public static Object callMethod(Object source, String method) { 155 | try { 156 | return source.getClass().getDeclaredMethod(method).invoke(source); 157 | } catch (Exception e) { 158 | e.printStackTrace(); 159 | return null; 160 | } 161 | } 162 | 163 | /** 164 | * Get the first object which have the searching for class type 165 | * 166 | * @param from the object where we will try to find the field 167 | * @param clazz the class that have to define the field 168 | * @param searchingFor the class of the required field 169 | * @return the field (or null if not found) 170 | * @throws Exception if something gone wrong 171 | */ 172 | public static T getFirstWith(Object from, Class searchingFor) throws Exception { 173 | return getFirstWith(from, from.getClass(), searchingFor); 174 | } 175 | 176 | /** 177 | * Get the first object which have the searching for class type 178 | * 179 | * @param from the object where we will try to find the field 180 | * @param clazz the class that have to define the field 181 | * @param searchingFor the class of the required field 182 | * @return the field (or null if not found) 183 | * @throws Exception if something gone wrong 184 | */ 185 | public static T getFirstWith(Object from, Class clazz, Class searchingFor) throws Exception { 186 | for (Field f : clazz.getDeclaredFields()) { 187 | if (f.getType().equals(searchingFor) && !Modifier.isStatic(f.getModifiers())) { 188 | f.setAccessible(true); 189 | return (T) f.get(from); 190 | } 191 | } 192 | if(!clazz.getSuperclass().equals(Object.class)) 193 | return getFirstWith(from, clazz.getSuperclass(), searchingFor); 194 | return null; 195 | } 196 | 197 | /** 198 | * Get the first field which have the searching for class type 199 | * 200 | * @param from the object where we will try to find the field 201 | * @param clazz the class that have to define the field 202 | * @param searchingFor the class of the required field 203 | * @return the field (or null if not found) 204 | * @throws Exception if something gone wrong 205 | */ 206 | public static Field getFirstFieldWith(Class clazz, Class searchingFor) throws Exception { 207 | for (Field f : clazz.getDeclaredFields()) { 208 | if (f.getType().equals(searchingFor) && !Modifier.isStatic(f.getModifiers())) { 209 | f.setAccessible(true); 210 | return f; 211 | } 212 | } 213 | return null; 214 | } 215 | 216 | public static boolean isClassExist(String name) { 217 | try { 218 | Class.forName(name); 219 | return true; 220 | } catch (Exception e) { 221 | return false; 222 | } 223 | } 224 | 225 | public static Constructor getConstructor(Class clazz, Class... params) { 226 | try { 227 | return clazz.getConstructor(params); 228 | } catch (Exception e) {} 229 | return null; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/SemVer.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.util.Locale; 4 | import java.util.Objects; 5 | 6 | import javax.annotation.Nullable; 7 | 8 | /** 9 | * Represents the simplified SemVer schema Negativity uses for its plugin versions. 10 | */ 11 | public final class SemVer implements Comparable { 12 | 13 | private final int major; 14 | private final int minor; 15 | private final int patch; 16 | 17 | private final @Nullable Suffix suffix; 18 | 19 | public SemVer(int major, int minor, int patch, @Nullable Suffix suffix) { 20 | this.major = major; 21 | this.minor = minor; 22 | this.patch = patch; 23 | this.suffix = suffix; 24 | } 25 | 26 | public boolean isNewerThan(SemVer other) { 27 | return this.compareTo(other) > 0; 28 | } 29 | 30 | public boolean isOlderThan(SemVer other) { 31 | return this.compareTo(other) < 0; 32 | } 33 | 34 | /** 35 | * Slightly different from {@link #equals} in that this method will return 36 | * true if the suffix has the same {@link Suffix#getWeight() weight} 37 | * but not the same {@link Suffix#getText()} text 38 | */ 39 | public boolean isEquivalentTo(SemVer other) { 40 | return this.compareTo(other) == 0; 41 | } 42 | 43 | public int getMajor() { 44 | return major; 45 | } 46 | 47 | public int getMinor() { 48 | return minor; 49 | } 50 | 51 | public int getPatch() { 52 | return patch; 53 | } 54 | 55 | public @Nullable Suffix getSuffix() { 56 | return suffix; 57 | } 58 | 59 | @Override 60 | public int compareTo(SemVer o) { 61 | int majorDelta = Integer.compare(this.major, o.major); 62 | if (majorDelta != 0) { 63 | return majorDelta; 64 | } 65 | int minorDelta = Integer.compare(this.minor, o.minor); 66 | if (minorDelta != 0) { 67 | return minorDelta; 68 | } 69 | int patchDelta = Integer.compare(this.patch, o.patch); 70 | if (patchDelta != 0) { 71 | return patchDelta; 72 | } 73 | if (this.suffix != null) { 74 | return o.suffix != null ? this.suffix.compareTo(o.suffix) : -1; 75 | } 76 | if (o.suffix != null) { 77 | return 1; 78 | } 79 | return 0; 80 | } 81 | 82 | @Override 83 | public boolean equals(Object o) { 84 | if (this == o) return true; 85 | if (o == null || getClass() != o.getClass()) return false; 86 | SemVer semVer = (SemVer) o; 87 | return major == semVer.major && minor == semVer.minor && patch == semVer.patch && Objects.equals(suffix, semVer.suffix); 88 | } 89 | 90 | @Override 91 | public int hashCode() { 92 | return Objects.hash(major, minor, patch, suffix); 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return "SemVer{major=" + major + ", minor=" + minor + ", patch=" + patch + ", suffix=" + suffix + '}'; 98 | } 99 | 100 | public String toFormattedString() { 101 | if (suffix == null) { 102 | if(patch > 0) 103 | return major + "." + minor + (patch > 0 ? "." + patch : ""); 104 | } 105 | return major + "." + minor + (patch > 0 ? "." + patch : "") + (suffix == null ? "" : "-" + suffix.getText()); 106 | } 107 | 108 | public static @Nullable SemVer parse(String text) { 109 | if (text == null || text.isEmpty()) { 110 | return null; 111 | } 112 | 113 | String[] suffixSplit = text.split("-", 2); 114 | Suffix suffix = null; 115 | if (suffixSplit.length > 1) { 116 | suffix = Suffix.of(suffixSplit[1]); 117 | } 118 | 119 | String[] parts = suffixSplit[0].split("\\."); 120 | int major; 121 | try { 122 | major = Integer.parseInt(parts[0]); 123 | } catch (NumberFormatException e) { 124 | return null; 125 | } 126 | int minor = 0; 127 | if (parts.length > 1) { 128 | try { 129 | minor = Integer.parseInt(parts[1]); 130 | } catch (NumberFormatException ignore) { 131 | } 132 | } 133 | int patch = 0; 134 | if (parts.length > 2) { 135 | try { 136 | patch = Integer.parseInt(parts[2]); 137 | } catch (NumberFormatException ignore) { 138 | } 139 | } 140 | return new SemVer(major, minor, patch, suffix); 141 | } 142 | 143 | public static final class Suffix implements Comparable { 144 | 145 | public static final Suffix SNAPSHOT = new Suffix(0, "SNAPSHOT"); 146 | public static final Suffix ALPHA = new Suffix(1, "ALPHA"); 147 | public static final Suffix BETA = new Suffix(2, "BETA"); 148 | public static final Suffix GAMMA = new Suffix(3, "GAMMA"); 149 | public static final Suffix DELTA = new Suffix(4, "DELTA"); 150 | 151 | private final int weight; 152 | private final String text; 153 | 154 | public Suffix(int weight, String text) { 155 | this.weight = weight; 156 | this.text = text; 157 | } 158 | 159 | public int getWeight() { 160 | return weight; 161 | } 162 | 163 | public String getText() { 164 | return text; 165 | } 166 | 167 | @Override 168 | public int compareTo(Suffix o) { 169 | return Integer.compare(this.weight, o.weight); 170 | } 171 | 172 | @Override 173 | public boolean equals(Object o) { 174 | if (this == o) return true; 175 | if (o == null || getClass() != o.getClass()) return false; 176 | Suffix suffix = (Suffix) o; 177 | return weight == suffix.weight && text.equals(suffix.text); 178 | } 179 | 180 | @Override 181 | public int hashCode() { 182 | return Objects.hash(weight, text); 183 | } 184 | 185 | @Override 186 | public String toString() { 187 | return "Suffix{weight=" + weight + ", text='" + text + "'}"; 188 | } 189 | 190 | public static Suffix of(String text) { 191 | String uppercaseText = text.toUpperCase(Locale.ROOT); 192 | switch (uppercaseText) { 193 | case "SNAPSHOT": 194 | return SNAPSHOT; 195 | case "ALPHA": 196 | return ALPHA; 197 | case "BETA": 198 | return BETA; 199 | case "GAMMA": 200 | return GAMMA; 201 | case "DELTA": 202 | return DELTA; 203 | default: 204 | return new Suffix(-1, uppercaseText); 205 | } 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/me/dadus33/chatitem/utils/Version.java: -------------------------------------------------------------------------------- 1 | package me.dadus33.chatitem.utils; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | import me.dadus33.chatitem.ChatItem; 6 | 7 | public enum Version { 8 | 9 | // http://wiki.vg/Protocol_version_numbers 10 | UNSUPPORTED(0, 5, 7), 11 | V1_8(6, 47, 8), 12 | V1_9(49, 110, 9), // 1.9.X - Starts with 49 as 48 was an april fools update 13 | V1_10(201, 210, 10), // 1.10.X - Starts with 201 because why not. 14 | V1_11(301, 316, 11), 15 | V1_12(317, 340, 12), 16 | V1_13(341, 440, 13), 17 | V1_14(441, 500, 14), 18 | V1_15(550, 578, 15), 19 | V1_16(700, 754, 16), 20 | V1_17(755, 756, 17), 21 | V1_18(757, 758, 18), 22 | V1_19(759, 762, 19), 23 | V1_20(763, 765, 20), 24 | V1_20_6(766, 766, 20.6), 25 | V1_21(767, 1000, 21), 26 | HIGHER(Integer.MAX_VALUE, -1, Integer.MAX_VALUE); 27 | 28 | // Latest version should always have the upper limit set to Integer.MAX_VALUE so 29 | // I don't have to update the plugin for every minor protocol change 30 | 31 | public final int MIN_VER; 32 | public final int MAX_VER; 33 | public final double index; // Represents how new the version is (0 - extremely old) 34 | 35 | private static final Version SERVER_VERSION = ChatItem.getPlatform().getMinecraftVersion(); 36 | 37 | Version(int min, int max, double index) { 38 | this.MIN_VER = min; 39 | this.MAX_VER = max; 40 | this.index = index; 41 | } 42 | 43 | public boolean isNewerOrEquals(Version other) { 44 | return index >= other.index; 45 | } 46 | 47 | public boolean isNewerThan(Version other) { 48 | return index > other.index; 49 | } 50 | 51 | public static Version getVersionByName(String name) { 52 | try { 53 | return Version.valueOf(name.toUpperCase()); 54 | } catch (Exception e) {} 55 | for (Version v : Version.values()) 56 | if (name.toLowerCase().startsWith(v.name().toLowerCase())) 57 | return v; 58 | return HIGHER; 59 | } 60 | 61 | public static Version getVersion(int protocolVersion) { 62 | return getVersion(protocolVersion, HIGHER); 63 | } 64 | 65 | public static Version getVersion(int protocolVersion, Version def) { 66 | for (Version ver : Version.values()) { 67 | if (protocolVersion >= ver.MIN_VER && protocolVersion <= ver.MAX_VER) { 68 | return ver; 69 | } 70 | } 71 | ChatItem.debug("Failed to find version for protocol " + protocolVersion); 72 | return def; 73 | } 74 | 75 | public static Version getVersion() { 76 | return SERVER_VERSION; 77 | } 78 | 79 | public static String stringifyAdress(InetSocketAddress address) { 80 | if(address == null) 81 | return "0.0.0.0:0"; 82 | String port = String.valueOf(address.getPort()); 83 | String ip = address.getAddress().getHostAddress(); 84 | return ip + ":" + port; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/resources/langs.yml: -------------------------------------------------------------------------------- 1 | all: 2 | - "af_za" 3 | - "ar_sa" 4 | - "ast_es" 5 | - "az_az" 6 | - "bar" 7 | - "ba_ru" 8 | - "be_by" 9 | - "bg_bg" 10 | - "brb" 11 | - "br_fr" 12 | - "bs_ba" 13 | - "ca_es" 14 | - "cs_cz" 15 | - "cy_gb" 16 | - "da_dk" 17 | - "de_at" 18 | - "de_ch" 19 | - "de_de" 20 | - "el_gr" 21 | - "enp" 22 | - "enws" 23 | - "en_au" 24 | - "en_ca" 25 | - "en_gb" 26 | - "en_nz" 27 | - "en_pt" 28 | - "en_ud" 29 | - "eo_uy" 30 | - "esan" 31 | - "es_ar" 32 | - "es_cl" 33 | - "es_ec" 34 | - "es_es" 35 | - "es_mx" 36 | - "es_uy" 37 | - "es_ve" 38 | - "et_ee" 39 | - "eu_es" 40 | - "fa_ir" 41 | - "fil_ph" 42 | - "fi_fi" 43 | - "fo_fo" 44 | - "fra_de" 45 | - "fr_ca" 46 | - "fr_fr" 47 | - "fur_it" 48 | - "fy_nl" 49 | - "ga_ie" 50 | - "gd_gb" 51 | - "gl_es" 52 | - "haw_us" 53 | - "he_il" 54 | - "hi_in" 55 | - "hr_hr" 56 | - "hu_hu" 57 | - "hy_am" 58 | - "id_id" 59 | - "ig_ng" 60 | - "io_en" 61 | - "isv" 62 | - "is_is" 63 | - "it_it" 64 | - "ja_jp" 65 | - "jbo_en" 66 | - "ka_ge" 67 | - "kk_kz" 68 | - "kn_in" 69 | - "ko_kr" 70 | - "ksh" 71 | - "kw_gb" 72 | - "la_la" 73 | - "lb_lu" 74 | - "li_li" 75 | - "lmo" 76 | - "lol_us" 77 | - "lt_lt" 78 | - "lv_lv" 79 | - "lzh" 80 | - "mk_mk" 81 | - "mn_mn" 82 | - "ms_my" 83 | - "mt_mt" 84 | - "nds_de" 85 | - "nl_be" 86 | - "nl_nl" 87 | - "nn_no" 88 | - "no_no" 89 | - "oc_fr" 90 | - "ovd" 91 | - "pl_pl" 92 | - "pt_br" 93 | - "pt_pt" 94 | - "qya_aa" 95 | - "ro_ro" 96 | - "rpr" 97 | - "ru_ru" 98 | - "ry_ua" 99 | - "se_no" 100 | - "sk_sk" 101 | - "sl_si" 102 | - "so_so" 103 | - "sq_al" 104 | - "sr_sp" 105 | - "sv_se" 106 | - "sxu" 107 | - "szl" 108 | - "ta_in" 109 | - "th_th" 110 | - "tlh_aa" 111 | - "tl_ph" 112 | - "tok" 113 | - "tr_tr" 114 | - "tt_ru" 115 | - "uk_ua" 116 | - "val_es" 117 | - "vec_it" 118 | - "vi_vn" 119 | - "yi_de" 120 | - "yo_ng" 121 | - "zh_cn" 122 | - "zh_hk" 123 | - "zh_tw" 124 | - "zlm_arab" 125 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: ChatItem 2 | main: me.dadus33.chatitem.ChatItem 3 | version: ${project.version} 4 | 5 | softdepend: [ViaVersion, ProtocolSupport, ProtocolLib, LangUtils, HexNicks, EcoEnchants, DiscordSRV, ChatControl, ChatManager, PlaceholderAPI, MVdWPlaceholderAPI, Vault] 6 | authors: [dadus33, WOLFI3654, Elikill58] 7 | api-version: 1.13 8 | folia-supported: true 9 | 10 | commands: 11 | cireload: 12 | description: Reload the ChatItem config. 13 | aliases: [chatitemreload, citemreload, cir] 14 | permission: chatitem.reload 15 | chatitem: 16 | description: See and edit ChatItem informations 17 | permissions: 18 | chatitem.reload: 19 | description: Allows reloading the config 20 | default: op 21 | chatitem.use: 22 | description: Allows your messages to be parsed by the plugin 23 | default: op 24 | chatitem.ignore-cooldown: 25 | description: Allows you to ignore cooldowns (if enabled) 26 | default: op 27 | --------------------------------------------------------------------------------