commit d7c79d7eac7355ed6e02defa02f7bd5e94ca92db Author: aroooo Date: Thu Oct 20 17:48:16 2022 +0200 initial project commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..1541cee --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..8cf359d --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..670784a --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..ba31031 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..06e8b35 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/dependency-reduced-pom.xml b/core/dependency-reduced-pom.xml new file mode 100644 index 0000000..551faa3 --- /dev/null +++ b/core/dependency-reduced-pom.xml @@ -0,0 +1,118 @@ + + + + nicko-parent + net.artelnatif + 1.0-SNAPSHOT + + 4.0.0 + nicko-core + 1.0-SNAPSHOT + + + + true + ${basedir}/src/main/resources/ + + + + + maven-surefire-plugin + 2.12.4 + + true + + + + maven-shade-plugin + 3.3.1-SNAPSHOT + + + package + + shade + + + + + net.artelnatif:nicko-* + xyz.upperlevel.spigot.book:spigot-book-api + net.wesjd:anvilgui + + + + + xyz.upperlevel.spigot.book + net.artelnatif.bookapi + + + net.wesjd.anvilgui + net.artelnatif.anvilgui + + + false + + + + + + + + + bungeecord-repo + https://oss.sonatype.org/content/repositories/snapshots + + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + codemc-snapshots + https://repo.codemc.io/repository/maven-snapshots/ + + + + + org.spigotmc + spigot-api + 1.18.2-R0.1-SNAPSHOT + provided + + + net.md-5 + bungeecord-api + 1.18-R0.1-SNAPSHOT + compile + + + com.google.guava + guava + 31.1-jre + provided + + + org.junit.jupiter + junit-jupiter-api + 5.8.2 + test + + + opentest4j + org.opentest4j + + + junit-platform-commons + org.junit.platform + + + apiguardian-api + org.apiguardian + + + + + + 17 + 17 + + diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 0000000..2bae2bb --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,124 @@ + + + 4.0.0 + + nicko-core + 1.0-SNAPSHOT + + + net.artelnatif + nicko-parent + 1.0-SNAPSHOT + + + + 17 + 17 + + + + + bungeecord-repo + https://oss.sonatype.org/content/repositories/snapshots + + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + codemc-snapshots + https://repo.codemc.io/repository/maven-snapshots/ + + + + + + org.spigotmc + spigot-api + 1.18.2-R0.1-SNAPSHOT + provided + + + net.md-5 + bungeecord-api + 1.18-R0.1-SNAPSHOT + + + xyz.upperlevel.spigot.book + spigot-book-api + 1.6 + + + net.wesjd + anvilgui + 1.5.3-SNAPSHOT + + + com.google.guava + guava + 31.1-jre + provided + + + org.junit.jupiter + junit-jupiter-api + 5.8.2 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + true + + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.1-SNAPSHOT + + + package + + shade + + + + + net.artelnatif:nicko-* + xyz.upperlevel.spigot.book:spigot-book-api + net.wesjd:anvilgui + + + + + xyz.upperlevel.spigot.book + net.artelnatif.bookapi + + + net.wesjd.anvilgui + net.artelnatif.anvilgui + + + + false + + + + + + + + true + ${basedir}/src/main/resources/ + + + + \ No newline at end of file diff --git a/core/src/main/java/com/yoshiplex/rainbow/RainbowText.java b/core/src/main/java/com/yoshiplex/rainbow/RainbowText.java new file mode 100644 index 0000000..19e926b --- /dev/null +++ b/core/src/main/java/com/yoshiplex/rainbow/RainbowText.java @@ -0,0 +1,104 @@ +package com.yoshiplex.rainbow; + +import java.util.Arrays; +import java.util.List; + +public class RainbowText { + private static final List RAINBOW = Arrays.asList("§4", "§c", "§6", "§a", "§2", "§b", "§3", "§9", "§1", "§5", "§d"); + private int place; + private List rainbowArray = null; + // STOPSHIP: 7/28/22 i18n + private String text = "You did not provide any text."; + private String fancyText = "§4You did not provide any text"; + private String prefix = ""; + + public RainbowText(String text) { + this(text, (String) null); + } + + public RainbowText(String text, String formatCode) { + place = 0; + if (text != null) { + this.text = text; + } + if (formatCode != null) { + prefix = formatCode; + } + rainbowArray = RAINBOW; + updateFancy(); + } + + private void updateFancy() { + int spot = place; + String fancyText = ""; + for (char l : text.toCharArray()) { + String letter = Character.toString(l); + String t1 = fancyText; + if (!letter.equalsIgnoreCase(" ")) { + fancyText = t1 + rainbowArray.get(spot) + prefix + letter; + if (spot == rainbowArray.size() - 1) { + spot = 0; + } else { + spot++; + } + } else { + fancyText = t1 + letter; + } + } + this.fancyText = fancyText; + } + + public void moveRainbow() { + if (rainbowArray.size() - 1 == place) { + place = 0; + } else { + place++; + } + updateFancy(); + } + + public void moveRainbowRight() { + if (place == 0) { + place = rainbowArray.size() - 1; + } else { + place--; + } + updateFancy(); + } + + public String getOrigonalText() { + return this.text; + } + + public String getText() { + return this.fancyText; + } + + public void setPlace(int place) { + if (place > RAINBOW.size() - 1 || place < 0) { + return; + } + this.place = place; + updateFancy(); + } + + public int getPlace() { + return this.place; + } + + public List getRainbow() { + return rainbowArray; + } + + public String getFormatPrefix() { + return this.prefix; + } + + public void setFormatPrefix(String prefix) { + this.prefix = prefix; + } + + public static List getDefaultRainbow() { + return RAINBOW; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/NickoBukkit.java b/core/src/main/java/net/artelnatif/nicko/NickoBukkit.java new file mode 100644 index 0000000..4e42077 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/NickoBukkit.java @@ -0,0 +1,94 @@ +package net.artelnatif.nicko; + +import net.artelnatif.nicko.bungee.NickoBungee; +import net.artelnatif.nicko.command.NickoCommand; +import net.artelnatif.nicko.command.NickoTabCompleter; +import net.artelnatif.nicko.config.NickoConfiguration; +import net.artelnatif.nicko.event.PlayerJoinListener; +import net.artelnatif.nicko.event.PlayerQuitListener; +import net.artelnatif.nicko.impl.Internals; +import net.artelnatif.nicko.impl.InternalsProvider; +import net.artelnatif.nicko.mojang.MojangAPI; +import net.artelnatif.nicko.pluginchannel.UpdateMessageHandler; +import net.artelnatif.nicko.storage.PlayerDataStore; +import net.artelnatif.nicko.utils.ServerUtils; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.java.JavaPlugin; + +public class NickoBukkit extends JavaPlugin { + private static NickoBukkit plugin; + + private NickoConfiguration nickoConfiguration; + private MojangAPI mojangAPI; + private PlayerDataStore dataStore; + + @Override + public void onEnable() { + plugin = this; + + final PluginCommand command = getCommand("nicko"); + if (command != null) { + command.setExecutor(new NickoCommand()); + command.setTabCompleter(new NickoTabCompleter()); + } + + getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this); + getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this); + + mojangAPI = new MojangAPI(); + nickoConfiguration = new NickoConfiguration(this); + + getLogger().info("Loading configuration..."); + saveDefaultConfig(); + + getLogger().info("Loading persistence..."); + dataStore = new PlayerDataStore(this); + if (!dataStore.getStorage().getProvider().init()) { + dataStore.getStorage().setError(true); + getLogger().warning("Failed to open persistence, data will NOT be saved!"); + } + + if (nickoConfiguration.isBungeecordEnabled()) { + getLogger().info("Enabling Bungeecord support..."); + if (ServerUtils.checkBungeeCordHook()) { + getServer().getMessenger().registerIncomingPluginChannel(this, NickoBungee.NICKO_PLUGIN_CHANNEL_UPDATE, new UpdateMessageHandler()); + } + } + + getLogger().info("Nicko (Bukkit) has been enabled."); + } + + @Override + public void onDisable() { + getLogger().info("Closing persistence..."); + if (!dataStore.getStorage().getProvider().close()) { + getLogger().warning("Failed to close persistence!"); + } + if (dataStore.getStorage().isError()) { + dataStore.getStorage().setError(false); + } + + if (nickoConfiguration.isBungeecordEnabled()) { + getServer().getMessenger().unregisterIncomingPluginChannel(this); + getServer().getMessenger().unregisterOutgoingPluginChannel(this); + } + + getLogger().info("Nicko (Bukkit) has been disabled."); + } + + public static NickoBukkit getInstance() { + return plugin; + } + + public MojangAPI getMojangAPI() { + return mojangAPI; + } + + public NickoConfiguration getNickoConfig() { return nickoConfiguration; } + + public PlayerDataStore getDataStore() { return dataStore; } + + public Internals getInternals() { + return InternalsProvider.getInternals(); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java b/core/src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java new file mode 100644 index 0000000..56a687a --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java @@ -0,0 +1,87 @@ +package net.artelnatif.nicko.anvil; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.AppearanceManager; +import net.artelnatif.nicko.disguise.NickoProfile; +import net.artelnatif.nicko.mojang.MojangUtils; +import net.wesjd.anvilgui.AnvilGUI; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class AnvilManager { + private final Player player; + private final NickoProfile profile; + private final AppearanceManager appearanceManager; + + public AnvilManager(Player player) { + this.player = player; + this.appearanceManager = AppearanceManager.get(player); + this.profile = appearanceManager.getProfile(); + } + + public void openNameAndSkinAnvil() { + final AnvilGUI.Builder skin = getSkinAnvil(); + final AnvilGUI.Builder name = new AnvilGUI.Builder() + .plugin(NickoBukkit.getInstance()) + .itemLeft(getLeftItem()) + .onComplete((anvilPlayer, response) -> { + if (MojangUtils.isUsernameInvalid(response)) { + return AnvilGUI.Response.text("Invalid username!"); + } else { + profile.setName(response); + skin.open(player); + return AnvilGUI.Response.close(); + } + }) + .text("New name..."); + + name.open(player); + } + + public void openNameAnvil() { + new AnvilGUI.Builder() + .plugin(NickoBukkit.getInstance()) + .itemLeft(getLeftItem()) + .onComplete((anvilPlayer, response) -> { + if (MojangUtils.isUsernameInvalid(response)) { + return AnvilGUI.Response.text("Invalid username!"); + } else { + appearanceManager.setName(response); + appearanceManager.updatePlayer(false); + return AnvilGUI.Response.close(); + } + }) + .text("New name...") + .open(player); + } + + public void openSkinAnvil() { + getSkinAnvil().open(player); + } + + private AnvilGUI.Builder getSkinAnvil() { + return new AnvilGUI.Builder() + .plugin(NickoBukkit.getInstance()) + .itemLeft(getLeftItem()) + .onComplete((anvilPlayer, response) -> { + if (MojangUtils.isUsernameInvalid(response)) { + return AnvilGUI.Response.text("Invalid username!"); + } else { + appearanceManager.setSkin(response); + appearanceManager.updatePlayer(true); + return AnvilGUI.Response.close(); + } + }) + .text("New skin..."); + } + + private ItemStack getLeftItem() { + final ItemStack item = new ItemStack(Material.PAPER); + final ItemMeta meta = item.getItemMeta(); + meta.setDisplayName("§0ID"); + item.setItemMeta(meta); + return item; + } +} \ No newline at end of file diff --git a/core/src/main/java/net/artelnatif/nicko/bungee/NickoBungee.java b/core/src/main/java/net/artelnatif/nicko/bungee/NickoBungee.java new file mode 100644 index 0000000..8222e15 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/bungee/NickoBungee.java @@ -0,0 +1,33 @@ +package net.artelnatif.nicko.bungee; + +import net.md_5.bungee.api.plugin.Plugin; + +public class NickoBungee extends Plugin { + public static final String NICKO_PLUGIN_CHANNEL_BASE = "nicko:"; + public static final String NICKO_PLUGIN_CHANNEL_FETCH = NICKO_PLUGIN_CHANNEL_BASE + "fetch"; + public static final String NICKO_PLUGIN_CHANNEL_UPDATE = NICKO_PLUGIN_CHANNEL_BASE + "update"; + + private static NickoBungee plugin; + + @Override + public void onEnable() { + getLogger().info("Registering channels..."); + getProxy().registerChannel(NICKO_PLUGIN_CHANNEL_FETCH); + getProxy().registerChannel(NICKO_PLUGIN_CHANNEL_UPDATE); + + getLogger().info("Nicko (Bungee) has been enabled."); + } + + @Override + public void onDisable() { + getLogger().info("Unregistering channels..."); + getProxy().unregisterChannel(NICKO_PLUGIN_CHANNEL_FETCH); + getProxy().unregisterChannel(NICKO_PLUGIN_CHANNEL_UPDATE); + + getLogger().info("Nicko (Bungee) has been disabled."); + } + + public static NickoBungee getInstance() { + return plugin; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/bungee/event/ServerSwitchListener.java b/core/src/main/java/net/artelnatif/nicko/bungee/event/ServerSwitchListener.java new file mode 100644 index 0000000..5877a1c --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/bungee/event/ServerSwitchListener.java @@ -0,0 +1,32 @@ +package net.artelnatif.nicko.bungee.event; + +import net.artelnatif.nicko.bungee.NickoBungee; +import net.artelnatif.nicko.bungee.pluginchannel.PluginChannelHelper; +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.connection.Server; +import net.md_5.bungee.api.event.ServerSwitchEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; + +public class ServerSwitchListener implements Listener { + + /* + * Nicko Message Format + * FETCH: nicko:skin/fetch + * - UUID + * + * UPDATE: nicko:skin/update + * - UUID + * - Skin + * - Name + */ + + @EventHandler + public void onSwitch(ServerSwitchEvent event) { + final ServerInfo from = event.getFrom(); + final ProxiedPlayer player = event.getPlayer(); + final Server to = player.getServer(); + PluginChannelHelper.sendMessage(from, NickoBungee.NICKO_PLUGIN_CHANNEL_FETCH, player.getUniqueId().toString()); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.java b/core/src/main/java/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.java new file mode 100644 index 0000000..a428a5d --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.java @@ -0,0 +1,17 @@ +package net.artelnatif.nicko.bungee.pluginchannel; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import net.md_5.bungee.api.config.ServerInfo; + +public class PluginChannelHelper { + public static boolean sendMessage(final ServerInfo info, final String channel, final String... data) { + final ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.writeUTF(channel); + for (String elt : data) { + output.writeUTF(elt); + } + System.out.printf("(%s) PluginMessage <-> %s", info.getSocketAddress().toString(), output); + return info.sendData(channel, output.toByteArray(), false); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/NickoCommand.java b/core/src/main/java/net/artelnatif/nicko/command/NickoCommand.java new file mode 100644 index 0000000..4f24e42 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/NickoCommand.java @@ -0,0 +1,56 @@ +package net.artelnatif.nicko.command; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.command.sub.NickoCheckSubCmd; +import net.artelnatif.nicko.command.sub.NickoDebugSubCmd; +import net.artelnatif.nicko.command.sub.NickoDisguiseSubCmd; +import net.artelnatif.nicko.command.sub.NickoGUISubCmd; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; + +public class NickoCommand implements CommandExecutor { + private final String opPrefix = "§c(OP)"; + private String helpMessage = """ + §cNicko §8§o[{version}] §f- §2Help: + §6/nicko disguise §f- §7Change your appearance. + §6/nicko revert §f- §7Revert your appearance to your default skin and name. + §6/nicko help §f- §7Prints this help message. + """; + private String adminHelpMessage = """ + {admin} §6/nicko disguise §b §f- §7Change designed player's appearance. + {admin} §6/nicko revert §b §f- §7Revert designed player's appearance to their default skin and name. + {admin} §6/nicko check §b §f- §7Prints detailed information about designed player's appearance. + """.replace("{admin}", opPrefix); + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length >= 1) { + switch (args[0]) { + case "disguise" -> new NickoDisguiseSubCmd(this).execute(sender); + case "debug" -> new NickoDebugSubCmd(this).execute(sender, args); + case "check" -> new NickoCheckSubCmd(this).execute(sender, args); + case "gui" -> new NickoGUISubCmd(this).execute(sender, args); + default -> sendHelpMessages(sender); + } + } else { + sendHelpMessages(sender); + } + + return false; + } + + public void sendHelpMessages(CommandSender sender) { + helpMessage = helpMessage.replace("{version}", NickoBukkit.getInstance().getDescription().getVersion()); + if (sender instanceof ConsoleCommandSender) { + helpMessage = ChatColor.stripColor(helpMessage); + adminHelpMessage = ChatColor.stripColor(adminHelpMessage); + } + sender.sendMessage(helpMessage); + if (sender.isOp()) { + sender.sendMessage(adminHelpMessage); + } + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/NickoPermissions.java b/core/src/main/java/net/artelnatif/nicko/command/NickoPermissions.java new file mode 100644 index 0000000..a1dac76 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/NickoPermissions.java @@ -0,0 +1,16 @@ +package net.artelnatif.nicko.command; + +import net.artelnatif.nicko.NickoBukkit; + +public class NickoPermissions { + + public static final String NICKO_PERMISSION_BASE = "nicko."; + // TODO: 20/06/2022 i18n + public static final String NICKO_PERMISSION_MISSING = NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cMissing permission."; + + public static final class Player { + public static final class Command { + public static final String NICKO_PERMISSION_PLAYER_COMMAND_USE = NICKO_PERMISSION_BASE + "use"; + } + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/NickoTabCompleter.java b/core/src/main/java/net/artelnatif/nicko/command/NickoTabCompleter.java new file mode 100644 index 0000000..90f820e --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/NickoTabCompleter.java @@ -0,0 +1,27 @@ +package net.artelnatif.nicko.command; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; + +import java.util.Collections; +import java.util.List; + +public class NickoTabCompleter implements TabCompleter { + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (sender instanceof Player) { + if (args.length == 1) { + return List.of("disguise", "revert", "help", "check"); + } else if (args.length == 2 && !args[0].equalsIgnoreCase("help")) { + return Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName).toList(); + } else { + return Collections.emptyList(); + } + } + return null; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.java b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.java new file mode 100644 index 0000000..da93eb6 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.java @@ -0,0 +1,41 @@ +package net.artelnatif.nicko.command.sub; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.command.NickoCommand; +import net.artelnatif.nicko.disguise.AppearanceManager; +import net.artelnatif.nicko.utils.PlayerUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.StringJoiner; + +public class NickoCheckSubCmd extends NickoSubCmd { + public NickoCheckSubCmd(NickoCommand nickoCommand) { + super(nickoCommand); + } + + public void execute(CommandSender sender, String[] args) { + final String targetName = args[1]; + final Player target = Bukkit.getPlayerExact(targetName); + + AppearanceManager appearanceManager; + if (PlayerUtils.isPlayerOffline(target)) { + appearanceManager = AppearanceManager.get(targetName); + } else { + appearanceManager = AppearanceManager.get(target); + } + + final StringJoiner builder = new StringJoiner("\n"); + builder.add("§c" + NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§f- §6Check for:§f§o" + targetName); + if (!appearanceManager.hasData()) { + builder.add("§cThis player has not data."); + } else { + builder.add("§7- §fNicked: " + (appearanceManager.isNicked() ? "§a✔" : "§c❌")); + builder.add("§7- §fNickname: §6" + (appearanceManager.getName().equals(targetName) ? "N/A" : appearanceManager.getName())); + builder.add("§7- §fSkin: §6" + (appearanceManager.getSkin().equals(targetName) ? "N/A" : appearanceManager.getSkin())); + } + + sender.sendMessage(builder.toString()); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.java b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.java new file mode 100644 index 0000000..4160f8e --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.java @@ -0,0 +1,54 @@ +package net.artelnatif.nicko.command.sub; + +import com.yoshiplex.rainbow.RainbowText; +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.command.NickoCommand; +import net.artelnatif.nicko.disguise.AppearanceManager; +import net.artelnatif.nicko.mojang.MojangUtils; +import net.artelnatif.nicko.utils.PlayerUtils; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class NickoDebugSubCmd extends NickoSubCmd { + + public NickoDebugSubCmd(NickoCommand nickoCommand) { + super(nickoCommand); + } + + public void execute(CommandSender sender, String[] args) { + Player target; + String name, skin; + if (args.length == 3) { + target = (Player) sender; + name = args[1]; + skin = args[2]; + } else { + final String playerName = args[1]; + target = Bukkit.getPlayer(playerName); + + if(args.length < 3) { + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cMissing argument."); + } + + name = args[2]; + skin = args[3]; + if (PlayerUtils.isPlayerOffline(target)) { + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cSpecified player is offline."); + return; + } + } + + final AppearanceManager appearanceManager = AppearanceManager.get(target.getPlayer()); + + if (MojangUtils.isUsernameInvalid(name) || MojangUtils.isUsernameInvalid(skin)) { + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cSpecified username is invalid."); + } + + appearanceManager.setNameAndSkin(name, skin); + final RainbowText whooshText = new RainbowText("Whoosh!"); + target.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + whooshText.getText()); + target.playSound(target.getLocation(), Sound.ENTITY_ITEM_FRAME_PLACE, 1, 1); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.java b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.java new file mode 100644 index 0000000..9d3c0ab --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.java @@ -0,0 +1,80 @@ +package net.artelnatif.nicko.command.sub; + +import com.yoshiplex.rainbow.RainbowText; +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.command.NickoCommand; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import xyz.upperlevel.spigot.book.BookUtil; + +import java.util.Random; + +public class NickoDisguiseSubCmd extends NickoSubCmd { + + public NickoDisguiseSubCmd(NickoCommand nickoCommand) { + super(nickoCommand); + } + + public void execute(CommandSender sender) { + if (sender instanceof Player player) { + final String disguiseBaseCommand = "/nicko gui {player} "; + final String disguiseNameCommand = disguiseBaseCommand + "name"; + final String disguiseSkinCommand = disguiseBaseCommand + "skin"; + final String disguiseBothCommand = disguiseBaseCommand + "full"; + + final RainbowText text = new RainbowText(NickoBukkit.getInstance().getNickoConfig().getDisguiseKitHeader()); + final int displacement = new Random().nextInt(RainbowText.getDefaultRainbow().size() - 1); + text.setPlace(displacement); + + final ItemStack book = BookUtil.writtenBook() + .author("Nicko") + .title("§6Nicko - Book of magic") + .generation(BookMeta.Generation.ORIGINAL) + .pages( + new BookUtil.PageBuilder() + .add( + new TextComponent(text.getText()) + ) + .newLine() + .newLine() + .add("§0This disguise kit will help you change your name and skin.") + .newLine() + .newLine() + .add("§0Go through each page until the end or cancel the process at any time by exiting any of the interfaces.") + .build(), + new BookUtil.PageBuilder() + .add( + BookUtil.TextBuilder.of("§6> §0Change my skin") + .onHover(BookUtil.HoverAction.showText("Clicking this will prompt you a menu to change your skin.")) + .onClick(BookUtil.ClickAction.runCommand(disguiseSkinCommand.replace("{player}", player.getName()))) + .build() + ) + .newLine() + .newLine() + .add( + BookUtil.TextBuilder.of("§6> §0Change my name") + .onHover(BookUtil.HoverAction.showText("Clicking this will prompt you a menu to change your name.")) + .onClick(BookUtil.ClickAction.runCommand(disguiseNameCommand.replace("{player}", player.getName()))) + .build() + ) + .newLine() + .newLine() + .add( + BookUtil.TextBuilder.of("§6> §0Change both") + .onHover(BookUtil.HoverAction.showText("Clicking this will prompt you a menu to change both your name and your skin.")) + .onClick(BookUtil.ClickAction.runCommand(disguiseBothCommand.replace("{player}", player.getName()))) + .build() + ) + .build() + ) + .build(); + + BookUtil.openPlayer(player, book); + } else { + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "This command can only be performed by players!"); + } + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/command/sub/NickoGUISubCmd.java b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoGUISubCmd.java new file mode 100644 index 0000000..6b15083 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoGUISubCmd.java @@ -0,0 +1,49 @@ +package net.artelnatif.nicko.command.sub; + +import com.yoshiplex.rainbow.RainbowText; +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.anvil.AnvilManager; +import net.artelnatif.nicko.command.NickoCommand; +import net.artelnatif.nicko.command.NickoPermissions; +import net.artelnatif.nicko.utils.PlayerUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class NickoGUISubCmd extends NickoSubCmd { + public NickoGUISubCmd(NickoCommand nickoCommand) { + super(nickoCommand); + } + + public void execute(CommandSender sender, String[] args) { + Player target; + if (args.length < 3) { + target = (Player) sender; + } else { + final String playerName = args[1]; + target = Bukkit.getPlayerExact(playerName); + if (PlayerUtils.isPlayerOffline(target)) { + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cSpecified player is offline."); + return; + } + + if (!sender.hasPermission(NickoPermissions.Player.Command.NICKO_PERMISSION_PLAYER_COMMAND_USE)) { + sender.sendMessage(NickoPermissions.NICKO_PERMISSION_MISSING); + return; + } + } + + final AnvilManager manager = new AnvilManager(target); + final String arg = args.length < 3 ? args[1] : args[2]; + switch (arg) { + case "name" -> manager.openNameAnvil(); + case "skin" -> manager.openSkinAnvil(); + case "full" -> manager.openNameAndSkinAnvil(); + default -> + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cInvalid argument."); + } + + final RainbowText whooshText = target == sender ? new RainbowText("Success!") : new RainbowText("Success! %player% is now undercover!".replace("%player%", target.getName())); + sender.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + whooshText.getText()); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/artelnatif/nicko/command/sub/NickoSubCmd.java b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoSubCmd.java new file mode 100644 index 0000000..0c94674 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/command/sub/NickoSubCmd.java @@ -0,0 +1,15 @@ +package net.artelnatif.nicko.command.sub; + +import net.artelnatif.nicko.command.NickoCommand; + +public class NickoSubCmd { + private final NickoCommand nickoCommand; + + public NickoSubCmd(NickoCommand nickoCommand) { + this.nickoCommand = nickoCommand; + } + + public NickoCommand getMainCommand() { + return nickoCommand; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/config/NickoConfiguration.java b/core/src/main/java/net/artelnatif/nicko/config/NickoConfiguration.java new file mode 100644 index 0000000..8e852ed --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/config/NickoConfiguration.java @@ -0,0 +1,41 @@ +package net.artelnatif.nicko.config; + +import net.artelnatif.nicko.NickoBukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; + +public class NickoConfiguration { + private final NickoBukkit nicko; + + public NickoConfiguration(NickoBukkit nicko) { + this.nicko = nicko; + } + + public String getPrefix() { + return getConfig().getString("prefix"); + } + + public String getDisguiseKitHeader() { + return getConfig().getString("disguisekit.header"); + } + + public ConfigurationSection getBungeecordSection() { return getConfig().getConfigurationSection("bungeecord"); } + + public ConfigurationSection getStorageSction() { return getConfig().getConfigurationSection("storage"); } + + public ConfigurationSection getRedisSection() { return getBungeecordSection().getConfigurationSection("redis"); } + + public boolean isLocalStorage() { return getStorageSction().getBoolean("local"); } + + public boolean isBungeecordEnabled() { return getBungeecordSection().getBoolean("enabled"); } + + public String getStorageUsername() { return getStorageSction().getString("username"); } + + public String getStoragePassword() { return getStorageSction().getString("password"); } + + public String getStorageAddress() { return getStorageSction().getString("address"); } + + private FileConfiguration getConfig() { + return nicko.getConfig(); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java b/core/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java new file mode 100644 index 0000000..654a906 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java @@ -0,0 +1,71 @@ +package net.artelnatif.nicko.disguise; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.storage.PlayerDataStore; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; + +public class AppearanceManager { + private final NickoProfile profile; + private final Player player; + private final NickoBukkit instance = NickoBukkit.getInstance(); + private final PlayerDataStore dataStore = instance.getDataStore(); + + private AppearanceManager(UUID uuid) { + this.player = Bukkit.getPlayer(uuid); + this.profile = dataStore.getData(uuid).orElse(NickoProfile.EMPTY_PROFILE); + } + + private AppearanceManager(String name) { + this.player = null; + this.profile = dataStore.getOfflineData(name).orElse(NickoProfile.EMPTY_PROFILE); + } + + public static AppearanceManager get(Player player) { + return new AppearanceManager(player.getUniqueId()); + } + + public static AppearanceManager get(String name) { + return new AppearanceManager(name); + } + + public boolean hasData() { + return !profile.isEmpty(); + } + + public boolean isNicked() { + return hasData() && !profile.getSkin().equals(player.getName()) || !profile.getName().equals(player.getName()); + } + + public void setSkin(String skin) { + profile.setSkin(skin); + } + + public String getSkin() { + return profile.getSkin(); + } + + public void setName(String name) { + profile.setName(name); + } + + public String getName() { + return profile.getName(); + } + + public NickoProfile getProfile() { + return profile; + } + + public void setNameAndSkin(String name, String skin) { + this.profile.setName(name); + this.profile.setSkin(skin); + updatePlayer(true); + } + + public void updatePlayer(boolean skinChange) { + NickoBukkit.getInstance().getInternals().updateProfile(player, profile, skinChange); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/disguise/NickoProfile.java b/core/src/main/java/net/artelnatif/nicko/disguise/NickoProfile.java new file mode 100644 index 0000000..c7832b1 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/disguise/NickoProfile.java @@ -0,0 +1,42 @@ +package net.artelnatif.nicko.disguise; + +public class NickoProfile { + public static final NickoProfile EMPTY_PROFILE = new NickoProfile(null, null); + + private String name; + private String skin; + + public NickoProfile(String name, String skin) { + this.name = name; + this.skin = skin; + } + + public boolean isEmpty() { + return this != NickoProfile.EMPTY_PROFILE || (name == null && skin == null); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSkin() { + return skin; + } + + public void setSkin(String skin) { + this.skin = skin; + } + + @Override + public String toString() { + return "NickoProfile{" + + "name='" + name + '\'' + + ", skin='" + skin + '\'' + + ", empty='" + isEmpty() + '\'' + + '}'; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/event/PlayerJoinListener.java b/core/src/main/java/net/artelnatif/nicko/event/PlayerJoinListener.java new file mode 100644 index 0000000..71ff57d --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/event/PlayerJoinListener.java @@ -0,0 +1,24 @@ +package net.artelnatif.nicko.event; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.AppearanceManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerJoinListener implements Listener { + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + final Player player = event.getPlayer(); + Bukkit.getScheduler().runTaskLater(NickoBukkit.getInstance(), () -> { + final AppearanceManager appearanceManager = AppearanceManager.get(player); + + if (appearanceManager.hasData()) { + final boolean skinChange = !player.getName().equals(appearanceManager.getSkin()); + appearanceManager.updatePlayer(skinChange); + } + }, 20L); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/event/PlayerQuitListener.java b/core/src/main/java/net/artelnatif/nicko/event/PlayerQuitListener.java new file mode 100644 index 0000000..ff7e28f --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/event/PlayerQuitListener.java @@ -0,0 +1,15 @@ +package net.artelnatif.nicko.event; + +import net.artelnatif.nicko.NickoBukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerQuitListener implements Listener { + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + final Player player = event.getPlayer(); + NickoBukkit.getInstance().getDataStore().saveData(player); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/i18n/I18N.java b/core/src/main/java/net/artelnatif/nicko/i18n/I18N.java new file mode 100644 index 0000000..c1e75d5 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/i18n/I18N.java @@ -0,0 +1,13 @@ +package net.artelnatif.nicko.i18n; + +import net.artelnatif.nicko.NickoBukkit; + +public class I18N { + public static final class Message { + public static final String BASE = NickoBukkit.getInstance().getNickoConfig().getPrefix() + " "; + + public static final class Command { + public static final String TARGET_OFFLINE = BASE + "§cSpecified player is offline. Try again."; + } + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/impl/Internals.java b/core/src/main/java/net/artelnatif/nicko/impl/Internals.java new file mode 100644 index 0000000..7a319af --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/impl/Internals.java @@ -0,0 +1,10 @@ +package net.artelnatif.nicko.impl; + +import net.artelnatif.nicko.disguise.NickoProfile; +import org.bukkit.entity.Player; + +public interface Internals { + void updateSelf(Player player); + void updateOthers(Player player); + void updateProfile(Player player, NickoProfile profile, boolean skinChange); +} diff --git a/core/src/main/java/net/artelnatif/nicko/impl/InternalsProvider.java b/core/src/main/java/net/artelnatif/nicko/impl/InternalsProvider.java new file mode 100644 index 0000000..bb5c236 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/impl/InternalsProvider.java @@ -0,0 +1,29 @@ +package net.artelnatif.nicko.impl; + +import org.bukkit.Bukkit; + +import java.lang.reflect.InvocationTargetException; +import java.util.logging.Level; + +public class InternalsProvider { + private static Internals internals; + + static { + try { + final String packageName = Internals.class.getPackage().getName(); + final String bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + final String fullClassName = packageName + "." + bukkitVersion; + System.out.println("[DEBUG] packageName = " + packageName); + System.out.println("[DEBUG] bukkitVersion = " + bukkitVersion); + System.out.println("[DEBUG] Searching for " + fullClassName + "..."); + internals = (Internals) Class.forName(fullClassName).getConstructors()[0].newInstance(); + } catch (InvocationTargetException | ClassNotFoundException | InstantiationException | IllegalAccessException | + ClassCastException exception) { + Bukkit.getLogger().log(Level.SEVERE, "Nicko could not find a valid implementation for this server version. Is your server supported?"); + } + } + + public static Internals getInternals() { + return internals; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java b/core/src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java new file mode 100644 index 0000000..5b07444 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java @@ -0,0 +1,89 @@ +package net.artelnatif.nicko.mojang; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; + +import javax.annotation.Nonnull; +import javax.net.ssl.HttpsURLConnection; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +public class MojangAPI { + public static final String URL_NAME = "https://api.mojang.com/users/profiles/minecraft/{name}"; + public static final String URL_SKIN = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false"; + + private final CacheLoader> loader = new CacheLoader<>() { + @Nonnull + public Optional load(@Nonnull String uuid) throws Exception { + return getSkinFromMojang(uuid); + } + }; + private final LoadingCache> cache = CacheBuilder + .newBuilder() + .build(loader); + + public Optional getSkin(String uuid) throws IOException, ExecutionException { + return cache.get(uuid); + } + + public Optional getUUID(String name) throws IOException { + final String parametrizedUrl = URL_NAME.replace("{name}", name); + final JsonObject object = getRequestToUrl(parametrizedUrl); + if (hasNoError(object)) { + return Optional.of(object.get("id").getAsString()); + } + return Optional.empty(); + } + + private Optional getSkinFromMojang(String uuid) throws IOException { + final String parametrizedUrl = URL_SKIN.replace("{uuid}", uuid); + final JsonObject object = getRequestToUrl(parametrizedUrl); + if (hasNoError(object)) { + final MojangSkin skin = MojangSkin.buildFromJson(object); + return Optional.of(skin); + } + + return Optional.empty(); + } + + private JsonObject getRequestToUrl(String parametrizedUrl) throws IOException { + final URL url = new URL(parametrizedUrl); + final HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); + con.setDoInput(true); + con.setRequestMethod("GET"); + + final BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream())); + final StringBuilder builder = new StringBuilder(); + String line; + while ((line = input.readLine()) != null) { + builder.append(line); + } + + try { + final JsonElement jsonElt = JsonParser.parseString(builder.toString()); + return jsonElt.getAsJsonObject(); + } catch (JsonParseException | IllegalStateException exception) { + System.out.println("Failed to parse request (" + parametrizedUrl + ")! Does the username exists?"); + return getErrorObject(); + } + } + + private JsonObject getErrorObject() { + final JsonObject errorObject = new JsonObject(); + errorObject.addProperty("error", "An error occurred."); + return errorObject; + } + + private boolean hasNoError(JsonObject object) { + return object.get("error") == null; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/mojang/MojangSkin.java b/core/src/main/java/net/artelnatif/nicko/mojang/MojangSkin.java new file mode 100644 index 0000000..4d1ad1b --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/mojang/MojangSkin.java @@ -0,0 +1,13 @@ +package net.artelnatif.nicko.mojang; + +import com.google.gson.JsonObject; + +public record MojangSkin(String name, String value, String signature) { + public static MojangSkin buildFromJson(JsonObject object) { + final String name = object.get("name").getAsString(); + final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject(); + final String value = properties.get("value").getAsString(); + final String signature = properties.get("signature").getAsString(); + return new MojangSkin(name, value, signature); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/mojang/MojangUtils.java b/core/src/main/java/net/artelnatif/nicko/mojang/MojangUtils.java new file mode 100644 index 0000000..135c210 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/mojang/MojangUtils.java @@ -0,0 +1,26 @@ +package net.artelnatif.nicko.mojang; + +import java.util.UUID; +import java.util.regex.Pattern; + +public class MojangUtils { + public static boolean isUsernameInvalid(String username) { + return !Pattern.matches("^\\w{3,16}$", username); + } + + public static UUID fromTrimmed(String trimmedUUID) throws IllegalArgumentException { + if (trimmedUUID == null) throw new IllegalArgumentException(); + StringBuilder builder = new StringBuilder(trimmedUUID.trim()); + /* Backwards adding to avoid index adjustments */ + try { + builder.insert(20, "-"); + builder.insert(16, "-"); + builder.insert(12, "-"); + builder.insert(8, "-"); + } catch (StringIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } + + return UUID.fromString(builder.toString()); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/pluginchannel/UpdateMessageHandler.java b/core/src/main/java/net/artelnatif/nicko/pluginchannel/UpdateMessageHandler.java new file mode 100644 index 0000000..aab7624 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/pluginchannel/UpdateMessageHandler.java @@ -0,0 +1,22 @@ +package net.artelnatif.nicko.pluginchannel; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteStreams; +import net.artelnatif.nicko.bungee.NickoBungee; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; + +public class UpdateMessageHandler implements PluginMessageListener { + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] message) { + if(!channel.equals(NickoBungee.NICKO_PLUGIN_CHANNEL_UPDATE)) { + return; + } + + final ByteArrayDataInput in = ByteStreams.newDataInput(message); + final String subchannel = in.readUTF(); + if(subchannel.equals(NickoBungee.NICKO_PLUGIN_CHANNEL_UPDATE)) { + // TODO: 10/20/22 update player + } + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/PlayerDataStore.java b/core/src/main/java/net/artelnatif/nicko/storage/PlayerDataStore.java new file mode 100644 index 0000000..c3f4ea3 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/PlayerDataStore.java @@ -0,0 +1,69 @@ +package net.artelnatif.nicko.storage; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.NickoProfile; +import net.artelnatif.nicko.mojang.MojangUtils; +import net.artelnatif.nicko.storage.json.JSONStorage; +import net.artelnatif.nicko.storage.sql.SQLStorage; +import org.bukkit.entity.Player; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Optional; +import java.util.UUID; + +public class PlayerDataStore { + private final Storage storage; + + public PlayerDataStore(NickoBukkit instance) { + this.storage = instance.getNickoConfig().isLocalStorage() ? new JSONStorage() : new SQLStorage(instance); + } + + public static final HashMap PROFILES = new HashMap<>(); + + public Optional getData(UUID uuid) { + if(storage.isError()) { + return Optional.empty(); + } + + if (PROFILES.containsKey(uuid)) { + return Optional.of(PROFILES.get(uuid)); + } else if (storage.isStored(uuid)) { + Optional retrievedProfile = storage.retrieve(uuid); + retrievedProfile.ifPresent(profile -> PROFILES.put(uuid, profile)); + return retrievedProfile; + } else { + return Optional.empty(); + } + } + + public Optional getOfflineData(String name) { + if(storage.isError()) { + return Optional.empty(); + } + + try { + final Optional uuidTrimmed = NickoBukkit.getInstance().getMojangAPI().getUUID(name); + if (uuidTrimmed.isPresent()) { + final UUID uuid = MojangUtils.fromTrimmed(uuidTrimmed.get()); + return getData(uuid); + } + return Optional.empty(); + } catch (IOException e) { + return Optional.empty(); + } + } + + public void saveData(Player player) { + if(storage.isError()) { + return; + } + + storage.store(player.getUniqueId(), PROFILES.get(player.getUniqueId())); + PROFILES.remove(player.getUniqueId()); + } + + public Storage getStorage() { + return storage; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/Storage.java b/core/src/main/java/net/artelnatif/nicko/storage/Storage.java new file mode 100644 index 0000000..77cd9b4 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/Storage.java @@ -0,0 +1,26 @@ +package net.artelnatif.nicko.storage; + +import net.artelnatif.nicko.disguise.NickoProfile; + +import java.util.Optional; +import java.util.UUID; + +public abstract class Storage { + private boolean error = false; + + public abstract StorageProvider getProvider(); + + public abstract void store(UUID uuid, NickoProfile profile); + + public abstract boolean isStored(UUID uuid); + + public abstract Optional retrieve(UUID uuid); + + public boolean isError() { + return error; + } + + public void setError(boolean error) { + this.error = error; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/StorageProvider.java b/core/src/main/java/net/artelnatif/nicko/storage/StorageProvider.java new file mode 100644 index 0000000..41b66de --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/StorageProvider.java @@ -0,0 +1,7 @@ +package net.artelnatif.nicko.storage; + +public interface StorageProvider { + boolean init(); + + boolean close(); +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorage.java b/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorage.java new file mode 100644 index 0000000..56ec416 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorage.java @@ -0,0 +1,70 @@ +package net.artelnatif.nicko.storage.json; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.NickoProfile; +import net.artelnatif.nicko.storage.Storage; +import net.artelnatif.nicko.storage.StorageProvider; + +import java.io.*; +import java.util.Optional; +import java.util.UUID; + +public class JSONStorage extends Storage { + final Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); + final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/"); + + @Override + public StorageProvider getProvider() { return new JSONStorageProvider(directory); } + + @Override + public void store(UUID uuid, NickoProfile profile) { + final String profileToJson = gson.toJson(profile); + final File file = new File(directory, uuid.toString() + ".json"); + + try { + if (checkFileExists(file)) { + try (FileWriter fileWriter = new FileWriter(file)) { + try (BufferedWriter writer = new BufferedWriter(fileWriter)) { + writer.write(profileToJson); + } + } catch (IOException e) { + System.out.println("Could not write to file."); + throw new RuntimeException(e); + } + } + } catch (IOException e) { + System.out.println("Could not create file."); + throw new RuntimeException(e); + } + } + + @Override + public boolean isStored(UUID uuid) { + final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/"); + final File file = new File(directory, uuid.toString() + ".json"); + return file.exists(); + } + + @Override + public Optional retrieve(UUID uuid) { + final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/"); + final File file = new File(directory, uuid.toString() + ".json"); + try (FileReader fileReader = new FileReader(file)) { + try (BufferedReader reader = new BufferedReader(fileReader)) { + NickoProfile value = gson.fromJson(reader, NickoProfile.class); + return Optional.of(value); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private boolean checkFileExists(File file) throws IOException { + if (!file.exists()) { + return file.createNewFile(); + } + return true; + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorageProvider.java b/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorageProvider.java new file mode 100644 index 0000000..ac2be77 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorageProvider.java @@ -0,0 +1,22 @@ +package net.artelnatif.nicko.storage.json; + +import net.artelnatif.nicko.storage.StorageProvider; + +import java.io.File; + +public class JSONStorageProvider implements StorageProvider { + private final File directory; + + public JSONStorageProvider(File directory) { + this.directory = directory; + } + + @Override + public boolean init() + { + return directory.exists() || directory.mkdirs(); + } + + @Override + public boolean close() { return true; } +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorage.java b/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorage.java new file mode 100644 index 0000000..70e80b1 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorage.java @@ -0,0 +1,36 @@ +package net.artelnatif.nicko.storage.sql; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.NickoProfile; +import net.artelnatif.nicko.storage.Storage; +import net.artelnatif.nicko.storage.StorageProvider; + +import java.util.Optional; +import java.util.UUID; + +public class SQLStorage extends Storage { + private final NickoBukkit instance; + + public SQLStorage(NickoBukkit instance) { + this.instance = instance; + } + + @Override + public StorageProvider getProvider() { + return new SQLStorageProvider(instance); + } + + @Override + public void store(UUID uuid, NickoProfile profile) { + } + + @Override + public boolean isStored(UUID uuid) { + return false; + } + + @Override + public Optional retrieve(UUID uuid) { + return Optional.empty(); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorageProvider.java b/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorageProvider.java new file mode 100644 index 0000000..98b781f --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorageProvider.java @@ -0,0 +1,39 @@ +package net.artelnatif.nicko.storage.sql; + +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.config.NickoConfiguration; +import net.artelnatif.nicko.storage.StorageProvider; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SQLStorageProvider implements StorageProvider { + private final NickoBukkit instance; + private Connection connection; + + public SQLStorageProvider(NickoBukkit instance) { + this.instance = instance; + } + + @Override + public boolean init() { + try { + final NickoConfiguration config = instance.getNickoConfig(); + connection = DriverManager.getConnection("jdbc://" + config.getStorageAddress(), config.getStorageUsername(), config.getStoragePassword()); + return !connection.isClosed() && connection != null; + } catch (SQLException e) { + return false; + } + } + + @Override + public boolean close() { + try { + connection.close(); + return connection.isClosed(); + } catch (SQLException e) { + return false; + } + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/utils/PlayerUtils.java b/core/src/main/java/net/artelnatif/nicko/utils/PlayerUtils.java new file mode 100644 index 0000000..4c646e5 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/utils/PlayerUtils.java @@ -0,0 +1,9 @@ +package net.artelnatif.nicko.utils; + +import org.bukkit.entity.Player; + +public class PlayerUtils { + public static boolean isPlayerOffline(Player player) { + return player == null || !player.isOnline(); + } +} diff --git a/core/src/main/java/net/artelnatif/nicko/utils/ServerUtils.java b/core/src/main/java/net/artelnatif/nicko/utils/ServerUtils.java new file mode 100644 index 0000000..25c2268 --- /dev/null +++ b/core/src/main/java/net/artelnatif/nicko/utils/ServerUtils.java @@ -0,0 +1,22 @@ +package net.artelnatif.nicko.utils; + +import net.artelnatif.nicko.NickoBukkit; +import org.bukkit.Server; +import org.bukkit.configuration.file.YamlConfiguration; + +public class ServerUtils { + public static boolean checkBungeeCordHook() { + final NickoBukkit instance = NickoBukkit.getInstance(); + final Server server = instance.getServer(); + final YamlConfiguration config = server.spigot().getConfig(); + if (!config.getConfigurationSection("settings").getBoolean("settings.bungeecord")) { + instance.getLogger().severe("Hummm. You have enabled BungeeCord support inside Nicko,"); + instance.getLogger().severe("but it seems that your server is not hooked to your BungeeCord instance."); + instance.getLogger().severe("If the server is already hooked to BungeeCord, please enable it into your spigot.yml aswell."); + instance.getLogger().severe("The plugin will not continue."); + instance.getServer().getPluginManager().disablePlugin(instance); + return false; + } + return true; + } +} diff --git a/core/src/main/resources/bungee.yml b/core/src/main/resources/bungee.yml new file mode 100644 index 0000000..0902daf --- /dev/null +++ b/core/src/main/resources/bungee.yml @@ -0,0 +1,4 @@ +name: ${project.parent.name} +main: net.artelnatif.nicko.bungee.NickoBungee +version: ${project.version} +author: Aro diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml new file mode 100644 index 0000000..584532e --- /dev/null +++ b/core/src/main/resources/config.yml @@ -0,0 +1,28 @@ +# Nicko ${project.version} - Config: + +prefix: "§8[§6Nicko§8] " + +bungeecord: + # Enables Bungeecord support, switching through servers will keep player's skins. + enabled: false + redis: + username: "" + password: "" + # Time To Live, the time the data will be stored on a player-by-player basis. + ttl: -1 + + +disguisekit: + # The rainbow header text in the book. + header: "Nicko's Disguise Kit" + +storage: + # Indicates wherever the data will be stored + # locally through a .json file or a (My)SQL database. + local: true + # SQL database's address + address: "localhost" + # SQL database's username. + username: "" + # SQL database's password. + password: "" \ No newline at end of file diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml new file mode 100644 index 0000000..0730592 --- /dev/null +++ b/core/src/main/resources/plugin.yml @@ -0,0 +1,7 @@ +name: ${project.parent.name} +main: net.artelnatif.nicko.NickoBukkit +version: ${project.version} +author: Aro +api-version: 1.18 +commands: + nicko: diff --git a/core/src/test/java/net/artelnatif/nicko/test/MojangAPITest.java b/core/src/test/java/net/artelnatif/nicko/test/MojangAPITest.java new file mode 100644 index 0000000..0fd8a47 --- /dev/null +++ b/core/src/test/java/net/artelnatif/nicko/test/MojangAPITest.java @@ -0,0 +1,87 @@ +package net.artelnatif.nicko.test; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.artelnatif.nicko.mojang.MojangAPI; +import net.artelnatif.nicko.mojang.MojangSkin; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import javax.net.ssl.HttpsURLConnection; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +public class MojangAPITest { + public static final String NAME = "Notch"; + public static final String URL_NAME = "https://api.mojang.com/users/profiles/minecraft/{name}"; + public static final String URL_SKIN = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false"; + + public static JsonObject object = null; + + @Test + @DisplayName("MojangAPI - GET - Name") + public void testGetMojangAPIName() throws IOException { + final URL url = new URL(URL_NAME.replace("{name}", NAME)); + final HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); + urlConnection.setRequestMethod("GET"); + urlConnection.setDoOutput(true); + + //DataOutputStream output = new DataOutputStream(urlConnection.getOutputStream()); + //output.writeBytes(); + //output.flush(); + //output.close(); + + final BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + final StringBuilder response = new StringBuilder(); + String inputLine; + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + object = JsonParser.parseString(response.toString()).getAsJsonObject(); + Assertions.assertEquals(NAME, object.get("name").getAsString()); + } + + @Test + @DisplayName("MojangAPI - GET - Skin") + public void testGetMojangAPISkin() throws IOException { + final URL url = new URL(URL_SKIN.replace("{uuid}", object.get("id").getAsString().replaceAll("-", ""))); + final HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); + urlConnection.setRequestMethod("GET"); + urlConnection.setDoOutput(true); + + final BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + final StringBuilder response = new StringBuilder(); + String inputLine; + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + System.out.println(response); + } + + @Test + @DisplayName("MojangAPI - New Methods") + public void testNewMojangAPIMethods() throws IOException { + final MojangAPI mojangAPI = new MojangAPI(); + final Optional uuid = mojangAPI.getUUID(NAME); + Assertions.assertTrue(uuid.isPresent()); + + final Optional skin; + try { + skin = mojangAPI.getSkin(uuid.get()); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + + Assertions.assertTrue(skin.isPresent()); + Assertions.assertDoesNotThrow(this::testNewMojangAPIMethods); + } +} diff --git a/core/target/classes/bungee.yml b/core/target/classes/bungee.yml new file mode 100644 index 0000000..52d8a71 --- /dev/null +++ b/core/target/classes/bungee.yml @@ -0,0 +1,4 @@ +name: Nicko +main: net.artelnatif.nicko.bungee.NickoBungee +version: 1.0-SNAPSHOT +author: Aro diff --git a/core/target/classes/com/yoshiplex/rainbow/RainbowText.class b/core/target/classes/com/yoshiplex/rainbow/RainbowText.class new file mode 100644 index 0000000..dfebbf4 Binary files /dev/null and b/core/target/classes/com/yoshiplex/rainbow/RainbowText.class differ diff --git a/core/target/classes/config.yml b/core/target/classes/config.yml new file mode 100644 index 0000000..b6145ab --- /dev/null +++ b/core/target/classes/config.yml @@ -0,0 +1,26 @@ +# Nicko 1.0-SNAPSHOT - Config: + +prefix: "§8[§6Nicko§8] " + +bungeecord: + redis: + username: "" + password: "" + # Time To Live, the time the data will be stored on a player-by-player basis. + ttl: -1 + + +disguisekit: + # The rainbow header text in the book. + header: "Nicko's Disguise Kit" + +storage: + # Indicates wherever the data will be stored + # locally through a .json file or a (My)SQL database. + local: true + # SQL database's address + address: "localhost" + # SQL database's username. + username: "" + # SQL database's password. + password: "" \ No newline at end of file diff --git a/core/target/classes/net/artelnatif/nicko/NickoBukkit.class b/core/target/classes/net/artelnatif/nicko/NickoBukkit.class new file mode 100644 index 0000000..4b1ff2d Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/NickoBukkit.class differ diff --git a/core/target/classes/net/artelnatif/nicko/anvil/AnvilManager.class b/core/target/classes/net/artelnatif/nicko/anvil/AnvilManager.class new file mode 100644 index 0000000..fe1cfdc Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/anvil/AnvilManager.class differ diff --git a/core/target/classes/net/artelnatif/nicko/bungee/NickoBungee.class b/core/target/classes/net/artelnatif/nicko/bungee/NickoBungee.class new file mode 100644 index 0000000..818fc6a Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/bungee/NickoBungee.class differ diff --git a/core/target/classes/net/artelnatif/nicko/bungee/event/ServerSwitchListener.class b/core/target/classes/net/artelnatif/nicko/bungee/event/ServerSwitchListener.class new file mode 100644 index 0000000..b4fe582 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/bungee/event/ServerSwitchListener.class differ diff --git a/core/target/classes/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.class b/core/target/classes/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.class new file mode 100644 index 0000000..ada05d5 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/NickoCommand.class b/core/target/classes/net/artelnatif/nicko/command/NickoCommand.class new file mode 100644 index 0000000..2e3e80a Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/NickoCommand.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/NickoPermissions$Player$Command.class b/core/target/classes/net/artelnatif/nicko/command/NickoPermissions$Player$Command.class new file mode 100644 index 0000000..a4000ac Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/NickoPermissions$Player$Command.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/NickoPermissions$Player.class b/core/target/classes/net/artelnatif/nicko/command/NickoPermissions$Player.class new file mode 100644 index 0000000..da08338 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/NickoPermissions$Player.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/NickoPermissions.class b/core/target/classes/net/artelnatif/nicko/command/NickoPermissions.class new file mode 100644 index 0000000..e4c29d9 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/NickoPermissions.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/NickoTabCompleter.class b/core/target/classes/net/artelnatif/nicko/command/NickoTabCompleter.class new file mode 100644 index 0000000..17a5aaa Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/NickoTabCompleter.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.class b/core/target/classes/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.class new file mode 100644 index 0000000..da74b44 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.class b/core/target/classes/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.class new file mode 100644 index 0000000..4595379 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.class b/core/target/classes/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.class new file mode 100644 index 0000000..e8f2501 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/sub/NickoGUISubCmd.class b/core/target/classes/net/artelnatif/nicko/command/sub/NickoGUISubCmd.class new file mode 100644 index 0000000..1bffbe6 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/sub/NickoGUISubCmd.class differ diff --git a/core/target/classes/net/artelnatif/nicko/command/sub/NickoSubCmd.class b/core/target/classes/net/artelnatif/nicko/command/sub/NickoSubCmd.class new file mode 100644 index 0000000..aa24195 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/command/sub/NickoSubCmd.class differ diff --git a/core/target/classes/net/artelnatif/nicko/config/NickoConfiguration.class b/core/target/classes/net/artelnatif/nicko/config/NickoConfiguration.class new file mode 100644 index 0000000..fe60656 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/config/NickoConfiguration.class differ diff --git a/core/target/classes/net/artelnatif/nicko/disguise/AppearanceManager.class b/core/target/classes/net/artelnatif/nicko/disguise/AppearanceManager.class new file mode 100644 index 0000000..a4e20ea Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/disguise/AppearanceManager.class differ diff --git a/core/target/classes/net/artelnatif/nicko/disguise/NickoProfile.class b/core/target/classes/net/artelnatif/nicko/disguise/NickoProfile.class new file mode 100644 index 0000000..9a36ceb Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/disguise/NickoProfile.class differ diff --git a/core/target/classes/net/artelnatif/nicko/event/PlayerJoinListener.class b/core/target/classes/net/artelnatif/nicko/event/PlayerJoinListener.class new file mode 100644 index 0000000..d256542 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/event/PlayerJoinListener.class differ diff --git a/core/target/classes/net/artelnatif/nicko/event/PlayerQuitListener.class b/core/target/classes/net/artelnatif/nicko/event/PlayerQuitListener.class new file mode 100644 index 0000000..4fc3c08 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/event/PlayerQuitListener.class differ diff --git a/core/target/classes/net/artelnatif/nicko/i18n/I18N$Message$Command.class b/core/target/classes/net/artelnatif/nicko/i18n/I18N$Message$Command.class new file mode 100644 index 0000000..c27e011 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/i18n/I18N$Message$Command.class differ diff --git a/core/target/classes/net/artelnatif/nicko/i18n/I18N$Message.class b/core/target/classes/net/artelnatif/nicko/i18n/I18N$Message.class new file mode 100644 index 0000000..5aaa9d1 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/i18n/I18N$Message.class differ diff --git a/core/target/classes/net/artelnatif/nicko/i18n/I18N.class b/core/target/classes/net/artelnatif/nicko/i18n/I18N.class new file mode 100644 index 0000000..6457554 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/i18n/I18N.class differ diff --git a/core/target/classes/net/artelnatif/nicko/impl/Internals.class b/core/target/classes/net/artelnatif/nicko/impl/Internals.class new file mode 100644 index 0000000..2b8f0a3 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/impl/Internals.class differ diff --git a/core/target/classes/net/artelnatif/nicko/impl/InternalsProvider.class b/core/target/classes/net/artelnatif/nicko/impl/InternalsProvider.class new file mode 100644 index 0000000..292301c Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/impl/InternalsProvider.class differ diff --git a/core/target/classes/net/artelnatif/nicko/mojang/MojangAPI$1.class b/core/target/classes/net/artelnatif/nicko/mojang/MojangAPI$1.class new file mode 100644 index 0000000..77d3416 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/mojang/MojangAPI$1.class differ diff --git a/core/target/classes/net/artelnatif/nicko/mojang/MojangAPI.class b/core/target/classes/net/artelnatif/nicko/mojang/MojangAPI.class new file mode 100644 index 0000000..7715ee2 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/mojang/MojangAPI.class differ diff --git a/core/target/classes/net/artelnatif/nicko/mojang/MojangSkin.class b/core/target/classes/net/artelnatif/nicko/mojang/MojangSkin.class new file mode 100644 index 0000000..8c9d2db Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/mojang/MojangSkin.class differ diff --git a/core/target/classes/net/artelnatif/nicko/mojang/MojangUtils.class b/core/target/classes/net/artelnatif/nicko/mojang/MojangUtils.class new file mode 100644 index 0000000..e65d782 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/mojang/MojangUtils.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/PlayerDataStore.class b/core/target/classes/net/artelnatif/nicko/storage/PlayerDataStore.class new file mode 100644 index 0000000..1c775f3 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/PlayerDataStore.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/Storage.class b/core/target/classes/net/artelnatif/nicko/storage/Storage.class new file mode 100644 index 0000000..465ff80 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/Storage.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/StorageProvider.class b/core/target/classes/net/artelnatif/nicko/storage/StorageProvider.class new file mode 100644 index 0000000..1ee20f8 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/StorageProvider.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/json/JSONStorage.class b/core/target/classes/net/artelnatif/nicko/storage/json/JSONStorage.class new file mode 100644 index 0000000..d4f7743 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/json/JSONStorage.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/json/JSONStorageProvider.class b/core/target/classes/net/artelnatif/nicko/storage/json/JSONStorageProvider.class new file mode 100644 index 0000000..97c63e9 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/json/JSONStorageProvider.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/sql/SQLStorage.class b/core/target/classes/net/artelnatif/nicko/storage/sql/SQLStorage.class new file mode 100644 index 0000000..d65b131 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/sql/SQLStorage.class differ diff --git a/core/target/classes/net/artelnatif/nicko/storage/sql/SQLStorageProvider.class b/core/target/classes/net/artelnatif/nicko/storage/sql/SQLStorageProvider.class new file mode 100644 index 0000000..a956c24 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/storage/sql/SQLStorageProvider.class differ diff --git a/core/target/classes/net/artelnatif/nicko/utils/PlayerUtils.class b/core/target/classes/net/artelnatif/nicko/utils/PlayerUtils.class new file mode 100644 index 0000000..f3d4790 Binary files /dev/null and b/core/target/classes/net/artelnatif/nicko/utils/PlayerUtils.class differ diff --git a/core/target/classes/plugin.yml b/core/target/classes/plugin.yml new file mode 100644 index 0000000..a02a10f --- /dev/null +++ b/core/target/classes/plugin.yml @@ -0,0 +1,7 @@ +name: Nicko +main: net.artelnatif.nicko.NickoBukkit +version: 1.0-SNAPSHOT +author: Aro +api-version: 1.18 +commands: + nicko: diff --git a/core/target/maven-archiver/pom.properties b/core/target/maven-archiver/pom.properties new file mode 100644 index 0000000..b6edbe6 --- /dev/null +++ b/core/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Thu Oct 13 10:30:55 CEST 2022 +groupId=net.artelnatif +artifactId=nicko-core +version=1.0-SNAPSHOT diff --git a/core/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/core/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..2b7a49e --- /dev/null +++ b/core/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,38 @@ +net/artelnatif/nicko/disguise/AppearanceManager.class +net/artelnatif/nicko/mojang/MojangSkin.class +net/artelnatif/nicko/command/NickoPermissions$Player.class +net/artelnatif/nicko/impl/Internals.class +net/artelnatif/nicko/anvil/AnvilManager.class +net/artelnatif/nicko/bungee/event/ServerSwitchListener.class +com/yoshiplex/rainbow/RainbowText.class +net/artelnatif/nicko/storage/PlayerDataStore.class +net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.class +net/artelnatif/nicko/mojang/MojangAPI$1.class +net/artelnatif/nicko/i18n/I18N$Message$Command.class +net/artelnatif/nicko/mojang/MojangAPI.class +net/artelnatif/nicko/command/NickoTabCompleter.class +net/artelnatif/nicko/i18n/I18N$Message.class +net/artelnatif/nicko/event/PlayerJoinListener.class +net/artelnatif/nicko/command/NickoCommand.class +net/artelnatif/nicko/disguise/NickoProfile.class +net/artelnatif/nicko/event/PlayerQuitListener.class +net/artelnatif/nicko/impl/InternalsProvider.class +net/artelnatif/nicko/config/NickoConfiguration.class +net/artelnatif/nicko/storage/json/JSONStorage.class +net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.class +net/artelnatif/nicko/storage/sql/SQLStorage.class +net/artelnatif/nicko/mojang/MojangUtils.class +net/artelnatif/nicko/command/NickoPermissions$Player$Command.class +net/artelnatif/nicko/utils/PlayerUtils.class +net/artelnatif/nicko/i18n/I18N.class +net/artelnatif/nicko/storage/sql/SQLStorageProvider.class +net/artelnatif/nicko/storage/StorageProvider.class +net/artelnatif/nicko/command/sub/NickoGUISubCmd.class +net/artelnatif/nicko/command/sub/NickoCheckSubCmd.class +net/artelnatif/nicko/bungee/NickoBungee.class +net/artelnatif/nicko/command/sub/NickoSubCmd.class +net/artelnatif/nicko/command/NickoPermissions.class +net/artelnatif/nicko/command/sub/NickoDebugSubCmd.class +net/artelnatif/nicko/storage/Storage.class +net/artelnatif/nicko/NickoBukkit.class +net/artelnatif/nicko/storage/json/JSONStorageProvider.class diff --git a/core/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/core/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..6021fe6 --- /dev/null +++ b/core/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,33 @@ +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/NickoPermissions.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorage.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/event/PlayerQuitListener.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/disguise/NickoProfile.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/NickoTabCompleter.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/json/JSONStorageProvider.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/com/yoshiplex/rainbow/RainbowText.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/impl/InternalsProvider.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/bungee/event/ServerSwitchListener.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/sub/NickoCheckSubCmd.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/disguise/AppearanceManager.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/StorageProvider.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/NickoBukkit.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/Storage.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/bungee/NickoBungee.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/bungee/pluginchannel/PluginChannelHelper.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/PlayerDataStore.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/utils/PlayerUtils.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorageProvider.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/event/PlayerJoinListener.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/config/NickoConfiguration.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDebugSubCmd.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/NickoCommand.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/sub/NickoSubCmd.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/i18n/I18N.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/impl/Internals.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/sub/NickoDisguiseSubCmd.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/storage/sql/SQLStorage.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/mojang/MojangSkin.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/command/sub/NickoGUISubCmd.java +/home/aro/IdeaProjects/Nicko/core/src/main/java/net/artelnatif/nicko/mojang/MojangUtils.java diff --git a/core/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/core/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst new file mode 100644 index 0000000..10b8fe5 --- /dev/null +++ b/core/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst @@ -0,0 +1 @@ +net/artelnatif/nicko/test/MojangAPITest.class diff --git a/core/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/core/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 0000000..78a145a --- /dev/null +++ b/core/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst @@ -0,0 +1 @@ +/home/aro/IdeaProjects/Nicko/core/src/test/java/net/artelnatif/nicko/test/MojangAPITest.java diff --git a/core/target/nicko-core-1.0-SNAPSHOT.jar b/core/target/nicko-core-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..0edbadc Binary files /dev/null and b/core/target/nicko-core-1.0-SNAPSHOT.jar differ diff --git a/core/target/original-nicko-core-1.0-SNAPSHOT.jar b/core/target/original-nicko-core-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..f73c326 Binary files /dev/null and b/core/target/original-nicko-core-1.0-SNAPSHOT.jar differ diff --git a/core/target/test-classes/net/artelnatif/nicko/test/MojangAPITest.class b/core/target/test-classes/net/artelnatif/nicko/test/MojangAPITest.class new file mode 100644 index 0000000..322b3f9 Binary files /dev/null and b/core/target/test-classes/net/artelnatif/nicko/test/MojangAPITest.class differ diff --git a/dist/dependency-reduced-pom.xml b/dist/dependency-reduced-pom.xml new file mode 100644 index 0000000..dd3ab08 --- /dev/null +++ b/dist/dependency-reduced-pom.xml @@ -0,0 +1,36 @@ + + + + nicko-parent + net.artelnatif + 1.0-SNAPSHOT + + 4.0.0 + dist + 1.0-SNAPSHOT + + ../target + nicko-${project.version} + + + maven-shade-plugin + 3.3.1-SNAPSHOT + + + package + + shade + + + + + net.artelnatif:nicko-* + + + + + + + + + diff --git a/dist/pom.xml b/dist/pom.xml new file mode 100644 index 0000000..f090d9e --- /dev/null +++ b/dist/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + + net.artelnatif + nicko-parent + 1.0-SNAPSHOT + + + dist + 1.0-SNAPSHOT + + + ../target + nicko-${project.version} + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.1-SNAPSHOT + + + package + + shade + + + + + net.artelnatif:nicko-* + + + + + + + + + + + + net.artelnatif + nicko-core + ${project.parent.version} + + + net.artelnatif + nicko-v1_18_R2 + ${project.parent.version} + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..08ef469 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + net.artelnatif + nicko-parent + 1.0-SNAPSHOT + Nicko + pom + + + core + dist + v1_18_R2 + v1_18_R1 + + + + 17 + 17 + + \ No newline at end of file diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..3d5d6e9 --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Thu Oct 13 10:30:56 CEST 2022 +groupId=net.artelnatif +artifactId=dist +version=1.0-SNAPSHOT diff --git a/target/original-nicko-1.0-SNAPSHOT.jar b/target/original-nicko-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..74679f2 Binary files /dev/null and b/target/original-nicko-1.0-SNAPSHOT.jar differ diff --git a/v1_18_R1/pom.xml b/v1_18_R1/pom.xml new file mode 100644 index 0000000..b97ff0c --- /dev/null +++ b/v1_18_R1/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + net.artelnatif + nicko-parent + 1.0-SNAPSHOT + + + nicko-v1_18_R1 + 1.0-SNAPSHOT + + + + org.spigotmc + spigot + 1.18.1-R0.1-SNAPSHOT + provided + + + net.artelnatif + nicko-core + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/v1_18_R1/src/main/java/net/artelnatif/impl/v1_18_R1.java b/v1_18_R1/src/main/java/net/artelnatif/impl/v1_18_R1.java new file mode 100644 index 0000000..1bd0558 --- /dev/null +++ b/v1_18_R1/src/main/java/net/artelnatif/impl/v1_18_R1.java @@ -0,0 +1,132 @@ +package net.artelnatif.impl; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.NickoProfile; +import net.artelnatif.nicko.impl.Internals; +import net.artelnatif.nicko.mojang.MojangSkin; +import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.DataWatcher; +import net.minecraft.network.syncher.DataWatcherObject; +import net.minecraft.network.syncher.DataWatcherRegistry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.level.EnumGamemode; +import net.minecraft.world.level.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; + +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +public class v1_18_R1 implements Internals { + @Override + public void updateSelf(Player player) { + final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + final ResourceKey levelResourceKey = entityPlayer.x().aa(); + final CraftWorld world = entityPlayer.W().getWorld(); + // again, wtf is that + // f*ck obfuscation + final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(entityPlayer.W().q_(), + levelResourceKey, world.getSeed(), + entityPlayer.d.b(), entityPlayer.d.c(), + false, + false, + false); + + final boolean wasFlying = player.isFlying(); + final ItemStack itemOnCursor = player.getItemOnCursor(); + entityPlayer.b.a(respawn); + player.setFlying(wasFlying); + player.setItemOnCursor(itemOnCursor); + player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); + player.updateInventory(); + } + + @Override + public void updateOthers(Player player) { + final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId()); + final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer); + + /* + BIT MASKS: + 0x01 Cape enabled + 0x02 Jacket enabled + 0x04 Left sleeve enabled + 0x08 Right sleeve enabled + 0x10 Left pants leg enabled + 0x20 Right pants leg enabled + 0x40 Hat enabled + */ + final DataWatcher dataWatcher = entityPlayer.ai(); + final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a); + dataWatcher.b(displayedSkinPartDataWatcher, (byte) 0x7f); // 127, all masks combined + final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true); + + Bukkit.getOnlinePlayers().forEach(online -> { + EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle(); + if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) { + onlineEntityPlayer.b.a(destroy); + onlineEntityPlayer.b.a(spawn); + onlineEntityPlayer.b.a(entityMetadata); + } + }); + } + + @Override + public void updateProfile(Player player, NickoProfile profile, boolean skinChange) { + final CraftPlayer craftPlayer = (CraftPlayer) player; + final EntityPlayer entityPlayer = craftPlayer.getHandle(); + Optional skin; + + final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer); + entityPlayer.b.a(remove); + + final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a); + final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profile.getName()); + + if (skinChange) { + try { + final Optional uuid = NickoBukkit.getInstance().getMojangAPI().getUUID(profile.getSkin()); + if (uuid.isPresent()) { + skin = NickoBukkit.getInstance().getMojangAPI().getSkin(uuid.get()); + if (skin.isPresent()) { + final PropertyMap properties = gameProfile.getProperties(); + properties.put("textures", new Property("textures", skin.get().value(), skin.get().signature())); + updateSelf(player); + } else { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cFailed to get skin from Mojang."); + } + } else { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cFailed to get username from Mojang. Does the user exists?"); + } + } catch (IOException e) { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cAn error occurred."); + } catch (ExecutionException e) { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cFailed to get skin from cache."); + } + } + + add.b().clear(); + add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile, + player.getPing(), + EnumGamemode.a(player.getGameMode().ordinal()), IChatBaseComponent.a(profile.getName()))); + entityPlayer.b.a(add); + + Bukkit.getOnlinePlayers().forEach(online -> { + EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle(); + onlineEntityPlayer.b.a(remove); + onlineEntityPlayer.b.a(add); + }); + updateOthers(player); + } +} diff --git a/v1_18_R1/target/classes/net/artelnatif/impl/v1_18_R1.class b/v1_18_R1/target/classes/net/artelnatif/impl/v1_18_R1.class new file mode 100644 index 0000000..e354efa Binary files /dev/null and b/v1_18_R1/target/classes/net/artelnatif/impl/v1_18_R1.class differ diff --git a/v1_18_R1/target/maven-archiver/pom.properties b/v1_18_R1/target/maven-archiver/pom.properties new file mode 100644 index 0000000..11adcc8 --- /dev/null +++ b/v1_18_R1/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Thu Oct 13 10:30:56 CEST 2022 +groupId=net.artelnatif +artifactId=nicko-v1_18_R1 +version=1.0-SNAPSHOT diff --git a/v1_18_R1/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/v1_18_R1/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..27ed777 --- /dev/null +++ b/v1_18_R1/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +net/artelnatif/impl/v1_18_R1.class diff --git a/v1_18_R1/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/v1_18_R1/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..86ffd05 --- /dev/null +++ b/v1_18_R1/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1 @@ +/home/aro/IdeaProjects/Nicko/v1_18_R1/src/main/java/net/artelnatif/impl/v1_18_R1.java diff --git a/v1_18_R1/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/v1_18_R1/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 0000000..e69de29 diff --git a/v1_18_R1/target/nicko-v1_18_R1-1.0-SNAPSHOT.jar b/v1_18_R1/target/nicko-v1_18_R1-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..1f31138 Binary files /dev/null and b/v1_18_R1/target/nicko-v1_18_R1-1.0-SNAPSHOT.jar differ diff --git a/v1_18_R2/pom.xml b/v1_18_R2/pom.xml new file mode 100644 index 0000000..2d8d8f7 --- /dev/null +++ b/v1_18_R2/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + net.artelnatif + nicko-parent + 1.0-SNAPSHOT + + + nicko-v1_18_R2 + 1.0-SNAPSHOT + + + + org.spigotmc + spigot + 1.18.2-R0.1-SNAPSHOT + provided + + + net.artelnatif + nicko-core + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java b/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java new file mode 100644 index 0000000..6775f40 --- /dev/null +++ b/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java @@ -0,0 +1,131 @@ +package net.artelnatif.nicko.impl; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import net.artelnatif.nicko.NickoBukkit; +import net.artelnatif.nicko.disguise.NickoProfile; +import net.artelnatif.nicko.mojang.MojangSkin; +import net.minecraft.core.Holder; +import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.DataWatcher; +import net.minecraft.network.syncher.DataWatcherObject; +import net.minecraft.network.syncher.DataWatcherRegistry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.world.level.EnumGamemode; +import net.minecraft.world.level.World; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; + +import java.io.IOException; +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +public class v1_18_R2 implements Internals { + @Override + public void updateSelf(Player player) { + final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + final ResourceKey levelResourceKey = entityPlayer.x().aa(); + final CraftWorld world = entityPlayer.s.getWorld(); + // wtf is that ? + final PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(Holder.a(entityPlayer.s.q_()), + levelResourceKey, world.getSeed(), + entityPlayer.d.b(), entityPlayer.d.c(), + false, + false, + false); + + final boolean wasFlying = player.isFlying(); + final ItemStack itemOnCursor = player.getItemOnCursor(); + entityPlayer.b.a(respawn); + player.setFlying(wasFlying); + player.setItemOnCursor(itemOnCursor); + player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); + player.updateInventory(); + } + + @Override + public void updateOthers(Player player) { + final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + final PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(entityPlayer.getBukkitEntity().getEntityId()); + final PacketPlayOutNamedEntitySpawn spawn = new PacketPlayOutNamedEntitySpawn(entityPlayer); + + /* + BIT MASKS: + 0x01 Cape enabled + 0x02 Jacket enabled + 0x04 Left sleeve enabled + 0x08 Right sleeve enabled + 0x10 Left pants leg enabled + 0x20 Right pants leg enabled + 0x40 Hat enabled + */ + final DataWatcher dataWatcher = entityPlayer.ai(); + final DataWatcherObject displayedSkinPartDataWatcher = new DataWatcherObject<>(17, DataWatcherRegistry.a); + dataWatcher.b(displayedSkinPartDataWatcher, (byte) 0x7f); // 127, all masks combined + final PacketPlayOutEntityMetadata entityMetadata = new PacketPlayOutEntityMetadata(entityPlayer.getBukkitEntity().getEntityId(), dataWatcher, true); + + Bukkit.getOnlinePlayers().forEach(online -> { + EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle(); + if (onlineEntityPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) { + onlineEntityPlayer.b.a(destroy); + onlineEntityPlayer.b.a(spawn); + onlineEntityPlayer.b.a(entityMetadata); + } + }); + } + + @Override + public void updateProfile(Player player, NickoProfile profile, boolean skinChange) { + final CraftPlayer craftPlayer = (CraftPlayer) player; + final EntityPlayer entityPlayer = craftPlayer.getHandle(); + Optional skin; + + final PacketPlayOutPlayerInfo remove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, entityPlayer); + entityPlayer.b.a(remove); + + final PacketPlayOutPlayerInfo add = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a); + final GameProfile gameProfile = new GameProfile(player.getUniqueId(), profile.getName()); + + if (skinChange) { + try { + final Optional uuid = NickoBukkit.getInstance().getMojangAPI().getUUID(profile.getSkin()); + if (uuid.isPresent()) { + skin = NickoBukkit.getInstance().getMojangAPI().getSkin(uuid.get()); + if (skin.isPresent()) { + final PropertyMap properties = gameProfile.getProperties(); + properties.put("textures", new Property("textures", skin.get().value(), skin.get().signature())); + updateSelf(player); + } else { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cFailed to get skin from Mojang."); + } + } else { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cFailed to get username from Mojang. Does the user exists?"); + } + } catch (IOException e) { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cAn error occurred."); + } catch (ExecutionException e) { + player.sendMessage(NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§cFailed to get skin from cache."); + } + } + + add.b().clear(); + add.b().add(new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile, + player.getPing(), + EnumGamemode.a(player.getGameMode().ordinal()), IChatBaseComponent.a(profile.getName()))); + entityPlayer.b.a(add); + + Bukkit.getOnlinePlayers().forEach(online -> { + EntityPlayer onlineEntityPlayer = ((CraftPlayer) online).getHandle(); + onlineEntityPlayer.b.a(remove); + onlineEntityPlayer.b.a(add); + }); + updateOthers(player); + } +} diff --git a/v1_18_R2/target/classes/net/artelnatif/nicko/impl/v1_18_R2.class b/v1_18_R2/target/classes/net/artelnatif/nicko/impl/v1_18_R2.class new file mode 100644 index 0000000..1c232b2 Binary files /dev/null and b/v1_18_R2/target/classes/net/artelnatif/nicko/impl/v1_18_R2.class differ diff --git a/v1_18_R2/target/maven-archiver/pom.properties b/v1_18_R2/target/maven-archiver/pom.properties new file mode 100644 index 0000000..a1410d5 --- /dev/null +++ b/v1_18_R2/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Thu Oct 13 10:30:56 CEST 2022 +groupId=net.artelnatif +artifactId=nicko-v1_18_R2 +version=1.0-SNAPSHOT diff --git a/v1_18_R2/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/v1_18_R2/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..3d6c76d --- /dev/null +++ b/v1_18_R2/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +net/artelnatif/nicko/impl/v1_18_R2.class diff --git a/v1_18_R2/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/v1_18_R2/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..54e9985 --- /dev/null +++ b/v1_18_R2/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1 @@ +/home/aro/IdeaProjects/Nicko/v1_18_R2/src/main/java/net/artelnatif/nicko/impl/v1_18_R2.java diff --git a/v1_18_R2/target/nicko-v1_18_R2-1.0-SNAPSHOT.jar b/v1_18_R2/target/nicko-v1_18_R2-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..22af3c8 Binary files /dev/null and b/v1_18_R2/target/nicko-v1_18_R2-1.0-SNAPSHOT.jar differ