diff --git a/Plugins/Mineplex.Bungee.Mineplexer/pom.xml b/Plugins/Mineplex.Bungee.Mineplexer/pom.xml index b32fcf94a..4b46f2b44 100644 --- a/Plugins/Mineplex.Bungee.Mineplexer/pom.xml +++ b/Plugins/Mineplex.Bungee.Mineplexer/pom.xml @@ -28,10 +28,6 @@ commons-codec commons-codec - - net.kencochrane.raven - raven - net.md-5 bungeecord-proxy diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java index e780804a7..91039533d 100644 --- a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/Mineplexer.java @@ -1,35 +1,16 @@ package mineplex.bungee; -import java.util.logging.Handler; -import java.util.logging.Level; import mineplex.bungee.lobbyBalancer.LobbyBalancer; import mineplex.bungee.motd.MotdManager; import mineplex.bungee.playerCount.PlayerCount; import mineplex.bungee.playerStats.PlayerStats; import mineplex.bungee.playerTracker.PlayerTracker; -import net.kencochrane.raven.DefaultRavenFactory; -import net.kencochrane.raven.dsn.Dsn; -import net.kencochrane.raven.jul.SentryHandler; import net.md_5.bungee.api.plugin.Plugin; public class Mineplexer extends Plugin { @Override public void onEnable() { - getProxy().getScheduler().runAsync(this, new Runnable() - { - @Override - public void run() - { - // Sentry setup - Handler sentry = new SentryHandler(new DefaultRavenFactory().createRavenInstance( - new Dsn("https://470f12378af3453ba089e0c0a0c9aae6:292516b722594784807aebb06db8ec38@app.getsentry.com/66323" - ))); - sentry.setLevel(Level.SEVERE); - getProxy().getLogger().addHandler(sentry); - } - }); - new MotdManager(this); new LobbyBalancer(this); new PlayerCount(this); diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiEndpoint.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiEndpoint.java index 06fdc0896..3b12c1d0b 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiEndpoint.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiEndpoint.java @@ -1,23 +1,30 @@ package mineplex.core.common.api; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; /** * @author Shaun Bennett */ public class ApiEndpoint { - private static final String API_HOST = "10.33.53.12"; -// private static final String API_HOST = "localhost"; -// private static final int API_PORT = 3000; - private static final int API_PORT = 7979; - private Gson _gson; private ApiWebCall _webCall; - public ApiEndpoint(String path, Gson gson) + public ApiEndpoint(ApiHost host, String path) { - String url = "http://" + API_HOST + ":" + API_PORT + path; + this(host, path, new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy()) + .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX").create()); + } + + public ApiEndpoint(ApiHost host, String path, Gson gson) + { + this(host.getHost(), host.getPort(), path, gson); + } + + public ApiEndpoint(String host, int port, String path, Gson gson) + { + String url = "http://" + host + ":" + port + path; _webCall = new ApiWebCall(url, gson); _gson = gson; } diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java new file mode 100644 index 000000000..93dbf761b --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/api/ApiHost.java @@ -0,0 +1,31 @@ +package mineplex.core.common.api; + +/** + * TODO: Store this in a file instead of being hardcoded + * + * @author Shaun Bennett + */ +public enum ApiHost +{ + AMPLIFIERS("10.33.53.12", 7979), + ANTISPAM("10.33.53.12", 8181); + + private String _host; + private int _port; + + ApiHost(String host, int port) + { + _host = host; + _port = port; + } + + public String getHost() + { + return _host; + } + + public int getPort() + { + return _port; + } +} diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/jsonchat/JsonMessage.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/jsonchat/JsonMessage.java index f4ce9532e..c32abd4a8 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/jsonchat/JsonMessage.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/jsonchat/JsonMessage.java @@ -108,7 +108,7 @@ public class JsonMessage public void sendToPlayer(Player player) { - UtilServer.getServer().dispatchCommand(UtilServer.getServer().getConsoleSender(), "tellraw " + player.getName() + " " + toString()); + ((CraftPlayer) player).getHandle().sendMessage(IChatBaseComponent.ChatSerializer.a(toString())); } /** diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java index 1612f92a0..333019f04 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java @@ -1,35 +1,58 @@ package mineplex.core.common.skin; +import java.lang.reflect.Field; import java.util.List; +import java.util.Map; +import java.util.UUID; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; -import org.bukkit.entity.Player; +import com.google.common.collect.Maps; +import com.mojang.authlib.minecraft.InsecureTextureException; +import com.mojang.authlib.minecraft.MinecraftProfileTexture; +import mineplex.core.common.util.UtilPlayer; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import net.minecraft.server.v1_8_R3.Item; -import net.minecraft.server.v1_8_R3.MinecraftKey; -import net.minecraft.server.v1_8_R3.NBTTagCompound; -import net.minecraft.server.v1_8_R3.NBTTagList; -import net.minecraft.server.v1_8_R3.NBTTagString; +import org.bukkit.inventory.meta.SkullMeta; public class SkinData { + private static final Field PROFILE_FIELD; + + static + { + try + { + PROFILE_FIELD = Class.forName("org.bukkit.craftbukkit.v1_8_R3.inventory.CraftMetaSkull").getDeclaredField("profile"); + PROFILE_FIELD.setAccessible(true); + } + catch (ReflectiveOperationException ex) + { + throw new RuntimeException(ex); + } + } + private static long _nameCount = -99999999999999L; public final static SkinData FREEDOM_CHEST = new SkinData("eyJ0aW1lc3RhbXAiOjE0NjY1NzA5NDAzODcsInByb2ZpbGVJZCI6IjQwZWQ5NzU1OWIzNTQ1M2Q4NjU1ZmMwMDM5OGRiNmI5IiwicHJvZmlsZU5hbWUiOiJTcG9vYm5jb29iciIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4N2Q4OGNlYzNmOWI0M2RiNDg1YTU0Mjc2YTQ1MjQzNGFiZDI2ZDMzY2QzZmZhMTM2N2ZiMzVmOWUzODQifX19", "UgsQyW/HJ/jmDzfI1d7RWFbhKi8PeJAKBuAOk7ajS5dzH5od301KfcmiT2X3TU7cBbUswcKtDb2F/m7gNrg/t+pU7Bi9UKzyALEu9HRjd4s1uKbqGkBip1z5Qycp4fhkSyKvtvTnA2fhpP9oHtE5FxGXdMhZXyFkLrli4Hyxp1BI0N4h7pgbcMaISPS0ZYzDRNxkrSnl3y3KyKn5Rl5qH7utmQtAjoyx9aueMZxG3tg/igfYF7uAvvmuYKsSiTZWZOOuSh+U1dkP+ZE/cQANfryXkLJSJHa9YZPCMJHXe4mMoAyu0/quwZCW9NlW3P30XeCfZ87IxfKxISIP0dLgY8hUJyCuI2u5U7TEDrDggPKr6XTcIbX2kFKOsYSeovsAgjC+1UKFH4Ba0jTbRmqzPK49fk/jU8XqRP2Gl9UZDIVbc0dMEXNOeJ0e0wejDtSyX8flBk9sIKYwqeB9ns4cFqSyTI5tKnNin12BNTFRK/bDp8dN7nloyQvhDGlW88UlnJmOFhR6R0naP89VM04VCLaYCr6jyv/ZwV88uPvL2kjhx14qSFfgqJI5ORhFgYkuc+nhyQaD8+y2t3ZMs0HAfoujmq98lp2ECLWyI0ATUcXjUyNYadLj4valS/m0jl7U2fwzcmVMQqOC3ddu6mHbt871hIkG2X4v6kEcVAtKmkg="); + + public final static SkinData ALEX = new SkinData("eyJ0aW1lc3RhbXAiOjE0NjY3Mzc4OTE4MTgsInByb2ZpbGVJZCI6IjZhYjQzMTc4ODlmZDQ5MDU5N2Y2MGY2N2Q5ZDc2ZmQ5IiwicHJvZmlsZU5hbWUiOiJNSEZfQWxleCIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7Im1ldGFkYXRhIjp7Im1vZGVsIjoic2xpbSJ9LCJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzYzYjA5ODk2NzM0MGRhYWM1MjkyOTNjMjRlMDQ5MTA1MDliMjA4ZTdiOTQ1NjNjM2VmMzFkZWM3YjM3NTAifX19", "BCyo2Ycx5cxjS9eR8ejakJ0inXSaiOO/2Wb3GoOSBFeKmnLpigR2kbvnIv0j+R5wtGLAbcAmxCZzvI9VpkHC0Al7zyAzY+WypfXi5MAju+dpVdCmp8p3m3oznYscPaI1ADR8ecQBMLFeG8RWuWha5whUyyRNQU8pBPbKMcsIMOn2voCQkH3cjtrZRgDGebxF32CE7I10GEhiFv8UyBVhZ11t6Jbbsj345j0ZHoydTlGADFFpnx+bAQ6BQlkMgNOWAJoI7/3p6IjFQUVYQV70o3VvP9G+B0VwHSQPxhCYxgF/1PcmKsET/HN6cPR34qKJ5HiSt2oS5q/EqLPc9cK/pFAVb+/rq/Z/TSVL94SE/OcImT7NHvVOqurLPLNyj7SMbQvL3bZS3wNkeU7TIkQkGiza2jmeTfPOkBXwMUBl95b+BX3aM36EtyZ4jL1eTOJdqG4x5JG9uGVvcGHw5289ykXUW3L3+A/9J2uYT3mzH9dJ1YLGA3dmTmMqjWrJRxdA5OU46fREsMWMaELbpiHOkhAgqMW1Bofs4hdvkBZE3JIbjIivncvXVU0MGgnd//U4P5iteUMY8Dpc+uKJ3N8KMojCbhWiig0ElLMuNFbNG9PVsUNwwT/wYLJZ3PJ0VBcNERgAWnJ16DM4oA8SfAKosmSQBCW11+1Sxfkj55QoxH0="); + public final static SkinData STEVE = new SkinData("eyJ0aW1lc3RhbXAiOjE0NjY3MzgxOTAzNDYsInByb2ZpbGVJZCI6ImJiYjg3ZGJlNjkwZjQyMDViZGM1NzJmZmI4ZWJjMjlkIiwicHJvZmlsZU5hbWUiOiJkaXJld29sZjIwIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82NmZlNTE3NjY1MTdmM2QwMWNmZGI3MjQyZWI1ZjM0YWVhOTYyOGExNjZlM2U0MGZhZjRjMTMyMTY5NiJ9fX0=", "xIDCRBS39ZhhROcYkYORDcWosWqR5xvrTTScNzpt8WtBq1cAoL1mXEi/PtBrEEvajcpR/nGhRlZV/IeavtmUx49ulY3bdX827Rex3504DnmolxVqnq8/p1W8ywxV9FBcMI4Cto3c5kmIXHTTAcLsUuCmsmprzuMS+/RvfJ//vjem+lUc+eQKBe3Hc3ocapfxf1dHqSrtzurW2fRTMZcJWEOr9eicRDzOOP2nbtfZGeCcwJPnYJMxJReBWLO/LiV6Bzm/8+ynRFzmJVw7zvXY9WCz/Yt95nK1lqpFZXR7djFYTsnLpLc71rUPhPwSZSVm0Ca+wZWI2RFnm3kbKRsIB89EqsVIxgw9SMKHJwGPc/GBMOZuO2J6HxGn5xXE5JnLTn8YzpBDft+3Hnb2EJTJ2OCPHaQtzMiYDG4+OkwP7ksxcwmMxRUWuE37dwXi/d4A94IKsLqrCxj+vGFPo13wc5L0DRRx7Plk2/nrC32UhKomkjGz2XbS1aJpKgLILbaM1nYnNGKx/VBLNNJdpwhwaoWgRPEB2MEFmxV+GQ/QgOJuaI7fj5KfLqCePX5V3tfdEUb5OmnC2rH1+ptE1RNOBvPPV/D04NzpvvT9QtCq3I6f1fqbcdWVaYkrRcyD/EjQv0Vod46GJPT4jEQ8f2K10dpDtaB/cWGpT16XCRNT0F8="); + + public final static SkinData MOOSHROOM = new SkinData("eyJ0aW1lc3RhbXAiOjE0NDk4NzI0OTU0MTcsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIxOWJlYTU0Y2FkN2Q1OGFiNWRhNDA2YjBhOTJhYjNhODI0MjI1MjY2Nzc3ZTUzNGI3ZGI2YzM3MmRkZmY3ZiJ9fX0=", "UoSif81+UyvkcaanU8KAMYBpw9mefAmWehE2liDUFvk+y0X/9NovsxTYVpIDCltTSpLW3sNgamvbj4Ybs+s6DbudPiEkvh0ER7Bv2v29UJw7RzIdr6/1g548X12zcnh5iPGz/P75uNRnSfTFQx0ed8P/GNkPIjWpDuJFxEj6KcPzrCAGMx+BVw1VwryBIYf9cCDHky8z0bxR89rjiIvPTBFI6MRhqI3vgpEBTySHDS+Ki0Hwl5oa3PwS6+jgYx/4RSfFsb+BawcvDk2Xpkt5UimvqZ5BceYLIfCt4KbShYipgLXLfYUZrntjPemd3SxthjxUuA07i44UxRdiC8uqy1twLT/HUS28gpk68lA/id9tKFwu1CUzshgcmvQPt3ghtNViNziR/2t7D/+5D31Vzmhf6n7Pnpdirt/5frMi2BKMMs7pLa0EF8CrrDU7QCwPav+EZVGFvVZbxSkCDq+n3IQ3PUWSCzy6KPxpdOlUjD0pAfLoiNj0P8u4+puQtID76r/St8ExchYl2dodUImu1ZETWeFUClF3ZGat62evx8uRQEI2W4dsVwj40VUfjaAuvyDzuouaKTrCzJXLQZZjR1B8URvuK61fGX0nhW607mEi6DE+nxP2ZoBrROEX4e37Ap6+TQn9Q8tKDPdcxtwSOpPO4Qkncjn/mGtP9lZU/DQ="); + public final static SkinData COMPANION_CUBE = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMDk5NjI0NjEsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyMTVkYmRhNTY1ZjVjYjhlYjEyZjU1NWY1ZTNkYTBlYTVmNTUxOTg5MWNjNWM1ZDY3NmZkODJjNjIifX19", "vaAQbhnhnTOs64ToFWLg7o4JmqkIl07HWJ6l7xibfISaOcU4BvYBxsfGvmoxlVdsUeCunAJ8/05qVLl5zZYd8Dt+To6JSY0RlqV8piRaaj3FztYWV2ZvG3YZxPxiD3HRJTAQnDobSuxHyPa1e3khjAFp9xJo4q1oqQ28oI2WDuoT+IHqxwkKVbGzO7UD5lzz5chjQC46E8SxddNKp9aqwbbccrkHYT4gteoonOXu4MFxZniJN12LqUCb6+G15rU8MijlBkWx0xE5NMUloeTGuJZItbHun9fysLk/+HE5xJOKYtpZNMuWX+DB/O5ds9dXrOoSAg+Vn0QU4CZbwcxzLii5ILOfEEBtePuEAgzROri+iCKp59CqlEMBrCsd3Um0MCdbuOfvkXGBHBz+bqX7VJY1ujlSdMefmbJtHAkDANnsaaVb+eli9Dk6139041sptsLytD+EfJzaitX6crBwKZ2WDx2P6LHo8B+iSOzOJxjf/08zlXqFw1vsk62IN6lisuZ89QyZw23RvOx3obLAGYs1GxAlMl9qQdpXcmuE1+lPR3g8gZ0BfnTeYwflC2wbR1tuwGG98lyUGCvGLyqNKAQTN87XV4IFQWR81mi1c5CcasoWhKf9D9nAik9aK7A915fEE5IvpeuUdZseDxDVVN5dBIs5q2PIHFAS0rDsDBc="); - public final static SkinData THE_GRINCH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTYxNDMwMDQsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWRlOTI3ZDQzOWVmMzliMzFhYzFkYzJhODM5NGZlNzlhY2U4NDMyNzBjYmUxMjg2ZGM3NTE3ZjMxYTk2In19fQ==","ELo594vTzPq9ZmPYOtVr4kim/k19gzmoxEIK1ehS87gwgag5HcgM+P1FMnHIyrmSvTVaMh0NxwXmNS+JETFL7OrmgRYNpkxkkO4VBA0pfSn3dA9ujnXpDnDiWEPxKdMgQspIOOI0Z3esNt3pj8qIj6dWPtGwtso48tjHl2o/kazfa82yvGORlFhGkeEJKQMno/Buc12C0foQw39XI8GjvlSkFN2eH4Fp16RLu8/hf7SqJQC3L1KacvzMW1d8BWEIgACCJDni29+YqxflSqSyYrV4Z+D66S0jYvUUL/vM4/q/p/YWX/vs/FtMtHQTj4PCpAmMNTgfkahuhb6rCvKHukbjA+WhUdwyxSqXU5YnpXCu1M2dzZgiXjIi+fnyn4CmXKindWCQtSwu+mCA2ILv/6vEHoYJgdlz+DXyRkFx+DH4Sl74HBCOXTOq5AGjq5h3LYfsre+UjCCUv8VgxbVprOyj35So7K0m+6faCFVSt35T3RgicDQfdiWUrW7kmHQVvJpvaq9Vu+63F/0X93cwqwaR0buMirxRx7qkFrRunSI4T+9fsN02t1fAieeu80lBSv83wr7BFneSsLsdVAND9xttTb6fClg7anr8/XVEVIkylB4B+ZcWQbH61XP1nn7oFP2VBg1h6XuuLp8FGSgYf/LW+54/KZci/MnanqQE6QQ="); + public final static SkinData THE_GRINCH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTYxNDMwMDQsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWRlOTI3ZDQzOWVmMzliMzFhYzFkYzJhODM5NGZlNzlhY2U4NDMyNzBjYmUxMjg2ZGM3NTE3ZjMxYTk2In19fQ==", "ELo594vTzPq9ZmPYOtVr4kim/k19gzmoxEIK1ehS87gwgag5HcgM+P1FMnHIyrmSvTVaMh0NxwXmNS+JETFL7OrmgRYNpkxkkO4VBA0pfSn3dA9ujnXpDnDiWEPxKdMgQspIOOI0Z3esNt3pj8qIj6dWPtGwtso48tjHl2o/kazfa82yvGORlFhGkeEJKQMno/Buc12C0foQw39XI8GjvlSkFN2eH4Fp16RLu8/hf7SqJQC3L1KacvzMW1d8BWEIgACCJDni29+YqxflSqSyYrV4Z+D66S0jYvUUL/vM4/q/p/YWX/vs/FtMtHQTj4PCpAmMNTgfkahuhb6rCvKHukbjA+WhUdwyxSqXU5YnpXCu1M2dzZgiXjIi+fnyn4CmXKindWCQtSwu+mCA2ILv/6vEHoYJgdlz+DXyRkFx+DH4Sl74HBCOXTOq5AGjq5h3LYfsre+UjCCUv8VgxbVprOyj35So7K0m+6faCFVSt35T3RgicDQfdiWUrW7kmHQVvJpvaq9Vu+63F/0X93cwqwaR0buMirxRx7qkFrRunSI4T+9fsN02t1fAieeu80lBSv83wr7BFneSsLsdVAND9xttTb6fClg7anr8/XVEVIkylB4B+ZcWQbH61XP1nn7oFP2VBg1h6XuuLp8FGSgYf/LW+54/KZci/MnanqQE6QQ="); public final static SkinData LOVESTRUCK = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMTAyNDMyNjUsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzczMTY5YWQwZTUyYjM1N2NiZGYxZDU0NGVkNGNmOWJmOTI4YmI0ZWNlMDhlY2YyY2M0YmYyYTlmMjJhODI4MmQifX19", "LL4RiSKQoTZamRQ4QG6izpvhgFu5gAqW4eZxcWAihk7GkhyxifpJpBTOzKrj5hH9fCUfYkkijVWUYTEcVSVRWhocp2HXW59TbKfxOeMvHU5vTMwgpwm6PnUfwuTsRPSLC7WMnEreI3cjOxPVmXbTniOSd+o8j4oOIgwFS+VLPiYLh5Jl16i5I/9ekafl3/x41NISKWl62geqO2jPWehlk+r3soiRJsxaKw20T61GSNLu19iA96Rz2T2tUHB4opm8hbLgoiNL2g1affTjq3cZPLHH4JWF3vPhqLB5uw6xb55vFLM/PP0YiEMIi7YZOfRGeaPp7uXbXgHeew+7PG9UDVMfqbwANQY4ndECijZoei54+xX3MDXkMhQsc5S+FLnGH6e4d008v81eEOyzJUPkKbGxLCBgTUb1s4IHwomCr30twPlo1IuFBOY1qeVvZUfAfPJsREuj5q/oCAoYFgupmb3ClWECnwwaH/T4wdHjfSBHoZQdLzcgDOAl0b5EXxWmYBECqk/WA4TrYIDVGdwkqjI0RkPLUoxTj6135KO+F7P7PwhU9WBGeW8hHq918DBL0fjQVHjrzvolTqwmw6nySSePnPOxFX/iwtHWzpBa9V6kUNNN+V7OGTgRr0H/yUxB+oq1F8UBqyqT4YpqxXCSD36derF/Xt5IdpTbEbGBpm0="); - public final static SkinData PRESENT = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3MDIxNjIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2U2YzRkZWQwNTdjMjhiMTU0NjVkYzQzNmFmODIyYTNkZTY4NzgyZTZjMzgyOGMzMmFhYWE4ZjRiOTIzOWVjIn19fQ==","rJNlxTqHHmOoWwbXdMQLcj0P9w/PIr/hWKXH0nbhm/S2CFo/zfefffZlnQmpKCgn1Y8tXvcRwLGQ4CLpm9m2ZrKprSWRhrnOtZWYabrhExQESEammS3TY81VoNt+4On0pAGBippz/bRfWLuDne2rDbhuljnqvxjROmxpky7gRCU06VMlm2WLFC5XYJkiAaOXBqzpiHMMRPNnCvtcbtpILKi/Luj302eyN8nRKjHHbbiDmttwvlshxZ8UxJHvALtM506IUHba10Q6QX2zCeDAU5/WYRKa6e19r8plROcgGbKYFSq8JW5cWuWT3/rveZM6FnU6ABn9DWsCyfQ5wr2jdBd+xaevGTAScRHA5J493GqL1bBZYKj9yhQFtxJHCAf0++raAVPCZgyPtwTth4TAQisn8gnhM5R+txnW6xK+oflLy0dwEN1YdPLN/h7yuDnyjSMDe9RZT2NKMjok2C6Kux4WBI0KFXKC5Gqwa3Htku4v3WEOWMaVoWOtchQ9BzpQ/etD0ylmzjALQLB+HtndEEm1Jd3tmob42X4hBE8hCce7C3EtGINB33dlx4CK1xBqyGTJEqi69DJRzVL99u98+7kJ1Db9+MaPOfI4B2RY3XbvnSYwecandY//A3bb19FGSdl299ZXbp4zpm8fivzeB1rUAhhmtaA3Iwu/nEQNMkU="); - public final static SkinData RUDOLPH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk1NjgxODIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2IzZjdlMjhiNTJkZjJjZjhlZWM2NDk2ZmM0NWFlMGQ2NTM0Njc5OGIxYWRjNzM3ZDcxYzBmOTRlNDIyMSJ9fX0=","uUBOTe63CL+qRvtsb2g4AjB2YzxE3N6AUqIsTv8n0jYyPsuXpuOmZPSMEdgDVONywEJ1L4XRx05sjnGu56A8vuXmGI/uHQWuMZzbOSjiFfT3DkEm8zEl5AWpH9dz/t8nZ1WYUIwy0pN5VrZqIr1DAkF6AMh/Qy+FGDw1GG9ReRr80eJ0JiRskpkCpCZIGGjrgwNKAM8JOuNZ4gCQOTRC3etrcfls3qmUMFcVlhuB4bydxSR01i2w0A4b5KpufsJjLKw4InWn2+m/druo8hl9sYuusTeItW0MQmZqCAqXCc9YBnRPQ0hDXFgnPxOh3RwGWiZvL4MnWUVmLwZWh/Fk9QmyVbd7zVao0lxS8YNsKtP8j5B+hs4l9qNohhf0A07bt4oPeTtd5fQeOU5N87fUGuUAcpC4gP9U5WpVY5FFPBvLvGbXdV5jpuAQz4lLSoo1grsP9baR2IBvdN/0awjQWoPJfGOttegubkBHwz3LNcVqvZLtX/M13IDHZa6zQZEX0wsnMX60LeWgBWfTON1l2cSgaPTerHFS2EifJ2LvTBife3s9/4XR6Zth3FLFqxI3MSlqT2hVFRPLke6rBqfqPoWOj2MCykQ70IAwb3oTHcJDJ86V2DdNaU2bZ8V4TjaP+nRobsLJOImoPYEPq23MP36X8gbXEIjmuu8S5xRlrrc="); - public final static SkinData SANTA = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3OTM3NTgsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyNTM5ZGFkZDUxYmE5ZTg0YzFhOTE1OTY3NWUxZTJiYWM1NmFlNmFlNTMxNTQyZDI1YTlkM2Q1YzQ2ODZmNiJ9fX0=","gvLc0Vo6+1vl17vrFCbK1eNqa4/ix4xiwcWae7WOCvqiVIX4sdIPagOGUrKsDdEhuWCKkTWILGP1K3wYfC9v/0mXZvbu0sRln+APTOsswMkQmbKcA1zTFTMpwEI+nIMzYJSbIx5wjz28K5hDf/umtHH2GADTENdJGGUtU4CyEdeHTzcqIAEV3bcMLkfTKvwKUWqI5gZbbercqmDeGkmXVS9297a9paRX1NfEL9pFT0pjdH3tCjgvvKfAwGC6tYtvTFbfcJocqgI+PI2f5OFf62A4XjWwWFi4wxCHVYNpqs/XTbfF64K7KVE0d9gsLjJoB8DMZPxlNpMFA0R5OIW6Q7Qjyz9IKxUqEYRCQbuUKpHyNDcmVKcTJRwBpCHeqAbTbweZHd5tzrT/terWhLEMsK1+lH2KBfIRIRB9kd3epyShNjSEKoly6uRXVxU+IJtfcq0aFVZlwgG3c1Ds9jbsNJV158e1n6WCmvT00RLdvpcIekwUKODhi3zFeFkrVvV50tGYqXLRZenitLJvDzx4c0IGK4krALrUS0oybinBS7/GmW3Ktz3xbGKZSzzaDw0EKB7Y6XHdb4yqR1xS7lAWgv4cNDEIUSzUDJ7HpmDCIF2A5kPS4XVYFCclyR6qPGD5e+9apVhBMz4lfYlT1IfRAUQlucO4UpAlkXs7ho3pQXU="); + public final static SkinData PRESENT = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3MDIxNjIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2U2YzRkZWQwNTdjMjhiMTU0NjVkYzQzNmFmODIyYTNkZTY4NzgyZTZjMzgyOGMzMmFhYWE4ZjRiOTIzOWVjIn19fQ==", "rJNlxTqHHmOoWwbXdMQLcj0P9w/PIr/hWKXH0nbhm/S2CFo/zfefffZlnQmpKCgn1Y8tXvcRwLGQ4CLpm9m2ZrKprSWRhrnOtZWYabrhExQESEammS3TY81VoNt+4On0pAGBippz/bRfWLuDne2rDbhuljnqvxjROmxpky7gRCU06VMlm2WLFC5XYJkiAaOXBqzpiHMMRPNnCvtcbtpILKi/Luj302eyN8nRKjHHbbiDmttwvlshxZ8UxJHvALtM506IUHba10Q6QX2zCeDAU5/WYRKa6e19r8plROcgGbKYFSq8JW5cWuWT3/rveZM6FnU6ABn9DWsCyfQ5wr2jdBd+xaevGTAScRHA5J493GqL1bBZYKj9yhQFtxJHCAf0++raAVPCZgyPtwTth4TAQisn8gnhM5R+txnW6xK+oflLy0dwEN1YdPLN/h7yuDnyjSMDe9RZT2NKMjok2C6Kux4WBI0KFXKC5Gqwa3Htku4v3WEOWMaVoWOtchQ9BzpQ/etD0ylmzjALQLB+HtndEEm1Jd3tmob42X4hBE8hCce7C3EtGINB33dlx4CK1xBqyGTJEqi69DJRzVL99u98+7kJ1Db9+MaPOfI4B2RY3XbvnSYwecandY//A3bb19FGSdl299ZXbp4zpm8fivzeB1rUAhhmtaA3Iwu/nEQNMkU="); + public final static SkinData RUDOLPH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk1NjgxODIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2IzZjdlMjhiNTJkZjJjZjhlZWM2NDk2ZmM0NWFlMGQ2NTM0Njc5OGIxYWRjNzM3ZDcxYzBmOTRlNDIyMSJ9fX0=", "uUBOTe63CL+qRvtsb2g4AjB2YzxE3N6AUqIsTv8n0jYyPsuXpuOmZPSMEdgDVONywEJ1L4XRx05sjnGu56A8vuXmGI/uHQWuMZzbOSjiFfT3DkEm8zEl5AWpH9dz/t8nZ1WYUIwy0pN5VrZqIr1DAkF6AMh/Qy+FGDw1GG9ReRr80eJ0JiRskpkCpCZIGGjrgwNKAM8JOuNZ4gCQOTRC3etrcfls3qmUMFcVlhuB4bydxSR01i2w0A4b5KpufsJjLKw4InWn2+m/druo8hl9sYuusTeItW0MQmZqCAqXCc9YBnRPQ0hDXFgnPxOh3RwGWiZvL4MnWUVmLwZWh/Fk9QmyVbd7zVao0lxS8YNsKtP8j5B+hs4l9qNohhf0A07bt4oPeTtd5fQeOU5N87fUGuUAcpC4gP9U5WpVY5FFPBvLvGbXdV5jpuAQz4lLSoo1grsP9baR2IBvdN/0awjQWoPJfGOttegubkBHwz3LNcVqvZLtX/M13IDHZa6zQZEX0wsnMX60LeWgBWfTON1l2cSgaPTerHFS2EifJ2LvTBife3s9/4XR6Zth3FLFqxI3MSlqT2hVFRPLke6rBqfqPoWOj2MCykQ70IAwb3oTHcJDJ86V2DdNaU2bZ8V4TjaP+nRobsLJOImoPYEPq23MP36X8gbXEIjmuu8S5xRlrrc="); + public final static SkinData SANTA = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3OTM3NTgsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyNTM5ZGFkZDUxYmE5ZTg0YzFhOTE1OTY3NWUxZTJiYWM1NmFlNmFlNTMxNTQyZDI1YTlkM2Q1YzQ2ODZmNiJ9fX0=", "gvLc0Vo6+1vl17vrFCbK1eNqa4/ix4xiwcWae7WOCvqiVIX4sdIPagOGUrKsDdEhuWCKkTWILGP1K3wYfC9v/0mXZvbu0sRln+APTOsswMkQmbKcA1zTFTMpwEI+nIMzYJSbIx5wjz28K5hDf/umtHH2GADTENdJGGUtU4CyEdeHTzcqIAEV3bcMLkfTKvwKUWqI5gZbbercqmDeGkmXVS9297a9paRX1NfEL9pFT0pjdH3tCjgvvKfAwGC6tYtvTFbfcJocqgI+PI2f5OFf62A4XjWwWFi4wxCHVYNpqs/XTbfF64K7KVE0d9gsLjJoB8DMZPxlNpMFA0R5OIW6Q7Qjyz9IKxUqEYRCQbuUKpHyNDcmVKcTJRwBpCHeqAbTbweZHd5tzrT/terWhLEMsK1+lH2KBfIRIRB9kd3epyShNjSEKoly6uRXVxU+IJtfcq0aFVZlwgG3c1Ds9jbsNJV158e1n6WCmvT00RLdvpcIekwUKODhi3zFeFkrVvV50tGYqXLRZenitLJvDzx4c0IGK4krALrUS0oybinBS7/GmW3Ktz3xbGKZSzzaDw0EKB7Y6XHdb4yqR1xS7lAWgv4cNDEIUSzUDJ7HpmDCIF2A5kPS4XVYFCclyR6qPGD5e+9apVhBMz4lfYlT1IfRAUQlucO4UpAlkXs7ho3pQXU="); public final static SkinData SECRET_PACKAGE = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMTAzNzE3OTIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2QyNWI5YTRjOWRhOThkZTliZmIwZDNjOWI1M2MzMjJhMjgxN2IyMTMxOTQzY2E1YWM2NTBjZThmMzEzZjdhIn19fQ==", "Wb5T0Zhp1RVt78V/i8dYrwZCNT0xZIRe3LvL0bngH498f8Jrl43KHgTi4f299zE9giVynkTogGhJ8inq/xqFCRctl7Nn9L3LVu78uQwt+fs+o+kw/Qc+lggFSjEIc+fc13AZndpec0Df46Kh/OGD7NXbtbLb6TE/0dU2RwQlvZrZ/QHYJb8OJ6aUcnHvAZim8NUtG/nlZtSClepHVSuKdNnfzoF9rFVFA/x4jTr6mZYPZ33YgQd2oTAPk+qE3iN+0InjZQNs2YLoKFmFrgzn+tGvNApC0siF0HEZGQCFIwJOtnBsasGoxujIrln/ZdOil+5ac4VWInXr8lKgY0Q3Ocy8/0cJl+E/XqB+ztG29zhB8B1zdHBfJr+MgeSIqBCPx4SCtY6r7gnMlQYG+uVx5NP3S5aJW/cEfDyXmpCykIcBPzeErnKC0SiAqXkCVNjWJpX6qRWvWMXqS69w6ht6qHvEY2GxlZUb5AP+JgFlsl3hJDms6EPvM4zNL0Ko4oWIBzwYRQXiemrP9TGgyo0aL1RcQ0JgBFO2hSo37PK0YL3tUPgteJXzm21wu0TiZLkLCWSgMUfYfvVnhTa+xzod0xvfujpN6Y1DUTdcf8WS8TRYw2JigSkWrRW0fXPBCtTtQN5jiwM5/HrTpNLzg03J6SpfZ+rr8Rhq0S/8beQOMas="); - public final static SkinData SNOWMAN = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk4Nzk5NDIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzEzMTgxYWViODQzODk3NzM1ZDQwMmIyNDk2OTQxNmZkYjBjZTM0YTZiOTM3ODE2MjQzNzU2ZTlkYWU1OGUzIn19fQ==","NZvsNu+HQ5uvGWq6O8VNDGq9A145bmk2IkHiz916uRVPMRqqCI/zwhKWNLlFACE/feuLkhYAois29ec6sVVOtHIoNA+S5q1Mb/Vjc3TJQxzqmx2FZOhJiIttFwYuo9WomQKBqrPMSJ9tpQig4wzoqldeeTjWC3dLz7JeX+gkzinryVjG7NNN9L5hXK5/BBxRcrtwmXJfUlSANyrd8RZW7mEUgU8yxlzdqTu0w7bZLjQNd4vciwoF3NelXDorMIIqiHTkuQesG91Njtu25VCUDK3nXbqEnZw2ZtxB5fT5G2Omm/vkNSRXc0P7iqchVowdYQcMlQUsp65xpkBbFS4LwjzDkYIfLmF++hePb8z72Gz77FxhO5sRLGreSH227McyL/0CtWNKm9ZZIfQtZZjEZTj9+eiJMCloCMg3yWa1VBOiLHzz0wY6gGklccIImPyXEg7E0dIK8qYseJMhmmBNZ8pDOkbUDp3mRlrQ2iyClgQkbuR63j79IBUaCxmsa3NnrAtaJklzd9mzkHXfMBh2XT7Gl8AhJS6JK5kCvip1rBBI8yjrsjE/E+lyJFIbC4rXxyMDGZWkcdrd7U4ZFYKiLHbzdFRqX+11qs9xO2BvomGXkATCzYmOf2kQ86R6rNN0+JfE4QpKzj2WWt3C8ky2qpuXZz29p0816E3/qseYtgg="); + public final static SkinData SNOWMAN = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk4Nzk5NDIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzEzMTgxYWViODQzODk3NzM1ZDQwMmIyNDk2OTQxNmZkYjBjZTM0YTZiOTM3ODE2MjQzNzU2ZTlkYWU1OGUzIn19fQ==", "NZvsNu+HQ5uvGWq6O8VNDGq9A145bmk2IkHiz916uRVPMRqqCI/zwhKWNLlFACE/feuLkhYAois29ec6sVVOtHIoNA+S5q1Mb/Vjc3TJQxzqmx2FZOhJiIttFwYuo9WomQKBqrPMSJ9tpQig4wzoqldeeTjWC3dLz7JeX+gkzinryVjG7NNN9L5hXK5/BBxRcrtwmXJfUlSANyrd8RZW7mEUgU8yxlzdqTu0w7bZLjQNd4vciwoF3NelXDorMIIqiHTkuQesG91Njtu25VCUDK3nXbqEnZw2ZtxB5fT5G2Omm/vkNSRXc0P7iqchVowdYQcMlQUsp65xpkBbFS4LwjzDkYIfLmF++hePb8z72Gz77FxhO5sRLGreSH227McyL/0CtWNKm9ZZIfQtZZjEZTj9+eiJMCloCMg3yWa1VBOiLHzz0wY6gGklccIImPyXEg7E0dIK8qYseJMhmmBNZ8pDOkbUDp3mRlrQ2iyClgQkbuR63j79IBUaCxmsa3NnrAtaJklzd9mzkHXfMBh2XT7Gl8AhJS6JK5kCvip1rBBI8yjrsjE/E+lyJFIbC4rXxyMDGZWkcdrd7U4ZFYKiLHbzdFRqX+11qs9xO2BvomGXkATCzYmOf2kQ86R6rNN0+JfE4QpKzj2WWt3C8ky2qpuXZz29p0816E3/qseYtgg="); public final static SkinData TEDDY_BEAR = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMDkzOTE4MjYsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzQ0OTU4ZDdjNjlhZTQ4NGM2NWYzMTM0N2NkY2M5MmM2OWY1NDA2ODA1YjUzNjUyYTc1YThlZDc5OWRmNyJ9fX0=", "sNTRV9jTjLszUmyaqyEG7N8d5RM1jbwMSXi34S2EkVmIjWsowfSMnHRQqqgZfxcyqBM5I7MljtB84IeQWu4rqhyFrM9blWvtowjijFIOgKCs97q2sswv9iauU6ohvgTpgN5B0Q16MJmMIgZU8d8TATtEaIzq2eg6Ve1AJlNnW4huGNsoNfm8WdVU1tZmsYAwtVP/ryvhyj7mHyVF27m0Sm4fZRf/lHH5gEJYB4JHSAoEhjPIQOdkgRMJRrWGOfhhiGs3kEWmsRGfIPFo2ZJfcu+TFV2rd4Q+A1LmY8kimnzdKX3InXeKbk8qzcgqGNro4XFnSiHo1d6/B+N0JeYOTITYRQ6u24rNSUh5ezbG01iikVFCfrgb7UR6utoLK15F4/fmhpex+BJpmyZoXAqk08tZws/5wsIWQ1okrGcbBKWEHhw2ekUc82US21/W53vd657UBg7FuqM4FhkAqmsYPvYLMpNYxxmDJaI8uJyU7cnGFYyBaFlqUxfJUfcFTwWo10JO3yp5FjqeCQa7rFvfpsqw3w2mBpJmlZ5HRjfS5pmhk0QiY0TRfwZfFemkuZYnNbO82qLUm+6zTm0fbC90Swt8nNr/42ajzEoUjnL6VsERIXS5/fPwjftbQAC60ujy8yo66Sp3sSAALNg5zjM+Uizkq2f9Axc+kind22hp10M="); public final static SkinData UNCLE_SAM = new SkinData("eyJ0aW1lc3RhbXAiOjE0NjYxODA0NjY4NTcsInByb2ZpbGVJZCI6IjlmY2FlZDhiMTRiNTRmN2ZhNjRjYjYwNDBlNzA1MjcyIiwicHJvZmlsZU5hbWUiOiJMQ2FzdHIxIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jYzM1YWRmZTQ3ODBjNmU2NTk4YTJlYzk2ZjdhZGQ5ZDc4NjljMjBlZjRmYjEyNjk2NmJhOGFlMDRlOWRhIn19fQ==", "NmJ+hXmvwQlYFYY7YVQWRr11yBbAfJP+jk11SQ91gUUtJJjb4v8RFbNu5UXNCKxYj3BPtldqshG1maNB0NWJRud7ZyAdHc0JMmR1vtHEge9Hhet4fLyyaZ9rZn4BvD9Guqgv9H/mZzUzrft9TIho0Qbu/U++lVsbZXC2GrJDDMyLnYr9C7f+FUnr0z4WvkNcg23SHBOYkOYT95NSdykIka3c3v+/HvSvuwOnMsfVxqLyCZLpo20vamBJ1uK1dmx2+TVGnUPlofFHRdOXOpJc+YmicJvrsQR6a9zlvnTbU4MYClMOKvjLe6aX5Af+n8Gw3oKcm0PuR8CPLyf9kjcmUF6XMiEXAWWJtCgvhCiFV5/mQQH3cQ1kqk4BDLUxMVhG5tzjKLoQQy39cFM32ee+QFjXlzy59meC8jgvPmOVU3GpJ32XWOtaXMCyeJrhz2QVKRLEr2KZgz8Pd8VrHARXVZsNYEasj8z0cHjgSJqTU9kD90CC+4YpvdyRBRqbNQig5KuGCqUHKgflsEsM7YrFRKP5As1LgqYQfqRAMmLSo47eW0onOwchC9wCqqisPlYSuDRt4Mun/KFGqYh1Sghn8/gzu49La8BpwlekjVEoPEcDaIIgnFzOvgmmgMANkoJ3PzhHoHMoXtObe3eSTi+eYp4qAQVzkTxfF3WXY2fui1M="); public final static SkinData METAL_MAN = new SkinData("eyJ0aW1lc3RhbXAiOjE0Njg3ODAyMzk2ODYsInByb2ZpbGVJZCI6IjlmY2FlZDhiMTRiNTRmN2ZhNjRjYjYwNDBlNzA1MjcyIiwicHJvZmlsZU5hbWUiOiJMQ2FzdHIxIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9hNzc5YWEzYzk3OTc0Mzk1YTY3MTZkZmQ5MTI4YWM0N2E1MzdlMzljMzdmMGM0ZjZkZjQ1YjJmMGI4ZjVkMiJ9fX0=", "acwmrIdtzzkuntsvQqD+o9UYaI09xzQoPgRXFtvS1hvGgGRbApdG7YbQ3Itjg/8WUl0trAMMJa1IL8TlXaOwTeClOj6if3HW2lJ8yO7E+MXEJoDZcjkxVOK3322NRCBiPG+VbNCwHE7IvT8P4awExvV2nHLbCk7upawxK3oKfR5U+YEq/eLG/UCC1TAnHNLXE0mr+6ZtNut5qgz1u0Y+VNQKI/vdjVit1ttYeBjIWpSszhlP4bH8Iw3u3ZRuDqU4xSAWzj6Qhw9UYm2T3s2N9s2yW3wiagijUEq9stbaw97n3UCqBas58lTBy46w524lBvwbYC1U9jwxPxSUo6L6omhPKZSwgK/u2w4mELvfNI09A4C7RNThnz9wgrT0FPajjXYkt31Ba5qaP7HwcThQu02Bb3gmYfHfMvuDBt8xUk4lFyUuL+lwqUHXlKRkUPGVkDLDpmsnk+y4LvaymNHBBWpOyqpm8y1BTpux02GqCIgK7nHtsRNH3q3yHR1YyM0tc6PKXOst5ex1cGP654/Q0KEUSAvAV5ozj/q5izRlPJNiwu9zPqhfs8oWSBSo/Sfej6p7Fu9u0h0j/k0m86bfZObe2RsCEgBe8GSF35cyYRou0qTvk+00hEr+jpxeat0e9JHe163jI/Ew9XPeGd6eT8GTy4iyJM0O/y1MlsRjUec="); @@ -41,76 +64,48 @@ public class SkinData //public final static SkinData CHISS = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTk1NDI5NjgyNDEsInByb2ZpbGVJZCI6IjFkMmJmZTYxN2ViZDQ0NWRiYTdkODM1NGEwZmZkMWVhIiwicHJvZmlsZU5hbWUiOiJDaGlzcyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTg3MmNkMzRjY2IzMTIxYjRjNmEzOGFjM2JmOGVkM2UwMzk3YmQ2YTg4NDI4YjdhZmM2ZTUyNTI4NTVhMzQzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "hNTLRA2acZYx2dM90lnJN8FMK/ceD3+AxKNdD5FrXzxGtYL4C1Jr/vbTE0UosmwFP3wScNEW/fuDOjeZRjZHMJdvgDZMlMK/5KDhOY6sj/RS9RckztsgummSyjH/hdDn7TWWfhZLMbiia/K0VReI9eq2yD6zGQpvMlz5hB/5SX5YHWXvCah3TL4UzYSlSVDlwY/Q3sVuIZUr8m/LIXJwniJKLGo6tUgtiJd9eseOsbBpVjzCUtLD8A9WBe2/eODgmLfqEvXESIoDRG8vL2nPSXWma/YolYHIl32/i+ZxVD7dRRaXQFYSiLI24EtzX1pPhMjyaTLazP9abH43J6J31w02pKM7N/xTa62020L/YfRRKGT5lygEDb1NMoSpAjszPxah+Ra2/L+yUWEI8cMES6I4mIJ00tclPjWK01xhIn3tqg+y2gqsGHwPhu/7vmF5NirNfKFw0qciKNBfbCAF7ae+mkUKjmAPuvBUBqQb7BOcpNVWsCo/XvzmiZZYsf5P4Uwz8LqUK4uH6V/5dg7lY2Xg3+IUylsrDqLGFDI8iy/NdjIQMbuRadh4IDO6DcmxBri2Ax4JNBPBTnRezge8uq37MZcft/IXQgFWKB9RtidVEACaTOkRj27k+Ojnkki+j44k0wZB47hiXFUHMCHl3a0SVdQe15ZbVsQj/HAvAS0="); //public final static SkinData DEFEK7 = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTk1NDI3ODkwNTksInByb2ZpbGVJZCI6Ijg5ZDQ2M2Y3MjNlYzQ3MGE4MjQ0NDU3ZjBjOGQ4NjFjIiwicHJvZmlsZU5hbWUiOiJkZWZlazciLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2JmYWNjOWM4ZjhlY2E1OWU0NTE4MTUxZmE4OGFiMDZjOTFmNjM3OTE2NzJmMTRlNGYzODY3YTI2OTVlN2NmYmYifSwiQ0FQRSI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIyYjljNWVhNzYzYzg2ZmM1Y2FlYTMzZDgyYjBmYTY1YTdjMjI4ZmQzMjFiYTU0NzY2ZWE5NWEzZDBiOTc5MyJ9fX0=", "jBoRvkhQXz+nap8yJJIZ+4HClMItWODumeSOYjXytP3WWKHK0UMq0xC/keXsnmvo89lMRdRbknPt2ZX5Flgyjgr4Rt0KtDvpL/hG4BUsTWryUZZMKxdd6DkZXYRtTogLUfHeDYIz+cZQ0aXGMtvX/ZYTXJfMi6FYbIHY/qEEDnWhDX5y+SPpaJaZByPsvzi+qbfcFGnJ6nqi9ccyZYnYpnI2IVBM/yO/VRXWHxfqvJ0VVvv5KsGmVbko2Jxo0SDCxUL2UTH2+eol53FxhkkC+m2geC14k1zsZQLHDF3BgAG9+kFJ4UEoYRKF2Gy1FxeDCJtjYNdrYR8fdaUKRMcpBgEs+ZGe2U9EVVS/ZcBCjB7S+1Ne2bPzPFzTQPuBoMgggo1xbxBmQ5NyhYo4gwgj/xjSLIhb+5h7ioN1URfSRcfYdVv6RRO9l/u9l09jEom8y/jGRviefpEr+/e9iAl5Dd/6nzQgosBQja3NSfqYZmyuet2eI9zu61CObDTpR6yaCbNgBe/lWofRfULdpJpgjb4UNTBom3q82FcCiOe02OekGPw4+YlilhICBhajF5JzN8FKAdqI1osDcX3KuJgikYIW3voNaOP5YN3GXgilJNdou20KFC8ICq68HglgX7/0rLrWKIEoswnINIM6HcJbQuXncVPwQhV6K34Hlt/Na60="); - - //private Property _skinProperty; - - /*public SkinData(String value, String signature) - { - _skinProperty = new Property("textures", value, signature); - } - - public SkinData(GameProfile profile) - { - _skinProperty = profile.getProperties().get("textures").iterator().next(); - }*/ - private String _value; - private String _signature; - private Property _property; + private String _skinValue; + private String _skinSignature; + private Property _skinProperty = null; public SkinData(String value, String signature) { - _value = value; - _signature = signature; + _skinValue = value; + _skinSignature = signature; + //_skinProperty = new Property("textures", value, signature); } - public SkinData(GameProfile gameProfile) + private SkinData(GameProfile profile) { - Property property = gameProfile.getProperties().get("textures").iterator().next(); - _value = property.getValue(); - _signature = property.getSignature(); - } - - public SkinData(Player player) - { - this(((CraftPlayer)player).getProfile()); + _skinProperty = profile.getProperties().get("textures").iterator().next(); } - public Property getSkinProperty() + private void getSkinProperty() { - if (_property == null) - { - Property property = new Property("textures", _value, _signature); - _property = property; - } - return _property; + _skinProperty = new Property("textures", _skinValue, _skinSignature); } - + public ItemStack getSkull() { - NBTTagCompound arrayElement = new NBTTagCompound(); - arrayElement.setString("Value", getSkinProperty().getValue()); - arrayElement.setString("Signature", getSkinProperty().getSignature()); - - NBTTagList textures = new NBTTagList(); - textures.add(arrayElement); - - NBTTagCompound properties = new NBTTagCompound(); - properties.set("textures", textures); - - NBTTagCompound skullOwner = new NBTTagCompound(); - skullOwner.set("Properties", properties); - skullOwner.set("Name", new NBTTagString(getUnusedSkullName())); - - NBTTagCompound tag = new NBTTagCompound(); - tag.set("SkullOwner", skullOwner); - - - net.minecraft.server.v1_8_R3.ItemStack nmsItem = new net.minecraft.server.v1_8_R3.ItemStack(Item.REGISTRY.get(new MinecraftKey("skull")), 1, 3); - nmsItem.setTag(tag); - - - return CraftItemStack.asBukkitCopy(nmsItem); + ItemStack item = new ItemStack(Material.SKULL_ITEM, 1, (byte) 3); + SkullMeta meta = (SkullMeta) item.getItemMeta(); + + GameProfile data = new GameProfile(UUID.randomUUID(), getUnusedSkullName()); + data.getProperties().put("textures", getProperty()); + + try + { + PROFILE_FIELD.set(meta, data); + } + catch (ReflectiveOperationException t) + { + t.printStackTrace(); + } + + item.setItemMeta(meta); + + return item; } public ItemStack getSkull(String name, List lore) @@ -122,11 +117,55 @@ public class SkinData stack.setItemMeta(meta); return stack; } - + + public Property getProperty() + { + if (_skinProperty == null) + { + getSkinProperty(); + } + return new Property(_skinProperty.getName(), _skinProperty.getValue(), _skinProperty.getSignature()); + } + public static String getUnusedSkullName() { _nameCount++; return "_" + _nameCount; } -} + + /* + * Creates a {@link SkinData} from a given {@link GameProfile}. + * Will return null if the GameProfile does not have any texture data + * + * @param input The GameProfile to get textures from + * @param requireSecure Whether the SkinData should be signed + * @param useDefaultSkins Whether to subsitute an Alex or Steve skin if no textures are present + * + * @return The SkinData, or null if no textures are present + */ + public static SkinData constructFromGameProfile(GameProfile input, boolean requireSecure, boolean useDefaultSkins) + { + final Map map = Maps.newHashMap(); + + try + { + map.putAll(MinecraftServer.getServer().aD().getTextures(input, requireSecure)); + } + catch (InsecureTextureException ignored) + { + } + + if (map.containsKey(MinecraftProfileTexture.Type.SKIN)) + { + return new SkinData(input); + } + + if (useDefaultSkins) + { + return UtilPlayer.isSlimSkin(input.getId()) ? SkinData.ALEX : SkinData.STEVE; + } + + return null; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java index 1945a0e1b..adcc05264 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java @@ -1,25 +1,23 @@ package mineplex.core.common.util; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Stream; - +import net.minecraft.server.v1_8_R3.AxisAlignedBB; import org.bukkit.Location; import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_8_R3.TrigMath; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.EulerAngle; import org.bukkit.util.Vector; -import net.minecraft.server.v1_8_R3.AxisAlignedBB; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.TreeSet; public class UtilAlg { @@ -56,6 +54,17 @@ public class UtilAlg { return to.clone().subtract(from).normalize(); } + + public static double[] getTrajectory(double srcx, double srcy, double srcz, double dstx, double dsty, double dstz) + { + double dx = dstx - srcx; + double dy = dsty - srcy; + double dz = dstz - srcz; + + double len = Math.sqrt(dx * dx + dy * dy + dz * dz); + + return new double[] { dx / len, dy / len, dz / len}; + } public static Vector getTrajectory2d(Entity from, Entity to) { @@ -98,28 +107,42 @@ public class UtilAlg public static float GetPitch(Vector vec) { - double x = vec.getX(); - double y = vec.getY(); - double z = vec.getZ(); + return GetPitch(vec.getX(), vec.getY(), vec.getZ()); + } + + public static float GetPitch(double[] vec) + { + return GetPitch(vec[0], vec[1], vec[2]); + } + + public static float GetPitch(double x, double y, double z) + { double xz = Math.sqrt((x*x) + (z*z)); - double pitch = Math.toDegrees(Math.atan(xz/y)); + double pitch = Math.toDegrees(TrigMath.atan(xz/y)); if (y <= 0) pitch += 90; else pitch -= 90; - - //Fix for two vectors at same Y giving 180 + + //Fix for two vectors at same Y giving 180 if (pitch == 180) pitch = 0; - + return (float) pitch; } public static float GetYaw(Vector vec) { - double x = vec.getX(); - double z = vec.getZ(); - - double yaw = Math.toDegrees(Math.atan((-x)/z)); + return GetYaw(vec.getX(), vec.getY(), vec.getZ()); + } + + public static float GetYaw(double[] vec) + { + return GetYaw(vec[0], vec[1], vec[2]); + } + + public static float GetYaw(double x, double y, double z) + { + double yaw = Math.toDegrees(TrigMath.atan((-x)/z)); if (z < 0) yaw += 180; return (float) yaw; diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java index 786f816a2..0e78782db 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java @@ -12,6 +12,7 @@ import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.TrigMath; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftCreature; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; @@ -295,7 +296,7 @@ public class UtilEnt Vector dir = entity.getEyeLocation().toVector().subtract(location.toVector()).normalize(); Location loc = entity.getEyeLocation().clone(); - loc.setYaw(180 - (float) Math.toDegrees(Math.atan2(dir.getX(), dir.getZ()))); + loc.setYaw(180 - (float) Math.toDegrees(TrigMath.atan2(dir.getX(), dir.getZ()))); loc.setPitch(90 - (float) Math.toDegrees(Math.acos(dir.getY()))); Rotate(entity, loc.getYaw(), loc.getPitch()); @@ -700,6 +701,13 @@ public class UtilEnt return CreatureLook(ent, UtilAlg.GetPitch(vec), UtilAlg.GetYaw(vec)); } + public static boolean CreatureLook(Entity ent, double srcx, double srcy, double srcz, double dstx, double dsty, double dstz) + { + double[] vec = UtilAlg.getTrajectory(srcx, srcy, srcz, dstx, dsty, dstz); + + return CreatureLook(ent, UtilAlg.GetPitch(vec), UtilAlg.GetYaw(vec)); + } + public static boolean CreatureLook(Entity ent, Vector target) { return CreatureLook(ent, UtilAlg.GetPitch(target), UtilAlg.GetYaw(target)); @@ -737,16 +745,19 @@ public class UtilEnt EntityTrackerEntry entry = (EntityTrackerEntry) ((WorldServer) ec.getWorld()).tracker.trackedEntities.get(ec.getId()); - byte ya = (byte) (yaw * 256.0F / 360.0F); - byte pi = (byte) (pitch * 256.0F / 360.0F); + if (entry != null) + { + byte ya = (byte) (yaw * 256.0F / 360.0F); + byte pi = (byte) (pitch * 256.0F / 360.0F); - entry.yRot = ya; - entry.xRot = pi; - entry.i = ya; + entry.yRot = ya; + entry.xRot = pi; + entry.i = ya; - // Looks like both packets need to be sent. EntityLook packet for body yaw and head pitch. Head rotation for head yaw. - entry.broadcast(new PacketPlayOutEntity.PacketPlayOutEntityLook(ent.getEntityId(), ya, pi, ec.onGround)); - entry.broadcast(new PacketPlayOutEntityHeadRotation(ec, ya)); + // Looks like both packets need to be sent. EntityLook packet for body yaw and head pitch. Head rotation for head yaw. + entry.broadcast(new PacketPlayOutEntity.PacketPlayOutEntityLook(ent.getEntityId(), ya, pi, ec.onGround)); + entry.broadcast(new PacketPlayOutEntityHeadRotation(ec, ya)); + } return true; } diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java index 9f5f14739..366c6fc35 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java @@ -938,9 +938,18 @@ public class UtilPlayer return true; } + public static void removeAllowedCommands(Player player) { if (ALLOWED_COMMANDS.containsKey(player.getUniqueId())) ALLOWED_COMMANDS.remove(player.getUniqueId()); } + + /* + * Returns whether the UUID belongs to a slim skin + */ + public static boolean isSlimSkin(UUID playerUUID) + { + return (playerUUID.hashCode() & 1) == 1; + } } diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java index 886d8e26d..b0ccc63ef 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilServer.java @@ -111,7 +111,7 @@ public class UtilServer HandlerList.unregisterAll(listener); } - public static Plugin getPlugin() + public static JavaPlugin getPlugin() { return JavaPlugin.getProvidingPlugin(UtilServer.class); } @@ -193,6 +193,11 @@ public class UtilServer return _serverName; } + public static String getServerNameFromConfig() + { + return getPlugin().getConfig().getString("serverstatus.name"); + } + public static Collection GetPlayers() { return Lists.newArrayList(getPlayers()); diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilTasks.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilTasks.java new file mode 100644 index 000000000..6e71d4002 --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilTasks.java @@ -0,0 +1,40 @@ +package mineplex.core.common.util; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitScheduler; + +import java.util.function.Consumer; + +public class UtilTasks +{ + private static final JavaPlugin LOADING_PLUGIN = JavaPlugin.getProvidingPlugin(UtilTasks.class); + + private static final BukkitScheduler SCHEDULER = Bukkit.getScheduler(); + + public static Runnable onMainThread(Runnable original) + { + return () -> + { + if (Bukkit.isPrimaryThread()) + { + original.run(); + } + else + { + SCHEDULER.runTask(LOADING_PLUGIN, original); + } + }; + } + + public static Consumer onMainThread(Consumer original) + { + return t -> + { + onMainThread(() -> + { + original.accept(t); + }); + }; + } +} diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java index 99979144b..86c6083f2 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWorld.java @@ -24,7 +24,12 @@ public class UtilWorld { return UtilServer.getServer().getWorld(world); } - + + public static boolean areChunksEqual(Location first, Location second) + { + return first.getBlockX() >> 4 == second.getBlockX() >> 4 && first.getBlockZ() >> 4 == second.getBlockZ() >> 4; + } + public static String chunkToStr(Chunk chunk) { if (chunk == null) diff --git a/Plugins/Mineplex.Core/pom.xml b/Plugins/Mineplex.Core/pom.xml index 2a88ca1ca..81a567966 100644 --- a/Plugins/Mineplex.Core/pom.xml +++ b/Plugins/Mineplex.Core/pom.xml @@ -44,6 +44,11 @@ org.apache.httpcomponents httpclient + + com.mineplex + anticheat + 1.1 + diff --git a/Plugins/Mineplex.Core/src/mineplex/core/CustomTagFix.java b/Plugins/Mineplex.Core/src/mineplex/core/CustomTagFix.java index 7a32a4aa3..fbbe9c561 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/CustomTagFix.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/CustomTagFix.java @@ -1,9 +1,12 @@ package mineplex.core; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.UUID; import mineplex.core.common.DummyEntity; @@ -53,15 +56,15 @@ import fr.neatmonster.nocheatplus.hooks.NCPHookManager; public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook { - private NautHashMap> _entityMap = new NautHashMap>(); - private NautHashMap> _entityNameMap = new NautHashMap>(); - private NautHashMap> _entityRiding = new NautHashMap>(); + private Map> _entityMap = new HashMap<>(); + private Map> _entityNameMap = new HashMap<>(); + private Map> _entityRiding = new HashMap<>(); - private HashSet _loggedIn = new HashSet(); - private HashSet _ignoreIds = new HashSet(); + private Set _loggedIn = new HashSet<>(); + private Set _ignoreIds = new HashSet<>(); - private NautHashMap _exemptTimeMap = new NautHashMap(); - private NautHashMap> _doubleStrike = new NautHashMap>(); + private Map _exemptTimeMap = new HashMap<>(); + private Map> _doubleStrike = new HashMap<>(); public CustomTagFix(JavaPlugin plugin, PacketHandler packetHandler) { @@ -79,10 +82,10 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook @EventHandler public void playerQuit(PlayerQuitEvent event) { - _entityMap.remove(event.getPlayer().getName()); - _entityNameMap.remove(event.getPlayer().getName()); - _entityRiding.remove(event.getPlayer().getName()); - _loggedIn.remove(event.getPlayer().getName()); + _entityMap.remove(event.getPlayer().getUniqueId()); + _entityNameMap.remove(event.getPlayer().getUniqueId()); + _entityRiding.remove(event.getPlayer().getUniqueId()); + _loggedIn.remove(event.getPlayer().getUniqueId()); } @EventHandler(priority = EventPriority.LOW) @@ -122,7 +125,7 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook public void ncpExemptVelocity(final PlayerVelocityEvent event) { long ignoreTime = System.currentTimeMillis() + (long) (event.getVelocity().length() * 1500); - + if (_exemptTimeMap.containsKey(event.getPlayer().getUniqueId())) { _exemptTimeMap.put(event.getPlayer().getUniqueId(), @@ -139,7 +142,7 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook if (event.getType() != UpdateType.TICK) return; - for (Iterator> iterator = _exemptTimeMap.entrySet().iterator(); iterator.hasNext();) + for (Iterator> iterator = _exemptTimeMap.entrySet().iterator(); iterator.hasNext(); ) { final Entry entry = iterator.next(); @@ -150,12 +153,12 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook } for (Iterator>> iterator = _doubleStrike.entrySet().iterator(); iterator - .hasNext();) + .hasNext(); ) { Entry> entry = iterator.next(); for (Iterator> innerIterator = entry.getValue().entrySet().iterator(); innerIterator - .hasNext();) + .hasNext(); ) { final Entry entry2 = innerIterator.next(); @@ -176,11 +179,11 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook if (event.getType() != UpdateType.SEC) return; - for (Iterator iterator = _loggedIn.iterator(); iterator.hasNext();) + for (Iterator iterator = _loggedIn.iterator(); iterator.hasNext(); ) { - String player = iterator.next(); + UUID player = iterator.next(); - if (Bukkit.getPlayerExact(player) == null) + if (Bukkit.getPlayer(player) == null) { iterator.remove(); _entityMap.remove(player); @@ -195,7 +198,7 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook } } - @SuppressWarnings("unchecked") + public void handle(PacketInfo packetInfo) { if (packetInfo.isCancelled()) @@ -205,311 +208,84 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook Player owner = packetInfo.getPlayer(); PacketVerifier verifier = packetInfo.getVerifier(); - if (owner.isOnline()) + if (!owner.isOnline()) + // wat + return; + + if (!_entityMap.containsKey(owner.getUniqueId())) { - if (owner.isOnline() && !_entityMap.containsKey(owner.getName())) + _entityMap.put(owner.getUniqueId(), new HashMap<>()); + _entityNameMap.put(owner.getUniqueId(), new HashMap<>()); + _loggedIn.add(owner.getUniqueId()); + } + + if (packet instanceof PacketPlayOutSpawnEntityLiving) + { + PacketPlayOutSpawnEntityLiving spawnPacket = (PacketPlayOutSpawnEntityLiving) packet; + + // Ignore Armor stand packets + if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId() || spawnPacket.l == null || spawnPacket.l.c() == null) { - _entityMap.put(owner.getName(), new NautHashMap()); - _entityNameMap.put(owner.getName(), new NautHashMap()); - _loggedIn.add(owner.getName()); - } - - if (packet instanceof PacketPlayOutSpawnEntityLiving) - { - PacketPlayOutSpawnEntityLiving spawnPacket = (PacketPlayOutSpawnEntityLiving) packet; - - // Ignore Armor stand packets - if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId() || spawnPacket.l == null || spawnPacket.l.c() == null) - { - if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId()) - { - _ignoreIds.add(spawnPacket.a); - } - - return; - } - - for (WatchableObject watchable : (List) spawnPacket.l.c()) - { - if (watchable.a() == 3 && watchable.b() instanceof Byte && ((Byte) watchable.b()) == 1) - { - if (_entityMap.get(owner.getName()).containsKey(spawnPacket.a)) - { - Integer[] ids = _entityMap.get(owner.getName()).get(spawnPacket.a); - int[] newIds = new int[ids.length]; - - for (int a = 0; a < ids.length; a++) - { - newIds[a] = ids[a]; - } - - UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); - - _entityNameMap.get(owner.getName()).remove(spawnPacket.a); - _entityMap.get(owner.getName()).remove(spawnPacket.a); - } - - final String entityName = spawnPacket.l.getString(2); - - if (entityName.isEmpty()) - { - return; - } - - Integer[] ids = new Integer[] - { - UtilEnt.getNewEntityId(), - UtilEnt.getNewEntityId() - }; - - _entityNameMap.get(owner.getName()).put(spawnPacket.a, entityName); - _entityMap.get(owner.getName()).put(spawnPacket.a, ids); - - sendProtocolPackets(owner, spawnPacket.a, entityName, verifier, true, ids); - break; - } - } - } - else if (packet instanceof PacketPlayOutNamedEntitySpawn) - { - PacketPlayOutNamedEntitySpawn spawnPacket = (PacketPlayOutNamedEntitySpawn) packet; - - for (WatchableObject watchable : (List) spawnPacket.i.c()) - { - if (watchable.a() == 3 && watchable.b() instanceof Byte && ((Byte) watchable.b()) == 1) - { - if (_entityMap.get(owner.getName()).containsKey(spawnPacket.a)) - { - Integer[] ids = _entityMap.get(owner.getName()).get(spawnPacket.a); - - int[] newIds = new int[ids.length]; - - for (int a = 0; a < ids.length; a++) - { - newIds[a] = ids[a]; - } - - UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); - - _entityNameMap.get(owner.getName()).remove(spawnPacket.a); - _entityMap.get(owner.getName()).remove(spawnPacket.a); - } - - final String entityName = spawnPacket.i.getString(2); - - if (entityName.isEmpty()) - { - return; - } - - Integer[] ids = new Integer[] - { - UtilEnt.getNewEntityId(), - UtilEnt.getNewEntityId() - }; - - _entityNameMap.get(owner.getName()).put(spawnPacket.a, entityName); - _entityMap.get(owner.getName()).put(spawnPacket.a, ids); - - sendProtocolPackets(owner, spawnPacket.a, entityName, verifier, true, ids); - break; - } - } - } - else if (packet instanceof PacketPlayOutEntityMetadata) - { - PacketPlayOutEntityMetadata metaPacket = (PacketPlayOutEntityMetadata) packet; - - if (metaPacket.a != 777777 && !_ignoreIds.contains(metaPacket.a) && metaPacket.a != owner.getEntityId()) - { - boolean isDisplaying = _entityMap.get(owner.getName()).containsKey(metaPacket.a); - String currentName = _entityNameMap.get(owner.getName()).get(metaPacket.a); - - if (currentName == null) - { - currentName = ""; - } - - String newName = currentName; - boolean displayName = isDisplaying; - - for (WatchableObject watchable : (List) metaPacket.b) - { - if (watchable.a() == 3 && watchable.b() instanceof Byte) - { - displayName = ((Byte) watchable.b()) == 1; - } - - if (watchable.a() == 2 && watchable.b() instanceof String) - { - newName = (String) watchable.b(); - } - } - - // If the name has changed and the name should be showing, or the name display status has changed. - if ((!newName.equals(currentName) && displayName) || displayName != isDisplaying) - { - // If name is still being displayed - if (displayName) - { - Integer[] newId; - - if (isDisplaying) // Sending metadata - { - newId = _entityMap.get(owner.getName()).get(metaPacket.a); - } - else - // Spawning new entity - { - newId = new Integer[] - { - UtilEnt.getNewEntityId(), - UtilEnt.getNewEntityId() - }; - - _entityMap.get(owner.getName()).put(metaPacket.a, newId); - } - - _entityNameMap.get(owner.getName()).put(metaPacket.a, newName); - sendProtocolPackets(owner, metaPacket.a, newName, verifier, !isDisplaying, newId); - } - else - { // Lets delete it - Integer[] ids = _entityMap.get(owner.getName()).get(metaPacket.a); - int[] newIds = new int[ids.length]; - - for (int a = 0; a < ids.length; a++) - { - newIds[a] = ids[a]; - } - - verifier.bypassProcess(new PacketPlayOutEntityDestroy(newIds)); - - _entityMap.get(owner.getName()).remove(metaPacket.a); - _entityNameMap.get(owner.getName()).remove(metaPacket.a); - } - } - } - } - else if (packet instanceof PacketPlayOutEntityDestroy) - { - try - { - for (int id : ((PacketPlayOutEntityDestroy) packet).a) - { - if (_entityMap.get(owner.getName()).containsKey(id)) - { - Integer[] ids = _entityMap.get(owner.getName()).get(id); - int[] newIds = new int[ids.length]; - - for (int a = 0; a < ids.length; a++) - { - newIds[a] = ids[a]; - } - - UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); - _entityMap.get(owner.getName()).remove(id); - _entityNameMap.get(owner.getName()).remove(id); - } - } - } - catch (Exception exception) - { - exception.printStackTrace(); - } - } - else if (packet instanceof PacketPlayOutSpawnEntity) - { - PacketPlayOutSpawnEntity spawnPacket = (PacketPlayOutSpawnEntity) packet; - if (spawnPacket.j == 78) // Armor Stand Object ID + if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId()) { _ignoreIds.add(spawnPacket.a); } + + return; } - else if (packet instanceof PacketPlayInUseEntity) + + for (WatchableObject watchable : (List) spawnPacket.l.c()) { - PacketPlayInUseEntity usePacket = (PacketPlayInUseEntity) packet; - - loop: - - for (Entry entry : _entityMap.get(owner.getName()).entrySet()) + if (watchable.a() == 3 && watchable.b() instanceof Byte && ((Byte) watchable.b()) == 1) { - for (int id : entry.getValue()) + if (_entityMap.get(owner.getUniqueId()).containsKey(spawnPacket.a)) { - if (id == usePacket.a) + Integer[] ids = _entityMap.get(owner.getUniqueId()).get(spawnPacket.a); + int[] newIds = new int[ids.length]; + + for (int a = 0; a < ids.length; a++) { - PacketPlayInUseEntity newPacket = new PacketPlayInUseEntity(); - newPacket.a = entry.getKey(); - newPacket.action = usePacket.action; - newPacket.c = usePacket.c; - - { - ((CraftPlayer) owner).getHandle().playerConnection.a(newPacket); - } - - break loop; + newIds[a] = ids[a]; } + + UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); + + _entityNameMap.get(owner.getUniqueId()).remove(spawnPacket.a); + _entityMap.get(owner.getUniqueId()).remove(spawnPacket.a); } + + final String entityName = spawnPacket.l.getString(2); + + if (entityName.isEmpty()) + { + return; + } + + Integer[] ids = new Integer[] + { + UtilEnt.getNewEntityId(), + UtilEnt.getNewEntityId() + }; + + _entityNameMap.get(owner.getUniqueId()).put(spawnPacket.a, entityName); + _entityMap.get(owner.getUniqueId()).put(spawnPacket.a, ids); + + sendProtocolPackets(owner, spawnPacket.a, entityName, verifier, true, ids); + break; } } - else if (packet instanceof PacketPlayOutAttachEntity || packet instanceof PacketPlayOutNewAttachEntity) + } + else if (packet instanceof PacketPlayOutNamedEntitySpawn) + { + PacketPlayOutNamedEntitySpawn spawnPacket = (PacketPlayOutNamedEntitySpawn) packet; + + for (WatchableObject watchable : (List) spawnPacket.i.c()) { - int vech = -1; - int rider = -1; - - if (packet instanceof PacketPlayOutAttachEntity) + if (watchable.a() == 3 && watchable.b() instanceof Byte && ((Byte) watchable.b()) == 1) { - PacketPlayOutAttachEntity attachPacket = (PacketPlayOutAttachEntity) packet; - vech = attachPacket.b; - rider = attachPacket.c; - } - else if (packet instanceof PacketPlayOutNewAttachEntity) - { - PacketPlayOutNewAttachEntity attachPacket = (PacketPlayOutNewAttachEntity) packet; - vech = attachPacket.a; - - if (attachPacket.b.length > 0) - rider = attachPacket.b[0]; - } - - // c = rider, b = ridden - // When detaching, c is sent, b is -1 - - // If this attach packet is for a player that has the fix - // If the attach packet isn't ordained by me - if (!_entityMap.containsKey(owner.getName())) - { - return; - } - - if (!_entityRiding.containsKey(owner.getName())) - { - _entityRiding.put(owner.getName(), new NautHashMap()); - } - - int vehicleId = -1; - - if (_entityRiding.get(owner.getName()).containsKey(vech)) - { - vehicleId = _entityRiding.get(owner.getName()).get(vech); - } - - if (rider == -1 && _entityMap.get(owner.getName()).containsKey(vehicleId)) - { - Integer[] ids = _entityMap.get(owner.getName()).get(vehicleId); - - _entityRiding.get(owner.getName()).remove(vech); - - sendProtocolPackets(owner, vehicleId, _entityNameMap.get(owner.getName()).get(vehicleId), verifier, true, - ids); - } - else - { - Integer[] ids = _entityMap.get(owner.getName()).get(rider); - - if (ids != null && ids[1] != vech) + if (_entityMap.get(owner.getUniqueId()).containsKey(spawnPacket.a)) { - _entityRiding.get(owner.getName()).put(vech, rider); + Integer[] ids = _entityMap.get(owner.getUniqueId()).get(spawnPacket.a); int[] newIds = new int[ids.length]; @@ -519,14 +295,242 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook } UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); + + _entityNameMap.get(owner.getUniqueId()).remove(spawnPacket.a); + _entityMap.get(owner.getUniqueId()).remove(spawnPacket.a); } + + final String entityName = spawnPacket.i.getString(2); + + if (entityName.isEmpty()) + { + return; + } + + Integer[] ids = new Integer[] + { + UtilEnt.getNewEntityId(), + UtilEnt.getNewEntityId() + }; + + _entityNameMap.get(owner.getUniqueId()).put(spawnPacket.a, entityName); + _entityMap.get(owner.getUniqueId()).put(spawnPacket.a, ids); + + sendProtocolPackets(owner, spawnPacket.a, entityName, verifier, true, ids); + break; + } + } + } + else if (packet instanceof PacketPlayOutEntityMetadata) + { + PacketPlayOutEntityMetadata metaPacket = (PacketPlayOutEntityMetadata) packet; + + if (metaPacket.a != 777777 && !_ignoreIds.contains(metaPacket.a) && metaPacket.a != owner.getEntityId()) + { + boolean isDisplaying = _entityMap.get(owner.getUniqueId()).containsKey(metaPacket.a); + String currentName = _entityNameMap.get(owner.getUniqueId()).get(metaPacket.a); + + if (currentName == null) + { + currentName = ""; + } + + String newName = currentName; + boolean displayName = isDisplaying; + + for (WatchableObject watchable : (List) metaPacket.b) + { + if (watchable.a() == 3 && watchable.b() instanceof Byte) + { + displayName = ((Byte) watchable.b()) == 1; + } + + if (watchable.a() == 2 && watchable.b() instanceof String) + { + newName = (String) watchable.b(); + } + } + + // If the name has changed and the name should be showing, or the name display status has changed. + if ((!newName.equals(currentName) && displayName) || displayName != isDisplaying) + { + // If name is still being displayed + if (displayName) + { + Integer[] newId; + + if (isDisplaying) // Sending metadata + { + newId = _entityMap.get(owner.getUniqueId()).get(metaPacket.a); + } + else + // Spawning new entity + { + newId = new Integer[] + { + UtilEnt.getNewEntityId(), + UtilEnt.getNewEntityId() + }; + + _entityMap.get(owner.getUniqueId()).put(metaPacket.a, newId); + } + + _entityNameMap.get(owner.getUniqueId()).put(metaPacket.a, newName); + sendProtocolPackets(owner, metaPacket.a, newName, verifier, !isDisplaying, newId); + } + else + { // Lets delete it + Integer[] ids = _entityMap.get(owner.getUniqueId()).get(metaPacket.a); + int[] newIds = new int[ids.length]; + + for (int a = 0; a < ids.length; a++) + { + newIds[a] = ids[a]; + } + + verifier.bypassProcess(new PacketPlayOutEntityDestroy(newIds)); + + _entityMap.get(owner.getUniqueId()).remove(metaPacket.a); + _entityNameMap.get(owner.getUniqueId()).remove(metaPacket.a); + } + } + } + } + else if (packet instanceof PacketPlayOutEntityDestroy) + { + try + { + for (int id : ((PacketPlayOutEntityDestroy) packet).a) + { + if (_entityMap.get(owner.getUniqueId()).containsKey(id)) + { + Integer[] ids = _entityMap.get(owner.getUniqueId()).get(id); + int[] newIds = new int[ids.length]; + + for (int a = 0; a < ids.length; a++) + { + newIds[a] = ids[a]; + } + + UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); + _entityMap.get(owner.getUniqueId()).remove(id); + _entityNameMap.get(owner.getUniqueId()).remove(id); + } + } + } + catch (Exception exception) + { + exception.printStackTrace(); + } + } + else if (packet instanceof PacketPlayOutSpawnEntity) + { + PacketPlayOutSpawnEntity spawnPacket = (PacketPlayOutSpawnEntity) packet; + if (spawnPacket.j == 78) // Armor Stand Object ID + { + _ignoreIds.add(spawnPacket.a); + } + } + else if (packet instanceof PacketPlayInUseEntity) + { + PacketPlayInUseEntity usePacket = (PacketPlayInUseEntity) packet; + + loop: + + for (Entry entry : _entityMap.get(owner.getUniqueId()).entrySet()) + { + for (int id : entry.getValue()) + { + if (id == usePacket.a) + { + PacketPlayInUseEntity newPacket = new PacketPlayInUseEntity(); + newPacket.a = entry.getKey(); + newPacket.action = usePacket.action; + newPacket.c = usePacket.c; + + { + ((CraftPlayer) owner).getHandle().playerConnection.a(newPacket); + } + + break loop; + } + } + } + } + else if (packet instanceof PacketPlayOutAttachEntity || packet instanceof PacketPlayOutNewAttachEntity) + { + int vech = -1; + int rider = -1; + + if (packet instanceof PacketPlayOutAttachEntity) + { + PacketPlayOutAttachEntity attachPacket = (PacketPlayOutAttachEntity) packet; + vech = attachPacket.b; + rider = attachPacket.c; + } + else if (packet instanceof PacketPlayOutNewAttachEntity) + { + PacketPlayOutNewAttachEntity attachPacket = (PacketPlayOutNewAttachEntity) packet; + vech = attachPacket.a; + + if (attachPacket.b.length > 0) + rider = attachPacket.b[0]; + } + + // c = rider, b = ridden + // When detaching, c is sent, b is -1 + + // If this attach packet is for a player that has the fix + // If the attach packet isn't ordained by me + if (!_entityMap.containsKey(owner.getUniqueId())) + { + return; + } + + if (!_entityRiding.containsKey(owner.getUniqueId())) + { + _entityRiding.put(owner.getUniqueId(), new HashMap()); + } + + int vehicleId = -1; + + if (_entityRiding.get(owner.getUniqueId()).containsKey(vech)) + { + vehicleId = _entityRiding.get(owner.getUniqueId()).get(vech); + } + + if (rider == -1 && _entityMap.get(owner.getUniqueId()).containsKey(vehicleId)) + { + Integer[] ids = _entityMap.get(owner.getUniqueId()).get(vehicleId); + + _entityRiding.get(owner.getUniqueId()).remove(vech); + + sendProtocolPackets(owner, vehicleId, _entityNameMap.get(owner.getUniqueId()).get(vehicleId), verifier, true, + ids); + } + else + { + Integer[] ids = _entityMap.get(owner.getUniqueId()).get(rider); + + if (ids != null && ids[1] != vech) + { + _entityRiding.get(owner.getUniqueId()).put(vech, rider); + + int[] newIds = new int[ids.length]; + + for (int a = 0; a < ids.length; a++) + { + newIds[a] = ids[a]; + } + + UtilPlayer.sendPacket(owner, new PacketPlayOutEntityDestroy(newIds)); } } } } private void sendProtocolPackets(final Player owner, final int entityId, String entityName, final PacketVerifier packetList, - final boolean newPacket, final Integer[] entityIds) + final boolean newPacket, final Integer[] entityIds) { CustomTagEvent event = new CustomTagEvent(owner, entityId, entityName); _plugin.getServer().getPluginManager().callEvent(event); @@ -565,9 +569,9 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook if (UtilPlayer.is1_9(owner)) { UtilPlayer.sendPacket(owner, new PacketPlayOutNewAttachEntity(entityId, new int[] - { - entityIds[1] - })); + { + entityIds[1] + })); } else { @@ -595,9 +599,9 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook if (UtilPlayer.is1_9(owner)) { UtilPlayer.sendPacket(owner, new PacketPlayOutNewAttachEntity(entityIds[1], new int[] - { - entityIds[0] - })); + { + entityIds[0] + })); } else { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/Managers.java b/Plugins/Mineplex.Core/src/mineplex/core/Managers.java new file mode 100644 index 000000000..f37bfc810 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/Managers.java @@ -0,0 +1,92 @@ +package mineplex.core; + +import mineplex.core.common.util.UtilServer; + +import java.lang.reflect.Constructor; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * This class will manage all the MiniPlugin instances. It's not the best way to do it, but it works given how + * we use MiniPlugins right now, so let's not fret about that + */ +public class Managers +{ + private static final Map, Object> MANAGER_MAP = Collections.synchronizedMap(new HashMap<>()); + + /** + * Gets a Manager ({@link MiniPlugin}) based on its class + * + * @param clazz The class of the MiniPlugin to return + * @return The mapped MiniPlugin, or null if not found + */ + public static T get(Class clazz) + { + Object result = MANAGER_MAP.get(clazz); + return clazz.cast(result); + } + + /** + * Gets the given module, and initializes if necessary + * @param clazz + * @param + * @return + */ + public static T require(Class clazz) + { + if (MANAGER_MAP.containsKey(clazz)) + { + return get(clazz); + } + try + { + ReflectivelyCreateMiniPlugin annotation = clazz.getAnnotation(ReflectivelyCreateMiniPlugin.class); + if (annotation != null) + { + Constructor defaultConstructor = clazz.getDeclaredConstructor(); + defaultConstructor.setAccessible(true); + return defaultConstructor.newInstance(); + } + } + catch (ReflectiveOperationException ex) + { + ex.printStackTrace(System.out); + } + return null; + } + + public static void put(MiniPlugin manager) + { + if (manager == null) throw new NullPointerException("Manager cannot be null"); + if (MANAGER_MAP.containsKey(manager.getClass())) + { + if (!UtilServer.isTestServer()) + { + System.out.println("============== WARNING =============="); + System.out.println(" "); + System.out.println(" "); + System.out.println(" "); + System.out.println("Attempted to register " + manager.getClass().getName() + ", but it was already registered"); + new Exception("Stack trace").printStackTrace(System.out); + System.out.println(" "); + System.out.println(" "); + System.out.println(" "); + System.out.println("============== WARNING =============="); + } + else + { + throw new IllegalArgumentException("Manager " + manager.getClass().getName() + " is already registered"); + } + } + MANAGER_MAP.put(manager.getClass(), manager); + } + + public static void put(MiniPlugin manager, Class extends MiniPlugin> type) + { + if (manager == null) throw new NullPointerException("Manager cannot be null"); + if (!type.isAssignableFrom(manager.getClass())) throw new IllegalArgumentException(manager.getClass().getName() + " is not a subclass of " + type.getName()); + if (MANAGER_MAP.containsKey(type)) throw new IllegalArgumentException("Manager " + type.getName() + " is already registered"); + MANAGER_MAP.put(type, manager); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java index d90d08fe5..c5f2119e1 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/MiniClientPlugin.java @@ -1,19 +1,21 @@ package mineplex.core; -import java.util.Collection; - +import mineplex.core.account.event.ClientUnloadEvent; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.plugin.java.JavaPlugin; -import mineplex.core.account.event.ClientUnloadEvent; -import mineplex.core.common.util.NautHashMap; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; public abstract class MiniClientPlugin extends MiniPlugin { - private static Object _clientDataLock = new Object(); + private static final Object _clientDataLock = new Object(); - private NautHashMap _clientData = new NautHashMap(); + private Map _clientData = new HashMap<>(); public MiniClientPlugin(String moduleName, JavaPlugin plugin) { @@ -26,18 +28,27 @@ public abstract class MiniClientPlugin extends MiniPlug synchronized (_clientDataLock) { saveData(event.GetName(), event.getAccountId()); - _clientData.remove(event.GetName()); + _clientData.remove(event.getUniqueId()); } } - + + @Deprecated public DataType Get(String name) + { + Player player = Bukkit.getPlayerExact(name); + if (player == null) + return null; + return Get(player); + } + + public DataType Get(UUID uuid) { synchronized (_clientDataLock) { - if (!_clientData.containsKey(name)) - _clientData.put(name, addPlayer(name)); - - return _clientData.get(name); + if (!_clientData.containsKey(uuid)) + _clientData.put(uuid, addPlayer(uuid)); + + return _clientData.get(uuid); } } @@ -45,7 +56,7 @@ public abstract class MiniClientPlugin extends MiniPlug public DataType Get(Player player) { - return Get(player.getName()); + return Get(player.getUniqueId()); } protected Collection GetValues() @@ -55,16 +66,16 @@ public abstract class MiniClientPlugin extends MiniPlug protected void Set(Player player, DataType data) { - Set(player.getName(), data); + Set(player.getUniqueId(), data); } - - protected void Set(String name, DataType data) + + protected void Set(UUID uuid, DataType data) { synchronized (_clientDataLock) { - _clientData.put(name, data); + _clientData.put(uuid, data); } } - protected abstract DataType addPlayer(String player); + protected abstract DataType addPlayer(UUID uuid); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/MiniDbClientPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/MiniDbClientPlugin.java index 2f479adeb..52805cdc5 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/MiniDbClientPlugin.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/MiniDbClientPlugin.java @@ -2,6 +2,7 @@ package mineplex.core; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.UUID; import org.bukkit.plugin.java.JavaPlugin; @@ -21,7 +22,7 @@ public abstract class MiniDbClientPlugin extends MiniCl clientManager.addStoredProcedureLoginProcessor(this); } - public abstract void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException; + public abstract void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException; public CoreClientManager getClientManager() { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java index 435f4dcff..80c128715 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/MiniPlugin.java @@ -1,20 +1,30 @@ package mineplex.core; +import mineplex.core.command.CommandCenter; +import mineplex.core.command.ICommand; +import mineplex.core.common.util.F; +import mineplex.core.common.util.NautHashMap; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.UtilTime.TimeUnit; +import mineplex.core.thread.ThreadPool; import org.bukkit.Bukkit; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; -import mineplex.core.command.CommandCenter; -import mineplex.core.command.ICommand; -import mineplex.core.common.util.F; -import mineplex.core.common.util.NautHashMap; -import mineplex.core.common.util.UtilTime; -import mineplex.core.common.util.UtilTime.TimeUnit; -import mineplex.core.thread.ThreadPool; - +/** + * In the future, all implementations of MiniPlugin should only have one constructor: + * + * private MiniPlugin() + * + * MiniPlugins should also not depend on load order. + * + * This way, we can reflectively create them during {@link #require} when they do not exist, leading to much cleaner code + */ public abstract class MiniPlugin implements Listener { protected String _moduleName = "Default"; @@ -23,6 +33,11 @@ public abstract class MiniPlugin implements Listener protected long _initializedTime; + public MiniPlugin(String moduleName) + { + this(moduleName, UtilServer.getPlugin()); + } + public MiniPlugin(String moduleName, JavaPlugin plugin) { _moduleName = moduleName; @@ -30,11 +45,13 @@ public abstract class MiniPlugin implements Listener _initializedTime = System.currentTimeMillis(); - _commands = new NautHashMap(); + _commands = new NautHashMap<>(); onEnable(); registerEvents(this); + + Managers.put(this); } public PluginManager getPluginManager() @@ -111,22 +128,36 @@ public abstract class MiniPlugin implements Listener public void runAsync(Runnable runnable) { - // Instead of using ThreadPool.ASYNC.execute(runnable); } - public void runAsync(Runnable runnable, long time) + public BukkitTask runAsync(Runnable runnable, long time) { - _plugin.getServer().getScheduler().runTaskLaterAsynchronously(_plugin, runnable, time); + return _plugin.getServer().getScheduler().runTaskLaterAsynchronously(_plugin, runnable, time); } - public void runSync(Runnable runnable) + public BukkitTask runAsyncTimer(Runnable runnable, long time, long period) { - _plugin.getServer().getScheduler().runTask(_plugin, runnable); + return _plugin.getServer().getScheduler().runTaskTimerAsynchronously(_plugin, runnable, time, period); } - public void runSyncLater(Runnable runnable, long delay) + public BukkitTask runSync(Runnable runnable) { - _plugin.getServer().getScheduler().runTaskLater(_plugin, runnable, delay); + return _plugin.getServer().getScheduler().runTask(_plugin, runnable); + } + + public BukkitTask runSyncLater(Runnable runnable, long delay) + { + return _plugin.getServer().getScheduler().runTaskLater(_plugin, runnable, delay); + } + + public BukkitTask runSyncTimer(Runnable runnable, long delay, long period) + { + return _plugin.getServer().getScheduler().runTaskTimer(_plugin, runnable, delay, period); + } + + protected T require(Class clazz) + { + return Managers.require(clazz); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/PacketsInteractionFix.java b/Plugins/Mineplex.Core/src/mineplex/core/PacketsInteractionFix.java index 227cba9bb..19d74a4b2 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/PacketsInteractionFix.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/PacketsInteractionFix.java @@ -4,6 +4,8 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; +import java.util.UUID; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.MathHelper; @@ -33,7 +35,7 @@ import mineplex.core.updater.event.UpdateEvent; public class PacketsInteractionFix extends MiniPlugin implements IPacketHandler { - private HashMap> _armorStands = new HashMap>(); + private Map> _armorStands = new HashMap<>(); public PacketsInteractionFix(JavaPlugin plugin, PacketHandler packetHandler) { @@ -46,7 +48,7 @@ public class PacketsInteractionFix extends MiniPlugin implements IPacketHandler @EventHandler public void onQuit(PlayerQuitEvent event) { - _armorStands.remove(event.getPlayer().getName()); + _armorStands.remove(event.getPlayer().getUniqueId()); } @EventHandler @@ -57,13 +59,13 @@ public class PacketsInteractionFix extends MiniPlugin implements IPacketHandler return; } - Iterator itel = _armorStands.keySet().iterator(); + Iterator itel = _armorStands.keySet().iterator(); while (itel.hasNext()) { - String name = itel.next(); + UUID id = itel.next(); - Player player = Bukkit.getPlayerExact(name); + Player player = Bukkit.getPlayer(id); if (player != null) { @@ -89,12 +91,12 @@ public class PacketsInteractionFix extends MiniPlugin implements IPacketHandler return; } - if (!_armorStands.containsKey(player.getName())) + if (!_armorStands.containsKey(player.getUniqueId())) { - _armorStands.put(player.getName(), new HashSet()); + _armorStands.put(player.getUniqueId(), new HashSet()); } - HashSet list = _armorStands.get(player.getName()); + HashSet list = _armorStands.get(player.getUniqueId()); if (packetInfo.getPacket() instanceof PacketPlayOutSpawnEntityLiving) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/PlayerSelector.java b/Plugins/Mineplex.Core/src/mineplex/core/PlayerSelector.java new file mode 100644 index 000000000..7969cf22e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/PlayerSelector.java @@ -0,0 +1,159 @@ +package mineplex.core; + +import mineplex.core.account.CoreClient; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.incognito.IncognitoManager; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * A helper for selecting arbitrary players given a set of conditions + */ +public class PlayerSelector +{ + /** + * Select a random player from all the online players + * + * @return A random player, or null if none matched + */ + public static Player selectPlayer() + { + return selectPlayer(player -> true); + } + + /** + * Select a random player who match the given criterion + * + * @param selector The condition that the players must match against + * @return A random player, or null if none matched + */ + public static Player selectPlayer(Predicate selector) + { + List selected = selectPlayers(selector); + return selected.get(ThreadLocalRandom.current().nextInt(selected.size())); + } + + /** + * Select all the players who match the given criterion + * @param selector The condition that the players must match against + * @return All the players who match + */ + public static List selectPlayers(Predicate selector) + { + return Bukkit.getOnlinePlayers().stream().filter(selector).collect(Collectors.toList()); + } + + /** + * This condition will return true if the player is not vanished, and false if they are. + * + * If the {@link IncognitoManager} is not loaded, then this will return true + */ + public static final Predicate NOT_VANISHED = player -> + { + IncognitoManager manager = Managers.get(IncognitoManager.class); + if (manager == null) + { + return true; + } + return !manager.Get(player).Status; + }; + + /** + * This condition will return true if the player is not spectating, and false if they are + */ + public static final Predicate NOT_SPECTATING = player -> player.getGameMode() != GameMode.SPECTATOR; + + /** + * This condition will return true if the player has one of the given ranks + * + * @param useDisguisedRank Whether to use the disguised rank of the player should they be disguised + * @param ranks The ranks to check + * @return The resulting criterion + */ + public static Predicate hasAnyRank(boolean useDisguisedRank, Rank... ranks) + { + return player -> + { + CoreClientManager coreClientManager = Managers.get(CoreClientManager.class); + if (coreClientManager == null) + { + return true; + } + CoreClient client = coreClientManager.Get(player); + Rank rank = useDisguisedRank ? client.getRealOrDisguisedRank() : client.GetRank(); + + for (Rank requiredRank : ranks) + { + if (rank == requiredRank) + { + return true; + } + } + + return false; + }; + } + + + /** + * This condition will return true if the entity is in the world specified + * @param world The world that the entity must be in + * @return The resulting criterion + */ + public static Predicate inWorld(World world) + { + return entity -> world == null || entity.getWorld().equals(world); + } + + /** + * This will return a {@link Predicate} which will return true if and only if all of the supplied Predicates + * return true + * @param predicates The Predicates to test against + * @return The resulting criterion + */ + @SafeVarargs + public static Predicate and(Predicate... predicates) + { + return t -> + { + for (Predicate predicate : predicates) + { + if (!predicate.test(t)) + { + return false; + } + } + return true; + }; + } + + /** + * This will return a {@link Predicate} which will return true if and only if one of the the supplied Predicates + * return true + * @param predicates The Predicates to test against + * @return The resulting criterion + */ + @SafeVarargs + public static Predicate or(Predicate... predicates) + { + return t -> + { + for (Predicate predicate : predicates) + { + if (predicate.test(t)) + { + return true; + } + } + return false; + }; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/ReflectivelyCreateMiniPlugin.java b/Plugins/Mineplex.Core/src/mineplex/core/ReflectivelyCreateMiniPlugin.java new file mode 100644 index 000000000..18c11d4cf --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/ReflectivelyCreateMiniPlugin.java @@ -0,0 +1,15 @@ +package mineplex.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Simply represents that this {@link MiniPlugin} can be reflectively instantiated with no harm + */ +@Target(value = ElementType.TYPE) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface ReflectivelyCreateMiniPlugin +{ +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClient.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClient.java index 61ccdc618..603281907 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClient.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClient.java @@ -9,51 +9,66 @@ import mineplex.serverdata.Utility; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -public class CoreClient +import java.util.UUID; + +public class CoreClient { - private int _accountId = -1; - private long _networkSessionLoginTime; + private int _accountId = -1; + private long _networkSessionLoginTime; private String _name; - private String _disguisedAs; + private UUID _uuid; private Player _player; private Rank _rank, _lastRank; - private Rank _disguisedRank; private Rank _tempRank, _lastTemp; - private boolean _disguised; - + + /* + * Disguise info + */ + private String _disguisedName; + private String _disguisedSkin; + private UUID _disguisedUUID; + private Rank _disguisedRank; + public CoreClient(Player player) { _player = player; + _uuid = player.getUniqueId(); _name = player.getName(); _networkSessionLoginTime = Utility.currentTimeMillis(); } - - public CoreClient(String name) + + public CoreClient(String name, UUID uuid) { _name = name; + _uuid = uuid; } - public String GetPlayerName() + public UUID getUniqueId() + { + return this._uuid; + } + + public String getName() { return _name; } - + public Player GetPlayer() { return _player; } - - public void SetPlayer(Player player) - { - _player = player; - } - - public int getAccountId() - { - return _accountId; - } - public void Delete() + public void SetPlayer(Player player) + { + _player = player; + } + + public int getAccountId() + { + return _accountId; + } + + public void Delete() { _name = null; _player = null; @@ -63,7 +78,7 @@ public class CoreClient { _accountId = accountId; } - + public Rank GetRank() { return GetRank(false); @@ -73,13 +88,13 @@ public class CoreClient { if (_rank == null) _rank = Rank.ALL; - + if (bypass || _tempRank == null) return _rank; else return _tempRank; } - + public Rank GetLastRank(boolean temp) { if (temp) @@ -100,7 +115,7 @@ public class CoreClient return _lastRank; } } - + public void SetRank(Rank rank, boolean temp) { if (temp) @@ -117,47 +132,70 @@ public class CoreClient _rank = rank; } } - + public long getNetworkSessionLoginTime() { return _networkSessionLoginTime; } - public String getDisguisedAs() + public void undisguise() { - return _disguisedAs; + this._disguisedName = null; + this._disguisedSkin = null; + this._disguisedRank = null; + this._disguisedUUID = null; } - public void setDisguisedAs(String originalName) + public String getDisguisedAs() { - this._disguisedAs = originalName; + return this._disguisedName; } - /** - * Only use this method if the client is actually disguised! - * @return - */ - public Rank getDisguisedRank() { + public String getDisguisedSkin() + { + return this._disguisedSkin; + } + + public Rank getDisguisedRank() + { return _disguisedRank; } - public void setDisguisedRank(Rank disguisedRank) { - this._disguisedRank = disguisedRank; + public UUID getDisguisedAsUUID() + { + return this._disguisedUUID; } - public boolean isDisguised() { - return _disguised; + public boolean isDisguised() + { + if (this._disguisedName == null) + { + return false; + } + return !this._name.equalsIgnoreCase(this._disguisedName); } - public void setDisguised(boolean disguised) { - this._disguised = disguised; + public void disguise(String name, UUID uuid, Rank rank) + { + this._disguisedName = name; + this._disguisedUUID = uuid; + this._disguisedRank = rank; } - public void setNetworkSessionLoginTime(long loginTime) + public Rank getRealOrDisguisedRank() + { + if (this._disguisedRank != null) + { + return this._disguisedRank; + } + return this.GetRank(); + } + + public void setNetworkSessionLoginTime(long loginTime) { _networkSessionLoginTime = loginTime; } - + public void resetTemp() { if (_tempRank != null) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java index e025133f9..dc68fca79 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java @@ -2,12 +2,17 @@ package mineplex.core.account; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import com.google.gson.Gson; @@ -22,13 +27,14 @@ import mineplex.core.account.repository.AccountRepository; import mineplex.core.account.repository.token.ClientToken; import mineplex.core.common.Rank; import mineplex.core.common.util.Callback; -import mineplex.core.common.util.NautHashMap; import mineplex.core.common.util.UUIDFetcher; import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTasks; import mineplex.core.timing.TimingManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.utils.UtilGameProfile; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @@ -43,43 +49,41 @@ import org.bukkit.plugin.java.JavaPlugin; public class CoreClientManager extends MiniPlugin { - private static NautHashMap _clientLoginLock = new NautHashMap(); - + private static final Map CLIENT_LOGIN_LOCKS = new ConcurrentHashMap<>(); + private JavaPlugin _plugin; private AccountRepository _repository; - private NautHashMap _clientList; - private HashSet _duplicateLoginGlitchPreventionList; + private Map _clientList = new HashMap<>(); + private HashSet _duplicateLoginGlitchPreventionList = new HashSet<>(); private List _loginProcessors = new ArrayList<>(); - private Object _clientLock = new Object(); - + private final Object _clientLock = new Object(); + private static AtomicInteger _clientsConnecting = new AtomicInteger(0); private static AtomicInteger _clientsProcessing = new AtomicInteger(0); - + private final Rank WHITELIST_BYPASS; - + public CoreClientManager(JavaPlugin plugin, String webServer) { this(plugin, webServer, Rank.MODERATOR); } - + public CoreClientManager(JavaPlugin plugin, String webServer, Rank whitelistBypass) { super("Client Manager", plugin); - + _plugin = plugin; _repository = new AccountRepository(plugin, webServer); - _clientList = new NautHashMap(); - _duplicateLoginGlitchPreventionList = new HashSet(); - WHITELIST_BYPASS = whitelistBypass; + WHITELIST_BYPASS = whitelistBypass; } - + public AccountRepository getRepository() { return _repository; } - + @Override public void addCommands() { @@ -87,72 +91,71 @@ public class CoreClientManager extends MiniPlugin addCommand(new TestRank(this)); } - public CoreClient Add(String name) + public CoreClient Add(String name, UUID uuid) { - CoreClient newClient = null; - - if (newClient == null) + CoreClient newClient = new CoreClient(name, uuid); + + CoreClient oldClient; + + synchronized (_clientLock) { - newClient = new CoreClient(name); + oldClient = _clientList.put(uuid, newClient); } - - CoreClient oldClient = null; - - synchronized(_clientLock) + + if (oldClient != null) { - oldClient = _clientList.put(name, newClient); + oldClient.Delete(); } - - if (oldClient != null) - { - oldClient.Delete(); - } return newClient; } - public void Del(String name, int accountId) + public void Del(String name, UUID uuid, int accountId) { - synchronized(_clientLock) + synchronized (_clientLock) { - _clientList.remove(name); + _clientList.remove(uuid); } // rawr added account id for custom data - william - _plugin.getServer().getPluginManager().callEvent(new ClientUnloadEvent(name, accountId)); + _plugin.getServer().getPluginManager().callEvent(new ClientUnloadEvent(name, uuid, accountId)); } + @Deprecated public CoreClient Get(String name) { - synchronized(_clientLock) + Player p = Bukkit.getPlayerExact(name); + return Get(p.getUniqueId()); + } + + public CoreClient Get(UUID uuid) + { + synchronized (_clientLock) { - for(CoreClient client : _clientList.values()) - { - if(client.getDisguisedAs() != null) - if(client.getDisguisedAs().equalsIgnoreCase(name)) - return client; - } - CoreClient client = _clientList.get(name); - + CoreClient client = _clientList.get(uuid); + if (client == null) { - client = new CoreClient(name); + Player player = Bukkit.getPlayer(uuid); + if (player != null) + { + client = new CoreClient(player.getName(), uuid); + } + else + { + client = new CoreClient(null, uuid); + } } - + return client; } } - - public boolean Contains(String name) - { - return _clientList.containsKey(name); - } - + public CoreClient Get(Player player) { - return Get(player.getName()); + return Get(player.getUniqueId()); } - + public int getPlayerCountIncludingConnecting() { return Bukkit.getOnlinePlayers().size() + Math.max(0, _clientsConnecting.get()); @@ -160,6 +163,7 @@ public class CoreClientManager extends MiniPlugin /** * Get the databse account id for a player. Requires the player is online + * * @param player * @return */ @@ -185,12 +189,12 @@ public class CoreClientManager extends MiniPlugin e.printStackTrace(); } } - + try { _clientsProcessing.incrementAndGet(); - - if (!LoadClient(Add(event.getName()), event.getUniqueId(), event.getAddress().getHostAddress())) + + if (!LoadClient(Add(event.getName(), event.getUniqueId()), event.getUniqueId(), event.getAddress().getHostAddress())) event.disallow(Result.KICK_OTHER, "There was a problem logging you in."); } catch (Exception exception) @@ -202,8 +206,8 @@ public class CoreClientManager extends MiniPlugin { _clientsProcessing.decrementAndGet(); } - - if (Bukkit.hasWhitelist() && !Get(event.getName()).GetRank().has(WHITELIST_BYPASS)) + + if (Bukkit.hasWhitelist() && !Get(event.getUniqueId()).GetRank().has(WHITELIST_BYPASS)) { for (OfflinePlayer player : Bukkit.getWhitelistedPlayers()) { @@ -212,7 +216,7 @@ public class CoreClientManager extends MiniPlugin return; } } - + event.disallow(Result.KICK_WHITELIST, "You are not whitelisted my friend."); } } @@ -226,93 +230,84 @@ public class CoreClientManager extends MiniPlugin { _repository.getAccountId(uuid, callback); } - + public void loadClientByName(final String playerName, final Runnable runnable) { - Bukkit.getServer().getScheduler().runTaskAsynchronously(getPlugin(), new Runnable() + loadClientByName(playerName, client -> runnable.run()); + } + + public void loadClientByName(String playerName, Consumer loadedClient) + { + runAsync(() -> { - public void run() + AtomicReference loaded = new AtomicReference<>(); + try { - try + ClientToken token = null; + Gson gson = new Gson(); + + // Fails if not in DB and if duplicate. + UUID uuid = loadUUIDFromDB(playerName); + + if (uuid == null) { - ClientToken token = null; - Gson gson = new Gson(); - - // Fails if not in DB and if duplicate. - UUID uuid = loadUUIDFromDB(playerName); - - if (uuid == null) + uuid = UtilGameProfile.getProfileByName(playerName, false, profile -> {}).get().getId(); + } + + String response = ""; + + if (uuid == null) + { + response = _repository.getClientByName(playerName); + } + else + { + response = _repository.getClientByUUID(uuid); + } + + token = gson.fromJson(response, ClientToken.class); + + CoreClient client = Add(playerName, uuid); + client.SetRank(Rank.valueOf(token.Rank), false); + client.setAccountId(_repository.login(_loginProcessors, uuid, client.getName())); + + // JSON sql response + Bukkit.getServer().getPluginManager().callEvent(new ClientWebResponseEvent(response, uuid)); + + if (client.getAccountId() > 0) + { + PlayerInfo playerInfo = PlayerCache.getInstance().getPlayer(uuid); + + if (playerInfo != null) { - try - { - uuid = UUIDFetcher.getUUIDOf(playerName); - } - catch (Exception exception) - { - System.out.println("Error fetching uuid from mojang : " + exception.getMessage()); - } - } - - String response = ""; - - if (uuid == null) - { - response = _repository.getClientByName(playerName); - } - else - { - response = _repository.getClientByUUID(uuid); - } - - token = gson.fromJson(response, ClientToken.class); - - CoreClient client = Add(playerName); - client.SetRank(Rank.valueOf(token.Rank), false); - client.setAccountId(_repository.login(_loginProcessors, uuid, client.GetPlayerName())); - - // JSON sql response - Bukkit.getServer().getPluginManager().callEvent(new ClientWebResponseEvent(response, uuid)); - - if (client.getAccountId() > 0) - { - PlayerInfo playerInfo = PlayerCache.getInstance().getPlayer(uuid); - - if (playerInfo != null) - { - playerInfo.setAccountId(client.getAccountId()); - PlayerCache.getInstance().addPlayer(playerInfo); - } + playerInfo.setAccountId(client.getAccountId()); + PlayerCache.getInstance().addPlayer(playerInfo); } } - catch (Exception exception) - { - exception.printStackTrace(); - } - finally - { - Bukkit.getServer().getScheduler().runTask(getPlugin(), new Runnable() - { - public void run() - { - if (runnable != null) - runnable.run(); - } - }); - } + + loaded.set(client); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + finally + { + UtilTasks.onMainThread(() -> loadedClient.accept(loaded.get())).run(); } }); } - + public void loadClientByNameSync(final String playerName, final Runnable runnable) { try { ClientToken token = null; Gson gson = new Gson(); - + // Fails if not in DB and if duplicate. UUID uuid = loadUUIDFromDB(playerName); - + if (uuid == null) { try @@ -324,9 +319,9 @@ public class CoreClientManager extends MiniPlugin System.out.println("Error fetching uuid from mojang : " + exception.getMessage()); } } - + String response = ""; - + if (uuid == null) { response = _repository.getClientByName(playerName); @@ -335,20 +330,20 @@ public class CoreClientManager extends MiniPlugin { response = _repository.getClientByUUID(uuid); } - - token = gson.fromJson(response, ClientToken.class); - CoreClient client = Add(playerName); - client.SetRank(Rank.valueOf(token.Rank), false); - client.setAccountId(_repository.login(_loginProcessors, uuid, client.GetPlayerName())); - + token = gson.fromJson(response, ClientToken.class); + + CoreClient client = Add(playerName, uuid); + client.SetRank(Rank.valueOf(token.Rank), false); + client.setAccountId(_repository.login(_loginProcessors, uuid, client.getName())); + // JSON sql response Bukkit.getServer().getPluginManager().callEvent(new ClientWebResponseEvent(response, uuid)); - + if (client.getAccountId() > 0) { PlayerInfo playerInfo = PlayerCache.getInstance().getPlayer(uuid); - + if (playerInfo != null) { playerInfo.setAccountId(client.getAccountId()); @@ -358,7 +353,7 @@ public class CoreClientManager extends MiniPlugin } catch (Exception exception) { - exception.printStackTrace(); + exception.printStackTrace(); } finally { @@ -372,13 +367,13 @@ public class CoreClientManager extends MiniPlugin }); } } - + public boolean LoadClient(final CoreClient client, final UUID uuid, String ipAddress) { - TimingManager.start(client.GetPlayerName() + " LoadClient Total."); + TimingManager.start(client.getName() + " LoadClient Total."); long timeStart = System.currentTimeMillis(); - _clientLoginLock.put(client.GetPlayerName(), new Object()); + CLIENT_LOGIN_LOCKS.put(client.getName(), new Object()); ClientToken token = null; Gson gson = new Gson(); @@ -387,33 +382,36 @@ public class CoreClientManager extends MiniPlugin @Override public void run() { - try { - client.setAccountId(_repository.login(_loginProcessors, uuid, client.GetPlayerName())); - } catch (SQLException e) { + try + { + client.setAccountId(_repository.login(_loginProcessors, uuid, client.getName())); + } + catch (SQLException e) + { // TODO Auto-generated catch block e.printStackTrace(); } - _clientLoginLock.remove(client.GetPlayerName()); + CLIENT_LOGIN_LOCKS.remove(client.getName()); } }); - - TimingManager.start(client.GetPlayerName() + " GetClient."); - String response = _repository.GetClient(client.GetPlayerName(), uuid, ipAddress); - TimingManager.stop(client.GetPlayerName() + " GetClient."); - TimingManager.start(client.GetPlayerName() + " Event."); - token = gson.fromJson(response, ClientToken.class); - + TimingManager.start(client.getName() + " GetClient."); + String response = _repository.GetClient(client.getName(), uuid, ipAddress); + TimingManager.stop(client.getName() + " GetClient."); + + TimingManager.start(client.getName() + " Event."); + token = gson.fromJson(response, ClientToken.class); + client.SetRank(Rank.valueOf(token.Rank), false); - + // _repository.updateMysqlRank(uuid.toString(), token.Rank, token.RankPerm, new Timestamp(Date.parse(token.RankExpire)).toString()); - + // JSON sql response Bukkit.getServer().getPluginManager().callEvent(new ClientWebResponseEvent(response, uuid)); - TimingManager.stop(client.GetPlayerName() + " Event."); + TimingManager.stop(client.getName() + " Event."); - TimingManager.start(client.GetPlayerName() + " While Loop."); - while (_clientLoginLock.containsKey(client.GetPlayerName()) && System.currentTimeMillis() - timeStart < 15000) + TimingManager.start(client.getName() + " While Loop."); + while (CLIENT_LOGIN_LOCKS.containsKey(client.getName()) && System.currentTimeMillis() - timeStart < 15000) { try { @@ -424,19 +422,19 @@ public class CoreClientManager extends MiniPlugin e.printStackTrace(); } } - TimingManager.stop(client.GetPlayerName() + " While Loop."); - - if (_clientLoginLock.containsKey(client.GetPlayerName())) + TimingManager.stop(client.getName() + " While Loop."); + + if (CLIENT_LOGIN_LOCKS.containsKey(client.getName())) { System.out.println("MYSQL TOO LONG TO LOGIN...."); } - - TimingManager.stop(client.GetPlayerName() + " LoadClient Total."); - + + TimingManager.stop(client.getName() + " LoadClient Total."); + if (client.getAccountId() > 0) { PlayerInfo playerInfo = PlayerCache.getInstance().getPlayer(uuid); - + if (playerInfo != null) { client.setNetworkSessionLoginTime(playerInfo.getLoginTime()); @@ -444,32 +442,32 @@ public class CoreClientManager extends MiniPlugin PlayerCache.getInstance().addPlayer(playerInfo); } } - - return !_clientLoginLock.containsKey(client.GetPlayerName()); + + return !CLIENT_LOGIN_LOCKS.containsKey(client.getName()); } @EventHandler(priority = EventPriority.LOWEST) public void Login(PlayerLoginEvent event) { - synchronized(_clientLock) + synchronized (_clientLock) { - if (!_clientList.containsKey(event.getPlayer().getName())) + if (!_clientList.containsKey(event.getPlayer().getUniqueId())) { - _clientList.put(event.getPlayer().getName(), new CoreClient(event.getPlayer().getName())); + _clientList.put(event.getPlayer().getUniqueId(), new CoreClient(event.getPlayer().getName(), event.getPlayer().getUniqueId())); } } - CoreClient client = Get(event.getPlayer().getName()); - - if (client == null || client.GetRank() == null) - { - event.disallow(PlayerLoginEvent.Result.KICK_OTHER, "There was an error logging you in. Please reconnect."); - return; - } - - client.SetPlayer(event.getPlayer()); - - // Reserved Slot Check + CoreClient client = Get(event.getPlayer().getUniqueId()); + + if (client == null || client.GetRank() == null) + { + event.disallow(PlayerLoginEvent.Result.KICK_OTHER, "There was an error logging you in. Please reconnect."); + return; + } + + client.SetPlayer(event.getPlayer()); + + // Reserved Slot Check if (Bukkit.getOnlinePlayers().size() >= Bukkit.getServer().getMaxPlayers()) { if (client.GetRank().has(event.getPlayer(), Rank.ULTRA, false)) @@ -478,27 +476,29 @@ public class CoreClientManager extends MiniPlugin event.setResult(PlayerLoginEvent.Result.ALLOWED); return; } - + event.disallow(PlayerLoginEvent.Result.KICK_OTHER, "This server is full and no longer accepts players."); } } - + @EventHandler public void Kick(PlayerKickEvent event) { if (event.getReason().contains("You logged in from another location")) { - _duplicateLoginGlitchPreventionList.add(event.getPlayer().getName()); - Bukkit.getScheduler().runTask(_plugin, new Runnable() { - public void run() { - if(!_clientList.containsKey(event.getPlayer().getName())) return; - Player p = _clientList.get(event.getPlayer().getName()).GetPlayer(); - p.kickPlayer("You're already logged in."); - } + _duplicateLoginGlitchPreventionList.add(event.getPlayer().getUniqueId()); + Bukkit.getScheduler().runTask(_plugin, new Runnable() + { + public void run() + { + if (!_clientList.containsKey(event.getPlayer().getUniqueId())) return; + Player p = _clientList.get(event.getPlayer().getUniqueId()).GetPlayer(); + p.kickPlayer("You're already logged in."); + } }); } } - + @EventHandler(priority = EventPriority.MONITOR) public void Quit(PlayerQuitEvent event) { @@ -509,11 +509,11 @@ public class CoreClientManager extends MiniPlugin // PlayerKick -> old // PlayerQuit -> old // Then it glitches because it added new, but then removed old afterwards since its based on name as key. - - if (!_duplicateLoginGlitchPreventionList.contains(event.getPlayer().getName())) + + if (!_duplicateLoginGlitchPreventionList.contains(event.getPlayer().getUniqueId())) { - Del(event.getPlayer().getName(), _clientList.get(event.getPlayer().getName()).getAccountId()); - _duplicateLoginGlitchPreventionList.remove(event.getPlayer().getName()); + Del(event.getPlayer().getName(), event.getPlayer().getUniqueId(), _clientList.get(event.getPlayer().getUniqueId()).getAccountId()); + _duplicateLoginGlitchPreventionList.remove(event.getPlayer().getUniqueId()); } } @@ -525,14 +525,14 @@ public class CoreClientManager extends MiniPlugin { if (_plugin.getServer().getPlayer(name) != null) { - CoreClient client = Get(name); + CoreClient client = Get(name); client.SetRank(newRank, false); } } }, name, uuid, rank, perm); } - + public void SaveRank(final Callback callback, final String name, final UUID uuid, Rank rank, boolean perm) { _repository.saveRank(new Callback() @@ -541,17 +541,17 @@ public class CoreClientManager extends MiniPlugin { if (_plugin.getServer().getPlayer(name) != null) { - CoreClient client = Get(name); + CoreClient client = Get(name); client.SetRank(newRank, false); } - + if (callback != null) callback.run(newRank); } }, name, uuid, rank, perm); } - + public void checkPlayerNameExact(final Callback callback, final String playerName) { _repository.matchPlayerName(new Callback>() @@ -570,7 +570,7 @@ public class CoreClientManager extends MiniPlugin } }, playerName); } - + public void checkPlayerName(final Player caller, final String playerName, final Callback callback) { _repository.matchPlayerName(new Callback>() @@ -617,51 +617,51 @@ public class CoreClientManager extends MiniPlugin } }, playerName); } - + // DONT USE THIS IN PRODUCTION...its for enjin listener -someone you despise but definitely not me (defek7) public UUID loadUUIDFromDB(String name) { return _repository.getClientUUID(name); } - + @EventHandler public void cleanGlitchedClients(UpdateEvent event) { if (event.getType() != UpdateType.SLOW) return; - - synchronized(_clientLock) + + synchronized (_clientLock) { - for (Iterator> clientIterator = _clientList.entrySet().iterator(); clientIterator.hasNext();) + for (Iterator> clientIterator = _clientList.entrySet().iterator(); clientIterator.hasNext(); ) { CoreClient client = clientIterator.next().getValue(); // rawr, needed this for custom data - william Player clientPlayer = client.GetPlayer(); - + if (clientPlayer != null && !clientPlayer.isOnline()) { clientIterator.remove(); - + if (clientPlayer != null) { - _plugin.getServer().getPluginManager().callEvent(new ClientUnloadEvent(clientPlayer.getName(), client.getAccountId())); + _plugin.getServer().getPluginManager().callEvent(new ClientUnloadEvent(clientPlayer.getName(), clientPlayer.getUniqueId(), client.getAccountId())); } } } } } - + @EventHandler public void debug(UpdateEvent event) { if (event.getType() != UpdateType.SLOWER) return; - + // System.out.println("====="); // System.out.println("Connecting : " + _clientsConnecting.get()); // System.out.println("Processing : " + _clientsProcessing.get()); // System.out.println("====="); } - + public void addStoredProcedureLoginProcessor(ILoginProcessor processor) { _loginProcessors.add(processor); @@ -672,7 +672,7 @@ public class CoreClientManager extends MiniPlugin CoreClient client = Get(player); if (client == null) return false; - + return client.GetRank().has(rank); } } \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/ILoginProcessor.java b/Plugins/Mineplex.Core/src/mineplex/core/account/ILoginProcessor.java index 7c7db7911..6aa25a27b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/ILoginProcessor.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/ILoginProcessor.java @@ -2,12 +2,13 @@ package mineplex.core.account; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.UUID; public interface ILoginProcessor { String getName(); - void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException; + void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException; String getQuery(int accountId, String uuid, String name); } \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/event/ClientUnloadEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/account/event/ClientUnloadEvent.java index d0d2d467a..47325e2c1 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/event/ClientUnloadEvent.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/event/ClientUnloadEvent.java @@ -3,36 +3,45 @@ package mineplex.core.account.event; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import java.util.UUID; + public class ClientUnloadEvent extends Event { - private static final HandlerList handlers = new HandlerList(); - - private String _name; - private int _accountId; + private static final HandlerList handlers = new HandlerList(); - public ClientUnloadEvent(String name, int accountId) - { - _name = name; - _accountId = accountId; - } - - public String GetName() - { - return _name; - } + private String _name; + private UUID _uuid; + private int _accountId; - public int getAccountId() - { - return _accountId; - } + public ClientUnloadEvent(String name, UUID uuid, int accountId) + { + _name = name; + _accountId = accountId; + this._uuid = uuid; + } - public HandlerList getHandlers() - { - return handlers; - } - - public static HandlerList getHandlerList() - { - return handlers; - } + public String GetName() + { + return _name; + } + + public UUID getUniqueId() + { + return this._uuid; + } + + public int getAccountId() + { + return _accountId; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/repository/AccountRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/account/repository/AccountRepository.java index e00cd1b21..daea474e6 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/repository/AccountRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/repository/AccountRepository.java @@ -113,7 +113,7 @@ public class AccountRepository extends MinecraftRepository for (ILoginProcessor loginProcessor : loginProcessors) { - loginProcessor.processLoginResultSet(name, finalId, statement.getResultSet()); + loginProcessor.processLoginResultSet(name, uuid, finalId, statement.getResultSet()); statement.getMoreResults(); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementManager.java b/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementManager.java index 5cdc68527..dbd63549c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementManager.java @@ -18,6 +18,8 @@ import mineplex.core.incognito.IncognitoManager; import mineplex.core.stats.StatsManager; import mineplex.core.stats.event.StatChangeEvent; +import java.util.UUID; + public class AchievementManager extends MiniPlugin { private IncognitoManager _incognitoManager; @@ -44,16 +46,16 @@ public class AchievementManager extends MiniPlugin public AchievementData get(Player player, Achievement type) { - return get(player.getName(), type); + return get(player.getUniqueId(), type); } - public AchievementData get(String playerName, Achievement type) + public AchievementData get(UUID playerUUID, Achievement type) { int exp = 0; for (String stat : type.getStats()) { - exp += _statsManager.Get(playerName).getStat(stat); + exp += _statsManager.Get(playerUUID).getStat(stat); } return type.getLevelData(exp); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java index 2bd3903b3..44430ffdb 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHack.java @@ -1,59 +1,109 @@ package mineplex.core.antihack; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map.Entry; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.GameMode; -import org.bukkit.Material; -import org.bukkit.Sound; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.event.player.PlayerVelocityEvent; -import org.bukkit.event.server.ServerListPingEvent; -import org.bukkit.plugin.java.JavaPlugin; - +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.AtomicDouble; +import com.mineplex.anticheat.api.GameEndEvent; +import com.mineplex.anticheat.api.GameStartEvent; +import com.mineplex.anticheat.api.MineplexLink; +import com.mineplex.anticheat.api.PlayerViolationEvent; +import mineplex.core.Managers; import mineplex.core.MiniPlugin; +import mineplex.core.PlayerSelector; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; import mineplex.core.account.CoreClientManager; +import mineplex.core.antihack.actions.AntiHackAction; +import mineplex.core.antihack.banwave.BanWaveManager; import mineplex.core.antihack.types.Fly; import mineplex.core.antihack.types.Idle; import mineplex.core.antihack.types.Reach; import mineplex.core.antihack.types.Speed; +import mineplex.core.command.CommandBase; import mineplex.core.common.Rank; -import mineplex.core.common.util.C; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilEnt; -import mineplex.core.common.util.UtilInv; -import mineplex.core.common.util.UtilMath; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.*; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguiseBase; import mineplex.core.portal.Portal; import mineplex.core.preferences.PreferencesManager; +import mineplex.core.punish.Category; import mineplex.core.punish.Punish; +import mineplex.core.punish.PunishClient; +import mineplex.core.punish.Punishment; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import mineplex.serverdata.commands.ServerCommandManager; +import net.minecraft.server.v1_8_R3.*; +import org.bukkit.*; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.*; +import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitTask; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Predicate; + +@ReflectivelyCreateMiniPlugin public class AntiHack extends MiniPlugin { - public static AntiHack Instance; + public static final Map CHECKS = ImmutableMap.of( + "Killaura (Type A)", new CheckThresholds("Kill Aura", 25, 50), + "Killaura (Type B)", new CheckThresholds("High CPS", 0, Integer.MAX_VALUE), + "Killaura (Type C)", new CheckThresholds("Reach", Integer.MAX_VALUE, Integer.MAX_VALUE), + "Killaura (Type D)", new CheckThresholds("Kill Aura", 1000, 1500), + "BadPackets", new CheckThresholds("Regen", 1000, 2000) + ); + + public static final String NAME = "Chiss"; + public static final String USER_HAS_BEEN_BANNED = F.main("GWEN", "%s has been banned. I am always watching"); + public static final String USER_HAS_BEEN_BANNED_BANWAVE = USER_HAS_BEEN_BANNED; + + private static final int VL_DIFF_BEFORE_RENOTIFY = 999999; + private static final int MAX_STALKED_PLAYERS = 3; + private static final int STALK_COOLDOWN_TIME_SECONDS = 5; + private static final int MIN_STALK_TIME = 10 * 20; + private static final int MAX_STALK_TIME = 20 * 20; + private static final int MAX_MIN_DIFF = MAX_STALK_TIME - MIN_STALK_TIME; + private static final Function STALK_END_PROBABILITY_EQUATION = x -> + { + return 1.0/ MAX_MIN_DIFF * x; // linear equation with points (0, 0) and (diff, 1) + }; + + private final Cache _cooldown = CacheBuilder.newBuilder() + .concurrencyLevel(1) + .expireAfterWrite(30, TimeUnit.SECONDS) + .build(); + + private final Cache _stalkingCooldown = CacheBuilder.newBuilder() + .concurrencyLevel(1) + .expireAfterWrite(STALK_COOLDOWN_TIME_SECONDS, TimeUnit.SECONDS) + .build(); + private final List _stalking = new ArrayList<>(); + + private final String _thisServer; private boolean _enabled = true; private boolean _strict = false; private boolean _kick = true; - public Punish Punish; - public Portal Portal; - private PreferencesManager _preferences; - private CoreClientManager _clientManager; + public Portal Portal = require(Portal.class); + private PreferencesManager _preferences = require(PreferencesManager.class); + private CoreClientManager _clientManager = require(CoreClientManager.class); //Record Offenses private HashMap>> _offense = new HashMap>>(); @@ -63,16 +113,16 @@ public class AntiHack extends MiniPlugin //Player Info private HashSet _velocityEvent = new HashSet(); - private HashMap _lastMoveEvent = new HashMap(); - + private HashMap _lastMoveEvent = new HashMap(); + private HashSet _hubAttempted = new HashSet(); //Hack Requirements - public int FloatHackTicks = 10; - public int HoverHackTicks = 4; + public int FloatHackTicks = 10; + public int HoverHackTicks = 4; public int RiseHackTicks = 6; public int SpeedHackTicks = 6; - public int IdleTime = 20000; + public int IdleTime = 20000; public int KeepOffensesFor = 30000; @@ -81,19 +131,25 @@ public class AntiHack extends MiniPlugin public ArrayList _movementDetectors; public ArrayList _combatDetectors; - + private AntiHackRepository _repository; - protected AntiHack(JavaPlugin plugin, Punish punish, Portal portal, PreferencesManager preferences, CoreClientManager clientManager) + private List _guardians = new ArrayList<>(); + + private Predicate _filter = player -> true; + + private Set _pendingBan = new HashSet<>(); + + @SuppressWarnings("Convert2streamapi") + private AntiHack() { - super("AntiHack", plugin); + super("AntiHack"); - Punish = punish; - Portal = portal; - _preferences = preferences; - _clientManager = clientManager; + DisguiseManager disguiseManager = require(DisguiseManager.class); - _repository = new AntiHackRepository(plugin.getConfig().getString("serverstatus.name")); + this._thisServer = UtilServer.getServerNameFromConfig(); + + _repository = new AntiHackRepository(this._thisServer); _repository.initialize(); _movementDetectors = new ArrayList(); @@ -102,13 +158,598 @@ public class AntiHack extends MiniPlugin _movementDetectors.add(new Fly(this)); _movementDetectors.add(new Idle(this)); _movementDetectors.add(new Speed(this)); - + _combatDetectors.add(new Reach(this)); + + Bukkit.getServicesManager().register(MineplexLink.class, new MineplexLink() + { + @Override + public EntityType getActiveDisguise(Player player) + { + DisguiseBase disguise = disguiseManager.getActiveDisguise(player); + return disguise != null ? disguise.getDisguiseType() : null; + } + + @Override + public boolean isSpectator(Player player) + { + return UtilPlayer.isSpectator(player); + } + }, this._plugin, ServicePriority.Normal); + + ServerCommandManager.getInstance().registerCommandType(MajorViolationCommand.class, violation -> + { + IChatBaseComponent component = getMinimalMessage(violation); + + for (Player player : Bukkit.getOnlinePlayers()) + { + if (player.getName().equals("Spoobncoobr")) + { + ((CraftPlayer) player).getHandle().sendMessage(getDetailedMessage(violation)); + + } else if (_clientManager.Get(player).GetRank().has(Rank.HELPER) && (violation.getOriginatingServer().equals(_thisServer) || Managers.get(PreferencesManager.class).Get(player).ShowMacReports)) + { + ((CraftPlayer) player).getHandle().sendMessage(component); + } + } + }); + + this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () -> + { + for (AntiHackGuardian guardian : this._guardians) + { + if (guardian.getTarget() != null && !guardian.getTarget().isOnline()) + { + this._stalking.remove(guardian.getTarget().getUniqueId()); + guardian.stopTargeting(); + } + else if (guardian.getTargetingTime() > MIN_STALK_TIME) + { + double threshold = STALK_END_PROBABILITY_EQUATION.apply(guardian.getTargetingTime() - MIN_STALK_TIME); + if (Math.random() <= threshold) + { + this._stalking.remove(guardian.getTarget().getUniqueId()); + _stalkingCooldown.put(guardian.getTarget().getUniqueId(), true); + guardian.stopTargeting(); + } + } + guardian.tick(); + } + }, 0L, 1L); + + this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () -> + { + if (_stalking.size() >= MAX_STALKED_PLAYERS) + { + return; + } + + if (_guardians.size() == 0) + { + return; + } + + List targets = PlayerSelector.selectPlayers(PlayerSelector.and( + PlayerSelector.NOT_VANISHED, + PlayerSelector.hasAnyRank(false, + Rank.ALL, + Rank.ULTRA, + Rank.HERO, + Rank.LEGEND, + Rank.TITAN, + Rank.TWITCH, + Rank.YOUTUBE_SMALL, + Rank.YOUTUBE, + Rank.MEDIA, + Rank.ADMIN, + Rank.DEVELOPER, + Rank.OWNER, + Rank.LT + ), + player -> !_stalking.contains(player.getUniqueId()), + player -> _stalkingCooldown.getIfPresent(player.getUniqueId()) == null, + _filter + )); + + while (_stalking.size() < MAX_STALKED_PLAYERS && targets.size() > 0) + { + Player target = targets.remove(ThreadLocalRandom.current().nextInt(targets.size())); + + int start = ThreadLocalRandom.current().nextInt(_guardians.size()); + + for (int i = start, j = 0; j < _guardians.size(); i++, j++) + { + if (i >= _guardians.size()) + { + i -= _guardians.size(); + } + AntiHackGuardian guardian = _guardians.get(i); + if (!guardian.isTargeting()) + { + guardian.target(target); + _stalking.add(target.getUniqueId()); + break; + } + } + } + }, 0L, 20L); + + require(BanWaveManager.class); } - public static void Initialize(JavaPlugin plugin, Punish punish, Portal portal, PreferencesManager preferences, CoreClientManager clientManager) + private IChatBaseComponent getDetailedMessage(MajorViolationCommand violation) { - Instance = new AntiHack(plugin, punish, portal, preferences, clientManager); + return new ChatComponentText("") + .addSibling( + new ChatComponentText("A") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.AQUA) + .setRandom(true) + ) + ) + .addSibling( + new ChatComponentText(" GWEN > ") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.RED) + .setBold(true) + ) + ) + .addSibling( + new ChatComponentText(violation.getPlayerName()) + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.GOLD) + ) + ) + .addSibling( + new ChatComponentText(" failed " + violation.getHackType() + " VL" + violation.getViolations() + " in server ") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.YELLOW) + ) + ) + .addSibling( + new ChatComponentText( + violation.getOriginatingServer() + ) + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.YELLOW) + .setChatClickable( + new ChatClickable( + ChatClickable.EnumClickAction.RUN_COMMAND, + "/server " + violation.getOriginatingServer() + ) + ) + .setChatHoverable( + new ChatHoverable( + ChatHoverable.EnumHoverAction.SHOW_TEXT, + new ChatComponentText("Teleport to " + violation.getOriginatingServer()) + ) + ) + ) + ) + .addSibling( + new ChatComponentText(": " + violation.getMessage() + ". Please investigate!") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.YELLOW) + ) + ); + } + + private IChatBaseComponent getMinimalMessage(MajorViolationCommand violation) + { + IChatBaseComponent component = new ChatComponentText("") + .addSibling( + new ChatComponentText("A") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.AQUA) + .setRandom(true) + ) + ) + .addSibling( + new ChatComponentText(" GWEN > ") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.RED) + .setBold(true) + ) + ) + .addSibling( + new ChatComponentText(violation.getPlayerName()) + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.GOLD) + ) + ) + .addSibling( + new ChatComponentText(" suspected of ") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.YELLOW) + ) + ) + .addSibling(CHECKS.get(violation.getHackType()).format(violation.getViolations())); + + if (!violation.getOriginatingServer().equals(this._thisServer)) + { + component + .addSibling( + new ChatComponentText(" in ") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.YELLOW) + ) + ) + .addSibling( + new ChatComponentText(violation.getOriginatingServer()) + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.AQUA) + .setChatClickable( + new ChatClickable( + ChatClickable.EnumClickAction.RUN_COMMAND, + "/server " + violation.getOriginatingServer() + ) + ) + .setChatHoverable( + new ChatHoverable( + ChatHoverable.EnumHoverAction.SHOW_TEXT, + new ChatComponentText("Teleport to " + violation.getOriginatingServer()) + ) + ) + ) + ); + } + + return component.addSibling( + new ChatComponentText(". Please investigate!") + .setChatModifier( + new ChatModifier() + .setColor(EnumChatFormat.YELLOW) + ) + ); + } + + public void registerFilter(Predicate filter) + { + if (filter == null) + { + this._filter = player -> true; + } + else + { + this._filter = filter; + } + } + + public void registerGuardian(AntiHackGuardian guardian) + { + this._guardians.add(guardian); + } + + public void clearGuardians() + { + this._guardians.forEach(AntiHackGuardian::remove); + this._guardians.clear(); + this._stalking.clear(); + this._stalkingCooldown.cleanUp(); + } + + public void runBanAnimation(Player player, Runnable after) + { + if (_pendingBan.add(player)) + { + float oldWalkSpeed = player.getWalkSpeed(); + player.setWalkSpeed(0); + player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 999999, -10)); + + double radius = 4; + double heightAdj = 8; + + double baseDeg = 18; + + Location center = player.getLocation().add(0, heightAdj, 0); + AntiHackGuardian north = new AntiHackGuardian(center.clone().add(0, 0, -radius), 0, 0, 0, 0, 0, 0); + AntiHackGuardian east = new AntiHackGuardian(center.clone().add(radius, 0, 0), 0, 0, 0, 0, 0, 0); + AntiHackGuardian south = new AntiHackGuardian(center.clone().add(0, 0, radius), 0, 0, 0, 0, 0, 0); + AntiHackGuardian west = new AntiHackGuardian(center.clone().add(-radius, 0, 0), 0, 0, 0, 0, 0, 0); + + UtilEnt.CreatureLook(east.getEntity(), player); + UtilEnt.CreatureLook(west.getEntity(), player); + UtilEnt.CreatureLook(south.getEntity(), player); + UtilEnt.CreatureLook(north.getEntity(), player); + + Function magic = seconds -> + { + return Math.pow(2, seconds - 5); + }; + + runSyncLater(() -> + { + north.shoot(player); + east.shoot(player); + south.shoot(player); + west.shoot(player); + + // We get 5 seconds, or 100 ticks + AtomicInteger timer = new AtomicInteger(5); + AtomicReference task = new AtomicReference<>(); + + AtomicDouble cNorth = new AtomicDouble(270); + AtomicDouble cEast = new AtomicDouble(0); + AtomicDouble cSouth = new AtomicDouble(90); + AtomicDouble cWest = new AtomicDouble(180); + + task.set(runSyncTimer(() -> + { + timer.getAndIncrement(); + if (timer.get() > 100) + { + task.get().cancel(); + + player.removePotionEffect(PotionEffectType.JUMP); + player.setWalkSpeed(oldWalkSpeed); + Location location = player.getLocation(); + + UtilParticle.PlayParticle(UtilParticle.ParticleType.HUGE_EXPLOSION, player.getLocation(), 3f, 3f, 3f, 0, 32, UtilParticle.ViewDist.MAX, UtilServer.getPlayers()); + + after.run(); + + _pendingBan.remove(player); + + north.shoot(null); + south.shoot(null); + east.shoot(null); + west.shoot(null); + UtilEnt.CreatureLook(north.getEntity(), location); + UtilEnt.CreatureLook(south.getEntity(), location); + UtilEnt.CreatureLook(east.getEntity(), location); + UtilEnt.CreatureLook(west.getEntity(), location); + runSyncLater(() -> + { + north.remove(); + south.remove(); + east.remove(); + west.remove(); + }, 40L); + return; + } + + double seconds = timer.get() / 20.0; + + double rate = magic.apply(seconds) * 3 * baseDeg; + + player.getLocation(center); + center.add(0, heightAdj, 0); + + { + cNorth.addAndGet(rate); + north.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cNorth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cNorth.get()))); + } + { + cSouth.addAndGet(rate); + south.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cSouth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cSouth.get()))); + } + { + cEast.addAndGet(rate); + east.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cEast.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cEast.get()))); + } + { + cWest.addAndGet(rate); + west.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cWest.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cWest.get()))); + } + }, 5, 1)); + }, 20); + } + } + + public void doBan(Player player, String message) + { + runSync(() -> + { + CoreClient coreClient = _clientManager.Get(player); + + if (coreClient.GetRank().has(Rank.TWITCH)) + { + require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, 3, true, -1, true); + } + else + { + runBanAnimation(player, () -> + { + require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, 3, true, -1, true); + announceBan(player); + }); + } + }); + } + + public void doBanWave(Player player, String message) + { + runSync(() -> + { + int totalPunishments = getPunishments(player); + int daysBanned = getDaysBanned(player); + CoreClient coreClient = _clientManager.Get(player); + if (coreClient.GetRank().has(Rank.TWITCH)) + { + require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, totalPunishments + 1, true, daysBanned == -1 ? -1 : TimeUnit.DAYS.toHours(daysBanned), true); + } + else + { + runBanAnimation(player, () -> + { + require(Punish.class).AddPunishment(coreClient.getName(), Category.Hacking, message, AntiHack.NAME, totalPunishments + 1, true, daysBanned == -1 ? -1 : TimeUnit.DAYS.toHours(daysBanned), true); + announceBanwave(player); + }); + } + }); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void on(PlayerMoveEvent event) + { + if (_pendingBan.contains(event.getPlayer()) && UtilMath.offset2d(event.getFrom().getBlock().getLocation(), event.getTo().getBlock().getLocation()) >= 1) + { + event.setCancelled(true); + event.getPlayer().teleport(event.getFrom().getBlock().getLocation().add(0, 1, 0)); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void on(PlayerInteractEvent event) + { + if (_pendingBan.contains(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void on(PlayerToggleFlightEvent event) + { + if (_pendingBan.contains(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void on(PlayerCommandPreprocessEvent event) + { + if (_pendingBan.contains(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void on(PlayerViolationEvent event) + { + AntiHackAction.getAction(event.getCheckClass()).handle(event); + } + + public void announceBan(Player player) + { + Bukkit.getServer().broadcastMessage(String.format(USER_HAS_BEEN_BANNED, player.getName())); + } + + public void announceBanwave(Player player) + { + Bukkit.getServer().broadcastMessage(String.format(USER_HAS_BEEN_BANNED_BANWAVE, player.getName())); + } + + public int getPunishments(Player player) + { + PunishClient punishClient = require(Punish.class).GetClient(player.getName()); + + int totalPunishments = 0; + + if (punishClient.GetPunishments().containsKey(Category.Hacking)) + { + for (Punishment punishment : punishClient.GetPunishments().get(Category.Hacking)) + { + if (punishment.GetAdmin().equalsIgnoreCase(NAME)) + { + totalPunishments++; + } + } + } + + return totalPunishments; + } + + public int getDaysBanned(Player player) + { + int totalPunishments = getPunishments(player); + + int daysBanned = 0; + + switch (totalPunishments) + { + case 0: + daysBanned = 7; + break; + case 1: + daysBanned = 30; + break; + case 2: + default: + daysBanned = -1; + } + + return daysBanned; + } + + @Override + public void addCommands() + { + if (UtilServer.isTestServer()) + { + addCommand(new CommandBase(this, Rank.DEVELOPER, "acon") + { + @Override + public void Execute(Player caller, String[] args) + { + if (caller.getUniqueId().toString().equals("b86b54da-93dd-46f9-be33-27bd92aa36d7")) + { + enableNewAnticheat(); + UtilPlayer.message(caller, F.main(getName(), "Enabled new anticheat")); + } + } + }); + addCommand(new CommandBase(this, Rank.DEVELOPER, "acoff") + { + @Override + public void Execute(Player caller, String[] args) + { + if (caller.getUniqueId().toString().equals("b86b54da-93dd-46f9-be33-27bd92aa36d7")) + { + disableNewAnticheat(); + UtilPlayer.message(caller, F.main(getName(), "Disabled new anticheat")); + } + } + }); + addCommand(new CommandBase(this, Rank.DEVELOPER, "testban") + { + @Override + public void Execute(Player caller, String[] args) + { + if (caller.getUniqueId().toString().equals("b86b54da-93dd-46f9-be33-27bd92aa36d7")) + { + if (args.length > 0) + { + Player p = Bukkit.getPlayerExact(args[0]); + if (p != null) + { + runBanAnimation(p, () -> + { + String reason = C.cRed + C.Bold + "You are banned for permanent by " + NAME + + "\n" + C.cWhite + "Seems to be speeding up time. (" + ThreadLocalRandom.current().nextInt(200, 400) + " packets/150 ms)" + + "\n" + C.cDGreen + "Unfairly banned? Appeal at " + C.cGreen + "www.mineplex.com/appeals"; + p.kickPlayer(reason); + + announceBan(p); + }); + } + else + { + UtilPlayer.message(caller, F.main(getName(), "Could not find player")); + } + } + else + { + UtilPlayer.message(caller, F.main(getName(), "No player specified")); + } + } + } + }); + } } @EventHandler @@ -193,17 +834,17 @@ public class AntiHack extends MiniPlugin { if (player.equals(other)) continue; - + if (other.getGameMode() != GameMode.SURVIVAL || UtilPlayer.isSpectator(player)) continue; - + if (other.getVehicle() != null) continue; - + if (UtilMath.offset(player, other) < 2) return true; } - + if (player.isFlying() || ((CraftPlayer) player).getHandle().isGliding() || player.isInsideVehicle() || player.getGameMode() != GameMode.SURVIVAL || UtilPlayer.isSpectator(player)) { return true; @@ -263,16 +904,8 @@ public class AntiHack extends MiniPlugin total += _offense.get(player).get(curType).size(); } - - //Inform - for (Player admin : UtilServer.getPlayers()) - if (_clientManager.Get(admin).GetRank().has(Rank.MODERATOR) && _preferences.Get(admin).ShowMacReports) - { - UtilPlayer.message(admin, "#" + total + ": " + C.cRed + C.Bold + player.getName() + " suspected for " + type + "."); - } - // Print (Debug) - System.out.println("[Offense] #" + total + ": "+ player.getName() + " received suspicion for " + type + "."); + System.out.println("[Offense] #" + total + ": " + player.getName() + " received suspicion for " + type + "."); } @EventHandler @@ -284,11 +917,11 @@ public class AntiHack extends MiniPlugin if (event.getType() != UpdateType.SEC) return; - for (Iterator>>> playerIterator = _offense.entrySet().iterator(); playerIterator.hasNext();) + for (Iterator>>> playerIterator = _offense.entrySet().iterator(); playerIterator.hasNext(); ) { Entry>> entry = playerIterator.next(); Player player = entry.getKey(); - + String out = ""; int total = 0; @@ -315,7 +948,7 @@ public class AntiHack extends MiniPlugin out = out.substring(0, out.length() - 2); String severity = "Low"; - + if (total > (_strict ? 6 : 18)) severity = "Extreme"; else if (total > (_strict ? 4 : 12)) @@ -325,7 +958,7 @@ public class AntiHack extends MiniPlugin //Send Report sendReport(player, out, severity); - + if (severity.equalsIgnoreCase("Extreme")) { playerIterator.remove(); @@ -334,6 +967,32 @@ public class AntiHack extends MiniPlugin } } + @EventHandler + public void onHack(PlayerViolationEvent event) + { + if (event.shouldTellStaff()) + { + String key = event.getPlayer().getName() + "." + event.getHackType() + "." + CHECKS.get(event.getHackType()).getSeverity(event.getViolations()).toString(); + Integer pastVl = this._cooldown.getIfPresent(key); + if (pastVl != null) + { + if (event.getViolations() - pastVl > VL_DIFF_BEFORE_RENOTIFY) + { + this._cooldown.put(key, event.getViolations()); + MajorViolationCommand command = new MajorViolationCommand(_thisServer, event.getPlayer().getName(), event.getHackType(), event.getViolations(), event.getMessage()); + ServerCommandManager.getInstance().publishCommand(command); + } + } + else + { + MajorViolationCommand command = new MajorViolationCommand(_thisServer, event.getPlayer().getName(), event.getHackType(), event.getViolations(), event.getMessage()); + ServerCommandManager.getInstance().publishCommand(command); + + this._cooldown.put(key, event.getViolations()); + } + } + } + public void sendReport(Player player, String report, String severity) { if (severity.equals("Extreme")) @@ -351,42 +1010,6 @@ public class AntiHack extends MiniPlugin } } - //Auto-Kick - if (!handled && - _clientManager.Get(player).GetRank() != Rank.YOUTUBE && - _clientManager.Get(player).GetRank() != Rank.YOUTUBE_SMALL && - _clientManager.Get(player).GetRank() != Rank.TWITCH) - { - player.playSound(player.getLocation(), Sound.ENDERDRAGON_GROWL, 2f, 0.5f); - - if (_kick || _hubAttempted.remove(player)) - { - player.kickPlayer( - C.cGold + "Mineplex Anti-Cheat" + "\n" + - C.cWhite + "You were kicked for suspicious movement." + "\n" + - C.cWhite + "Cheating may result in a " + C.cRed + "Permanent Ban" + C.cWhite + "." + "\n" + - C.cWhite + "If you were not cheating, you will not be banned." - ); - } - else - { - _hubAttempted.add(player); - - UtilPlayer.message(player, C.cGold + C.Strike + "---------------------------------------------"); - UtilPlayer.message(player, ""); - UtilPlayer.message(player, C.cGold + "Mineplex Anti-Cheat"); - UtilPlayer.message(player, ""); - UtilPlayer.message(player, "You were kicked from the game for suspicious movement."); - UtilPlayer.message(player, "Cheating may result in a " + C.cRed + "Permanent Ban" + C.cWhite + "."); - UtilPlayer.message(player, "If you were not cheating, you will not be banned."); - UtilPlayer.message(player, ""); - UtilPlayer.message(player, C.cGold + C.Strike + "---------------------------------------------"); - Portal.sendPlayerToServer(player, "Lobby"); - } - - UtilServer.broadcast(F.main("MAC", player.getName() + " was kicked for suspicious movement.")); - } - //Record ServerListPingEvent event = new ServerListPingEvent(null, Bukkit.getServer().getMotd(), Bukkit.getServer().getOnlinePlayers().size(), Bukkit.getServer().getMaxPlayers()); getPluginManager().callEvent(event); @@ -420,7 +1043,7 @@ public class AntiHack extends MiniPlugin { resetAll(player, true); } - + private void resetAll(Player player, boolean removeOffenses) { _ignore.remove(player); @@ -432,7 +1055,7 @@ public class AntiHack extends MiniPlugin for (Detector detector : _movementDetectors) detector.Reset(player); - + for (Detector detector : _combatDetectors) detector.Reset(player); } @@ -446,12 +1069,12 @@ public class AntiHack extends MiniPlugin if (event.getType() != UpdateType.SLOW) return; - for (Iterator> playerIterator = _ignore.entrySet().iterator(); playerIterator.hasNext();) + for (Iterator> playerIterator = _ignore.entrySet().iterator(); playerIterator.hasNext(); ) { Player player = playerIterator.next().getKey(); if (!player.isOnline() || player.isDead() || !player.isValid()) - { + { playerIterator.remove(); _velocityEvent.remove(player); @@ -461,19 +1084,19 @@ public class AntiHack extends MiniPlugin for (Detector detector : _movementDetectors) detector.Reset(player); - + for (Detector detector : _combatDetectors) detector.Reset(player); } } - - for (Iterator playerIterator = _hubAttempted.iterator(); playerIterator.hasNext();) + + for (Iterator playerIterator = _hubAttempted.iterator(); playerIterator.hasNext(); ) { Player player = playerIterator.next(); if (!player.isOnline() || !player.isValid()) - { + { playerIterator.remove(); } } @@ -503,11 +1126,23 @@ public class AntiHack extends MiniPlugin { return _strict; } - + public void setKick(boolean kick) { _kick = kick; System.out.println("MAC Kick: " + kick); } + + public void enableNewAnticheat() + { + UtilServer.CallEvent(new GameStartEvent()); + System.out.println("Enabled new anticheat"); + } + + public void disableNewAnticheat() + { + UtilServer.CallEvent(new GameEndEvent()); + System.out.println("Disabled new anticheat"); + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackGuardian.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackGuardian.java new file mode 100644 index 000000000..4f9da5912 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/AntiHackGuardian.java @@ -0,0 +1,395 @@ +package mineplex.core.antihack; + +import com.mineplex.spigot.ChunkAddEntityEvent; +import mineplex.core.Managers; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilServer; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguiseGuardian; +import mineplex.core.event.StackerEvent; +import net.minecraft.server.v1_8_R3.EntityArmorStand; +import net.minecraft.server.v1_8_R3.EntityPlayer; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftArmorStand; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.util.Vector; + +import java.util.Random; +import java.util.UUID; +import java.util.function.Function; + +public class AntiHackGuardian implements Listener +{ + private static final boolean DEBUG = false; + + private static final double DELTA_MOVE_PER_TICK = 0.2; + + private static final Function MAGICAL_FUNCTION = in -> + { + return Math.pow(100, in - 1); + }; + + protected Random _random = new Random(); + + private Location _center; + + private double _targetX; + private double _targetY; + private double _targetZ; + + private int _ticksUntilReset; + + private ArmorStand _armorStand; + private EntityArmorStand _nmsEntity; + + private DisguiseGuardian _disguise; + + private UUID _entityUUID; + + private Player _target; + private int _stalkTime; + + private final double MAX_DISTANCE_X; + private final double MIN_DISTANCE_X; + private final double MAX_DISTANCE_Y; + private final double MIN_DISTANCE_Y; + private final double MAX_DISTANCE_Z; + private final double MIN_DISTANCE_Z; + + private final double CENTER_X; + private final double CENTER_Y; + private final double CENTER_Z; + + public AntiHackGuardian(Location center, int maxX, int minX, int maxY, int minY, int maxZ, int minZ) + { + UtilServer.RegisterEvents(this); + + this.MAX_DISTANCE_X = maxX; + this.MIN_DISTANCE_X = minX; + this.MAX_DISTANCE_Y = maxY; + this.MIN_DISTANCE_Y = minY; + this.MAX_DISTANCE_Z = maxZ; + this.MIN_DISTANCE_Z = minZ; + + this.CENTER_X = MIN_DISTANCE_X + ((MAX_DISTANCE_X - MIN_DISTANCE_X) / 2.0); + this.CENTER_Y = MIN_DISTANCE_Y + ((MAX_DISTANCE_Y - MIN_DISTANCE_Y) / 2.0); + this.CENTER_Z = MIN_DISTANCE_Z + ((MAX_DISTANCE_Z - MIN_DISTANCE_Z) / 2.0); + + //debug("Spawning ArmorStand at " + center + ""); + + CoreClientManager clientManager = Managers.get(CoreClientManager.class); + DisguiseManager disguiseManager = Managers.get(DisguiseManager.class); + + this._center = center; + this._center.getChunk().load(); + + this._armorStand = (ArmorStand) new EntityArmorStand(((CraftWorld) this._center.getWorld()).getHandle(), this._center.getX(), this._center.getY(), this._center.getZ()).getBukkitEntity(); + this._armorStand.setGravity(false); + this._armorStand.setVisible(false); + this._armorStand.setRemoveWhenFarAway(false); + this._nmsEntity = ((CraftArmorStand) this._armorStand).getHandle(); + this._nmsEntity.maxNoDamageTicks = 86400; + this._nmsEntity.noDamageTicks = 86400; + + this._entityUUID = this._armorStand.getUniqueId(); + + this._disguise = new DisguiseGuardian(this._armorStand); + this._disguise.setHideIfNotDisguised(true); + + disguiseManager.disguise(this._disguise, player -> + { + // Don't let Builder -> Admin see it + Rank rank = clientManager.Get(player).GetRank(); + if (rank.has(Rank.MAPDEV)) + { + if (!rank.has(Rank.ADMIN)) + { + return false; + } + } + if (rank == Rank.EVENT) + return false; + return true; + }); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false) + public void onSpawn(EntitySpawnEvent event) + { + if (event.getEntity() instanceof ArmorStand) + { + event.setCancelled(false); + } + } + + @EventHandler + public void onLoad(ChunkAddEntityEvent event) + { + if (event.getEntity().getUniqueId().equals(this._entityUUID)) + { + this._armorStand = (ArmorStand) event.getEntity(); + this._nmsEntity = ((CraftArmorStand) this._armorStand).getHandle(); + } + } + + @EventHandler + public void onStack(StackerEvent event) + { + if (event.getEntity().getUniqueId().equals(this._entityUUID)) + { + event.setCancelled(true); + } + } + + public void tick() + { + if (this._nmsEntity.dead || !this._nmsEntity.valid) + { + //debug("Skipping because " + this._armorStand.isDead() + " " + this._armorStand.isValid()); + return; + } + + if (this._target == null) + { + regularTick(); + } + else + { + this._stalkTime++; + targetTick(); + } + //debug("Ticking " + this._armorStand + " " + this._armorStand.isDead() + " " + this._armorStand.getLocation() + " " + this._ticksUntilReset); + } + + private void regularTick() + { + if (this._ticksUntilReset <= 0) + { + reset(); + } + + //debug("===== Begin Calculations ====="); + + + //debug("Target: " + this._targetX + " " + this._targetY + " " + this._targetZ); + //debug("Start: " + this._armorStand.getLocation()); + double deltaX = _targetX - _nmsEntity.locX; + double deltaY = _targetY - _nmsEntity.locY; + double deltaZ = _targetZ - _nmsEntity.locZ; + + //debug("Delta Location: " + deltaX + " " + deltaY + " "+ deltaZ); + + double dx = 0; + if (deltaX > 0.1) dx = DELTA_MOVE_PER_TICK; + else if (deltaX < -0.1) dx = -DELTA_MOVE_PER_TICK; + double dy = 0; + if (deltaY > 0.1) dy = DELTA_MOVE_PER_TICK; + else if (deltaY < -0.1) dy = -DELTA_MOVE_PER_TICK; + double dz = 0; + if (deltaZ > 0.1) dz = DELTA_MOVE_PER_TICK; + else if (deltaZ < -0.1) dz = -DELTA_MOVE_PER_TICK; + + + _nmsEntity.locX += dx; + _nmsEntity.locY += dy; + _nmsEntity.locZ += dz; + + //debug("Dest: " + this._nmsEntity.locX + " " + this._nmsEntity.locY + " " + this._nmsEntity.locZ); + //debug("===== End Calculations ====="); + + // Only send look update every second + if (this._nmsEntity.ticksLived % 20 == 0) + { + UtilEnt.CreatureLook(_armorStand, _nmsEntity.locX, _nmsEntity.locY, _nmsEntity.locZ, _targetX, _targetY, _targetZ); + } + + this._ticksUntilReset--; + } + + private void targetTick() + { + //debug("===== Stalking " + this._target.getName() + " ====="); + EntityPlayer entityPlayer = ((CraftPlayer) this._target).getHandle(); + + Vector direction = this._target.getLocation().getDirection().normalize().multiply(-6); + + this._nmsEntity.locX = entityPlayer.locX + direction.getX(); + this._nmsEntity.locZ = entityPlayer.locZ + direction.getZ(); + this._nmsEntity.locY = entityPlayer.locY + 10.0 + nextDouble(-1.0, 1.0); + + UtilEnt.CreatureLook(_armorStand, _nmsEntity.locX, _nmsEntity.locY, _nmsEntity.locZ, entityPlayer.locX, entityPlayer.locY, entityPlayer.locZ); + } + + public void reset() + { + //debug("======= BEGIN RESET ======"); + final double x = _nmsEntity.locX; + final double y = _nmsEntity.locY; + final double z = _nmsEntity.locZ; + + double cx = 0, cy = 0, cz = 0; + if (x > CENTER_X) + cx = (x - CENTER_X) / (MAX_DISTANCE_X - CENTER_X); + else if (x < CENTER_X) + cx = (CENTER_X - x) / (CENTER_X - MIN_DISTANCE_X); + if (y > CENTER_Y) + cy = (y - CENTER_Y) / (MAX_DISTANCE_Y - CENTER_Y); + else if (y < CENTER_Y) + cy = (CENTER_Y - y) / (CENTER_Y - MIN_DISTANCE_Y); + if (z > CENTER_Z) + cz = (z - CENTER_Z) / (MAX_DISTANCE_Z - CENTER_Z); + else if (z < CENTER_Z) + cz = (CENTER_Z - z) / (CENTER_Z - MIN_DISTANCE_Z); + + cx = MAGICAL_FUNCTION.apply(cx) * (x > CENTER_X ? -(MAX_DISTANCE_X - CENTER_X) : (CENTER_X - MIN_DISTANCE_X)); + cy = MAGICAL_FUNCTION.apply(cy) * (y > CENTER_Y ? -(MAX_DISTANCE_Y - CENTER_Y) : (CENTER_Y - MIN_DISTANCE_Y)); + cz = MAGICAL_FUNCTION.apply(cz) * (z > CENTER_Z ? -(MAX_DISTANCE_Z - CENTER_Z) : (CENTER_Z - MIN_DISTANCE_Z)); + + //debug("Start: " + this._armorStand.getLocation()); + //debug("Changes: " + cx + " " + cy + " " + cz); + + int ex = nextInt(8, 12); + int ey = nextInt(0, 3); + int ez = nextInt(8, 12); + + if (_random.nextBoolean()) + ex = -ex; + if (_random.nextBoolean()) + ey = -ey; + if (_random.nextBoolean()) + ez = -ez; + + ex += cx; + ey += cy; + ez += cz; + + int dx = ex; + int dy = ey; + int dz = ez; + + //debug("Deltas: " + dx + " " + dy + " " + dz); + + this._targetX = x + dx; + this._targetY = y + dy; + this._targetZ = z + dz; + //debug("End: " + this._targetX + " " + this._targetY + " " + this._targetZ); + + + // If we can't find a good position, just go to the center + if (!locCheck()) + { + this._targetX = CENTER_X; + this._targetY = CENTER_Y; + this._targetZ = CENTER_Z; + + dx = (int) (CENTER_X - x); + dy = (int) (CENTER_Y - y); + dz = (int) (CENTER_Z - z); + } + + double maxDelta = Math.max(Math.max(Math.abs(dx), Math.abs(dy)), Math.abs(dz)); + + this._ticksUntilReset = (int) (maxDelta / DELTA_MOVE_PER_TICK); + + // Send look update for new target + UtilEnt.CreatureLook(_armorStand, _nmsEntity.locX, _nmsEntity.locY, _nmsEntity.locZ, _targetX, _targetY, _targetZ); + + //debug("Ticks: " + this._ticksUntilReset); + //debug("======= END RESET ======"); + } + + public void target(Player player) + { + this._target = player; + } + + public boolean isTargeting() + { + return this._target != null; + } + + public int getTargetingTime() + { + return this._stalkTime; + } + + public void stopTargeting() + { + this._target = null; + this._stalkTime = 0; + reset(); + } + + public void shoot(Player player) + { + this._disguise.setTarget(player == null ? 0 : player.getEntityId()); + Managers.get(DisguiseManager.class).updateDisguise(this._disguise); + } + + public Player getTarget() + { + return this._target; + } + + private boolean locCheck() + { + if (_targetX >= MAX_DISTANCE_X || + _targetX <= MIN_DISTANCE_X || + _targetY >= MAX_DISTANCE_Y || + _targetY <= MIN_DISTANCE_Y || + _targetZ >= MAX_DISTANCE_Z || + _targetZ <= MIN_DISTANCE_Z) + return false; + return true; + } + + public int nextInt(int lower, int upper) + { + return _random.nextInt(1 + upper - lower) + lower; + } + + public double nextDouble(double lower, double upper) + { + return lower + (upper - lower) * _random.nextDouble(); + } + + public void debug(String s) + { + if (DEBUG) System.out.println(s); + } + + public void remove() + { + this._armorStand.remove(); + this._target = null; + Managers.get(DisguiseManager.class).undisguise(this._disguise); + } + + public ArmorStand getEntity() + { + return this._armorStand; + } + + public void moveDelta(double dx, double dy, double dz) + { + this._nmsEntity.locX += dx; + this._nmsEntity.locY += dy; + this._nmsEntity.locZ += dz; + } + + public void move(double x, double y, double z) + { + this._nmsEntity.locX = x; + this._nmsEntity.locY = y; + this._nmsEntity.locZ = z; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java new file mode 100644 index 000000000..b00207db6 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/CheckThresholds.java @@ -0,0 +1,61 @@ +package mineplex.core.antihack; + +import net.minecraft.server.v1_8_R3.ChatComponentText; +import net.minecraft.server.v1_8_R3.ChatModifier; +import net.minecraft.server.v1_8_R3.EnumChatFormat; +import net.minecraft.server.v1_8_R3.IChatBaseComponent; + +public class CheckThresholds +{ + private final String _friendlyName; + private final int _med; + private final int _high; + + public CheckThresholds(String friendlyName, int med, int high) + { + _friendlyName = friendlyName; + _med = med; + _high = high; + } + + public String getFriendlyName() + { + return _friendlyName; + } + + public IChatBaseComponent format(int violationLevel) + { + EnumChatFormat color = getSeverity(violationLevel)._color; + return new ChatComponentText(_friendlyName).setChatModifier(new ChatModifier().setColor(color)); + } + + public Severity getSeverity(int violationLevel) + { + if (violationLevel >= _high) + { + return Severity.HIGH; + + } else if (violationLevel >= _med) + { + return Severity.MEDIUM; + + } else + { + return Severity.LOW; + } + } + + public enum Severity + { + LOW(EnumChatFormat.GREEN), + MEDIUM(EnumChatFormat.GOLD), + HIGH(EnumChatFormat.RED), + ; + private final EnumChatFormat _color; + + Severity(EnumChatFormat color) + { + _color = color; + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/MajorViolationCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/MajorViolationCommand.java new file mode 100644 index 000000000..8ed58a419 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/MajorViolationCommand.java @@ -0,0 +1,46 @@ +package mineplex.core.antihack; + +import mineplex.serverdata.commands.ServerCommand; + +public class MajorViolationCommand extends ServerCommand +{ + private final String _thisServer; + private final String _playerName; + private final String _hackType; + private final int _violations; + private final String _message; + + public MajorViolationCommand(String thisServer, String playerName, String hackType, int violations, String message) + { + this._thisServer = thisServer; + this._playerName = playerName; + this._hackType = hackType; + this._violations = violations; + this._message = message; + } + + public String getOriginatingServer() + { + return _thisServer; + } + + public String getPlayerName() + { + return _playerName; + } + + public String getHackType() + { + return _hackType; + } + + public int getViolations() + { + return _violations; + } + + public String getMessage() + { + return _message; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java new file mode 100644 index 000000000..689f57f7b --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/AntiHackAction.java @@ -0,0 +1,46 @@ +package mineplex.core.antihack.actions; + +import com.mineplex.anticheat.api.PlayerViolationEvent; +import com.mineplex.anticheat.checks.combat.KillauraTypeA; +import mineplex.core.common.util.UtilServer; +import org.bukkit.event.Listener; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public abstract class AntiHackAction implements Listener +{ + private static final Map, AntiHackAction> ACTIONS = new HashMap<>(); + private static final AntiHackAction NOOP_ACTION = new NoopAction(); + + private static final Date NEXT_BAN_WAVE = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)); + + static + { + ACTIONS.put(KillauraTypeA.class, new ImmediateBanAction(200)); + } + + private int _vl; + + AntiHackAction(int vl) + { + this._vl = vl; + + UtilServer.RegisterEvents(this); + } + + public abstract void handle(PlayerViolationEvent event); + + public int getMinVl() + { + return this._vl; + } + + public static AntiHackAction getAction(Class> checkClass) + { + AntiHackAction action = ACTIONS.getOrDefault(checkClass, NOOP_ACTION); + return action; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java new file mode 100644 index 000000000..64df22984 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/BanwaveAction.java @@ -0,0 +1,35 @@ +package mineplex.core.antihack.actions; + +import com.mineplex.anticheat.api.PlayerViolationEvent; +import mineplex.core.Managers; +import mineplex.core.antihack.banwave.BanWaveManager; +import mineplex.core.common.util.UtilServer; + +import java.util.Date; + +class BanwaveAction extends AntiHackAction +{ + private Date nextBanWave; + + BanwaveAction(Date nextBanWave, int vl) + { + super(vl); + this.nextBanWave = nextBanWave; + } + + @Override + public void handle(PlayerViolationEvent event) + { + if (event.getViolations() >= this.getMinVl()) + { + Managers.get(BanWaveManager.class).insertBanWaveInfo( + event.getPlayer(), + nextBanWave.getTime(), + event.getCheckClass(), + event.getMessage(), + event.getViolations(), + UtilServer.getServerNameFromConfig() + ); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java new file mode 100644 index 000000000..668d82389 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/ImmediateBanAction.java @@ -0,0 +1,28 @@ +package mineplex.core.antihack.actions; + +import com.mineplex.anticheat.api.PlayerViolationEvent; +import mineplex.core.Managers; +import mineplex.core.antihack.AntiHack; +import mineplex.core.common.util.UtilServer; + +class ImmediateBanAction extends AntiHackAction +{ + ImmediateBanAction(int vl) + { + super(vl); + } + + @Override + public void handle(PlayerViolationEvent event) + { + if (event.getViolations() >= this.getMinVl()) + { + String server = UtilServer.getServerName(); + if (server.contains("-")) + { + server = server.substring(0, server.indexOf('-')); + } + Managers.get(AntiHack.class).doBan(event.getPlayer(), "[GWEN] Hacking - " + AntiHack.CHECKS.get(event.getHackType()).getFriendlyName() + " [" + server + "]"); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/MixedAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/MixedAction.java new file mode 100644 index 000000000..14066a4d7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/MixedAction.java @@ -0,0 +1,49 @@ +package mineplex.core.antihack.actions; + +import com.mineplex.anticheat.api.PlayerViolationEvent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public class MixedAction extends AntiHackAction +{ + private List _actions = new ArrayList<>(); + private Map> _punished = new HashMap<>(); + + public MixedAction(AntiHackAction firstAction, AntiHackAction... actions) + { + super(firstAction.getMinVl()); + this._actions.add(firstAction); + this._actions.addAll(Arrays.asList(actions)); + } + + + @Override + public void handle(PlayerViolationEvent event) + { + for (int i = this._actions.size() - 1; i >= 0; i--) + { + AntiHackAction action = this._actions.get(i); + if (action.getMinVl() <= event.getViolations()) + { + if (_punished.computeIfAbsent(event.getPlayer().getUniqueId(), key -> new HashSet<>()).add(action)) + { + action.handle(event); + } + break; + } + } + } + + public int getMinVl() + { + return this._actions.get(0).getMinVl(); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java new file mode 100644 index 000000000..38794c630 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/actions/NoopAction.java @@ -0,0 +1,17 @@ +package mineplex.core.antihack.actions; + +import com.mineplex.anticheat.api.PlayerViolationEvent; + +public class NoopAction extends AntiHackAction +{ + NoopAction() + { + super(Integer.MAX_VALUE); + } + + @Override + public void handle(PlayerViolationEvent event) + { + + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveInfo.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveInfo.java new file mode 100644 index 000000000..c73b544a6 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveInfo.java @@ -0,0 +1,157 @@ +package mineplex.core.antihack.banwave; + +public class BanWaveInfo +{ + /** + * The unique id for this BanWaveInfo + */ + private int _id; + + /** + * The account id for this BanWaveInfo + */ + private int _accountId; + + /** + * The time in milliseconds at which to ban this user + */ + private long _timeToBan; + + /** + * Whether this BanWaveInfo has been executed + */ + private boolean _banned; + + /** + * The hack type + */ + private String _hackType; + + /** + * The ban message + */ + private String _message; + + /** + * The violation level + */ + private int _vl; + + /** + * The server on which the user was flagged + */ + private String _server; + + public int getId() + { + return _id; + } + + public void setId(int id) + { + _id = id; + } + + public int getAccountId() + { + return _accountId; + } + + public void setAccountId(int accountId) + { + _accountId = accountId; + } + + public long getTimeToBan() + { + return _timeToBan; + } + + public void setTimeToBan(long timeToBan) + { + _timeToBan = timeToBan; + } + + public boolean isBanned() + { + return _banned; + } + + public void setBanned(boolean banned) + { + _banned = banned; + } + + public String getHackType() + { + return _hackType; + } + + public void setHackType(String hackType) + { + _hackType = hackType; + } + + public String getMessage() + { + return _message; + } + + public void setMessage(String message) + { + _message = message; + } + + public int getVl() + { + return _vl; + } + + public void setVl(int vl) + { + _vl = vl; + } + + public String getServer() + { + return _server; + } + + public void setServer(String server) + { + _server = server; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + BanWaveInfo that = (BanWaveInfo) o; + + if (_id != that._id) return false; + if (_accountId != that._accountId) return false; + if (_timeToBan != that._timeToBan) return false; + if (_banned != that._banned) return false; + if (_vl != that._vl) return false; + if (_hackType != null ? !_hackType.equals(that._hackType) : that._hackType != null) return false; + if (_message != null ? !_message.equals(that._message) : that._message != null) return false; + return _server != null ? _server.equals(that._server) : that._server == null; + + } + + @Override + public int hashCode() + { + int result = _id; + result = 31 * result + _accountId; + result = 31 * result + (int) (_timeToBan ^ (_timeToBan >>> 32)); + result = 31 * result + (_banned ? 1 : 0); + result = 31 * result + (_hackType != null ? _hackType.hashCode() : 0); + result = 31 * result + (_message != null ? _message.hashCode() : 0); + result = 31 * result + _vl; + result = 31 * result + (_server != null ? _server.hashCode() : 0); + return result; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java new file mode 100644 index 000000000..8b39d9ac0 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveManager.java @@ -0,0 +1,75 @@ +package mineplex.core.antihack.banwave; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; +import mineplex.core.account.CoreClientManager; +import mineplex.core.antihack.AntiHack; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.List; + +@ReflectivelyCreateMiniPlugin +public class BanWaveManager extends MiniPlugin +{ + private final BanWaveRepository _repository = new BanWaveRepository(); + + private BanWaveManager() + { + super("BanWaveManager"); + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) + { + runAsync(() -> + { + CoreClient client = require(CoreClientManager.class).Get(event.getPlayer()); + + List infos = _repository.getBanWaveInfo(client.getAccountId()); + + long now = System.currentTimeMillis(); + + boolean banned = false; + for (BanWaveInfo info : infos) + { + if (info.getTimeToBan() < now && !info.isBanned()) + { + banned = true; + require(AntiHack.class).doBanWave(event.getPlayer(), info.getMessage()); + break; + } + } + + if (banned) + { + for (BanWaveInfo info : infos) + { + _repository.flagDone(info); + } + } + }); + } + + public void insertBanWaveInfo(Player player, long timeToBan, Class> checkClass, String message, int vl, String server) + { + insertBanWaveInfo(player, timeToBan, checkClass, message, vl, server, null); + } + + public void insertBanWaveInfo(Player player, long timeToBan, Class> checkClass, String message, int vl, String server, Runnable after) + { + runAsync(() -> + { + CoreClient client = require(CoreClientManager.class).Get(player); + + this._repository.insertBanWaveInfo(client.getAccountId(), timeToBan, checkClass.getName(), message, vl, server); + + if (after != null) + { + after.run(); + } + }); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java new file mode 100644 index 000000000..7b8650d35 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antihack/banwave/BanWaveRepository.java @@ -0,0 +1,90 @@ +package mineplex.core.antihack.banwave; + +import mineplex.core.common.util.UtilServer; +import mineplex.core.database.MinecraftRepository; +import mineplex.serverdata.database.DBPool; +import mineplex.serverdata.database.column.ColumnInt; +import mineplex.serverdata.database.column.ColumnLong; +import mineplex.serverdata.database.column.ColumnVarChar; + +import java.util.ArrayList; +import java.util.List; + +public class BanWaveRepository extends MinecraftRepository +{ + private static final String TABLE_NAME = "banwave"; + + private static final String INITIALIZE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + + "id INT AUTO_INCREMENT, " + + "accountId INT NOT NULL, " + + "timeToBan BIGINT UNSIGNED NOT NULL, " + + "banned TINYINT DEFAULT '0', " + + "hacktype VARCHAR(64), " + + "message VARCHAR(255), " + + "vl INT, " + + "server VARCHAR(32), " + + "PRIMARY KEY (id), " + + "INDEX (accountId))"; + private static final String QUERY_BY_ACCOUNT = "SELECT * FROM " + TABLE_NAME + " WHERE accountId = ?"; + private static final String INSERT_INTO_TABLE = "INSERT INTO " + TABLE_NAME + " (accountId, timeToBan, hacktype, message, vl, server) VALUES (?, ?, ?, ?, ?, ?)"; + private static final String FLAG_DONE = "UPDATE " + TABLE_NAME + " SET banned = 1 WHERE id = ?"; + + BanWaveRepository() + { + super(UtilServer.getPlugin(), DBPool.getAccount()); + } + + @Override + protected void initialize() + { + executeUpdate(INITIALIZE_TABLE); + } + + @Override + protected void update() + { + + } + + List getBanWaveInfo(int accountId) + { + List banWaveInfo = new ArrayList<>(); + + executeQuery(QUERY_BY_ACCOUNT, resultSet -> + { + while (resultSet.next()) + { + BanWaveInfo info = new BanWaveInfo(); + info.setId(resultSet.getInt(1)); + info.setAccountId(resultSet.getInt(2)); + info.setTimeToBan(resultSet.getLong(3)); + info.setBanned(resultSet.getInt(4) == 1); + info.setHackType(resultSet.getString(5)); + info.setMessage(resultSet.getString(6)); + info.setVl(resultSet.getInt(7)); + info.setServer(resultSet.getString(8)); + + banWaveInfo.add(info); + } + }, new ColumnInt("accountId", accountId)); + + return banWaveInfo; + } + + void insertBanWaveInfo(int accountId, long timeToBan, String hackType, String message, int vl, String server) + { + executeInsert(INSERT_INTO_TABLE, null, + new ColumnInt("accountId", accountId), + new ColumnLong("timeToBan", timeToBan), + new ColumnVarChar("hacktype", 64, hackType), + new ColumnVarChar("message", 255, message), + new ColumnInt("vl", vl), + new ColumnVarChar("server", 32, server) + ); + } + + void flagDone(BanWaveInfo info) + { + executeUpdate(FLAG_DONE, new ColumnInt("id", info.getId())); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antispam/AntiSpamManager.java b/Plugins/Mineplex.Core/src/mineplex/core/antispam/AntiSpamManager.java new file mode 100644 index 000000000..ce8ce600b --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antispam/AntiSpamManager.java @@ -0,0 +1,54 @@ +package mineplex.core.antispam; + +import mineplex.core.MiniPlugin; +import mineplex.core.antispam.repository.AntiSpamRepository; +import mineplex.core.status.ServerStatusManager; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; + +/** + * @author Shaun Bennett + */ +public class AntiSpamManager extends MiniPlugin +{ + private final String _pluginName; + private final String _serverName; + private final String _region; + private final AntiSpamRepository _repository; + + public AntiSpamManager() + { + super("AntiSpam"); + + _pluginName = getPlugin().getClass().getSimpleName(); + _repository = new AntiSpamRepository(); + + ServerStatusManager serverStatusManager = require(ServerStatusManager.class); + if (serverStatusManager != null) + { + _serverName = serverStatusManager.getCurrentServerName(); + _region = serverStatusManager.getRegion().name(); + } + else + { + _serverName = "Unknown"; + _region = "Unknown"; + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onChat(AsyncPlayerChatEvent event) + { + // Only listen to async events, as non async events are fake messages + if (event.isAsynchronous()) + { + Player player = event.getPlayer(); + String message = event.getMessage(); + ChatPayload payload = new ChatPayload(player.getName(), player.getUniqueId().toString(), _region, _serverName, message, System.currentTimeMillis()); + // Run our API call async to the chat message (prevents blocking chat message) + runAsync(() -> _repository.logMessage(_pluginName, payload)); + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antispam/ChatPayload.java b/Plugins/Mineplex.Core/src/mineplex/core/antispam/ChatPayload.java new file mode 100644 index 000000000..bec9550c0 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antispam/ChatPayload.java @@ -0,0 +1,126 @@ +package mineplex.core.antispam; + +/** + * @author Shaun Bennett + */ +public class ChatPayload +{ + private String _playerName; + private String _uuid; + private String _region; + private String _server; + private String _message; + private long _time; + + public ChatPayload(String playerName, String uuid, String region, String server, String message, long time) + { + _playerName = playerName; + _uuid = uuid; + _region = region; + _server = server; + _message = message; + _time = time; + } + + public String getPlayerName() + { + return _playerName; + } + + public void setPlayerName(String playerName) + { + _playerName = playerName; + } + + public String getUuid() + { + return _uuid; + } + + public void setUuid(String uuid) + { + _uuid = uuid; + } + + public String getMessage() + { + return _message; + } + + public void setMessage(String message) + { + _message = message; + } + + public String getServer() + { + return _server; + } + + public void setServer(String server) + { + _server = server; + } + + public long getTime() + { + return _time; + } + + public void setTime(long time) + { + _time = time; + } + + public String getRegion() + { + return _region; + } + + public void setRegion(String region) + { + _region = region; + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ChatPayload payload = (ChatPayload) o; + + if (_time != payload._time) return false; + if (!_playerName.equals(payload._playerName)) return false; + if (!_uuid.equals(payload._uuid)) return false; + if (!_region.equals(payload._region)) return false; + if (!_server.equals(payload._server)) return false; + return _message.equals(payload._message); + + } + + @Override + public int hashCode() + { + int result = _playerName.hashCode(); + result = 31 * result + _uuid.hashCode(); + result = 31 * result + _region.hashCode(); + result = 31 * result + _server.hashCode(); + result = 31 * result + _message.hashCode(); + result = 31 * result + (int) (_time ^ (_time >>> 32)); + return result; + } + + @Override + public String toString() + { + return "ChatPayload{" + + "_playerName='" + _playerName + '\'' + + ", _uuid='" + _uuid + '\'' + + ", _region='" + _region + '\'' + + ", _server='" + _server + '\'' + + ", _message='" + _message + '\'' + + ", _time=" + _time + + '}'; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java new file mode 100644 index 000000000..42e9ddf15 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/antispam/repository/AntiSpamRepository.java @@ -0,0 +1,26 @@ +package mineplex.core.antispam.repository; + +import com.google.gson.Gson; +import mineplex.core.antispam.ChatPayload; +import mineplex.core.common.api.ApiEndpoint; +import mineplex.core.common.api.ApiHost; +import mineplex.core.common.api.ApiResponse; +import mineplex.core.thread.ThreadPool; + +import java.util.Random; + +/** + * @author Shaun Bennett + */ +public class AntiSpamRepository extends ApiEndpoint +{ + public AntiSpamRepository() + { + super(ApiHost.ANTISPAM, "/chat"); + } + + public ApiResponse logMessage(String source, ChatPayload payload) + { + return getWebCall().post("/" + source, ApiResponse.class, payload); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/benefit/BenefitManager.java b/Plugins/Mineplex.Core/src/mineplex/core/benefit/BenefitManager.java index 804ba1931..c0768500e 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/benefit/BenefitManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/benefit/BenefitManager.java @@ -4,6 +4,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import mineplex.core.MiniDbClientPlugin; import mineplex.core.account.CoreClientManager; @@ -67,15 +68,15 @@ public class BenefitManager extends MiniDbClientPlugin } @Override - protected BenefitData addPlayer(String player) + protected BenefitData addPlayer(UUID uuid) { return new BenefitData(); } @Override - public void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException + public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException { - Set(playerName, _repository.retrievePlayerBenefitData(resultSet)); + Set(uuid, _repository.retrievePlayerBenefitData(resultSet)); } @Override diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java index b1fbc2894..a25da963c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java @@ -43,6 +43,7 @@ import mineplex.core.recharge.Recharge; import mineplex.core.reward.RewardManager; import mineplex.core.stats.StatsManager; import mineplex.core.status.ServerStatusManager; +import mineplex.core.thank.ThankManager; import mineplex.core.treasure.TreasureType; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; @@ -125,8 +126,8 @@ public class BonusManager extends MiniClientPlugin implements I private StatsManager _statsManager; private FacebookManager _facebookManager; private YoutubeManager _youtubeManager; - private BoosterManager _boosterManager; private PowerPlayClubManager _powerPlayClubManager; + private ThankManager _thankManager; public boolean _enabled; private Npc _carlNpc; private AnimationCarl _animation; @@ -169,7 +170,7 @@ public class BonusManager extends MiniClientPlugin implements I updateOffSet(); } - public BonusManager(JavaPlugin plugin, CoreClientManager clientManager, ServerStatusManager statusManager, DonationManager donationManager, PollManager pollManager, NpcManager npcManager, HologramManager hologramManager, StatsManager statsManager, InventoryManager inventoryManager, PetManager petManager, FacebookManager facebookManager, YoutubeManager youtubeManager, GadgetManager gadgetManager, BoosterManager boosterManager) + public BonusManager(JavaPlugin plugin, CoreClientManager clientManager, ServerStatusManager statusManager, DonationManager donationManager, PollManager pollManager, NpcManager npcManager, HologramManager hologramManager, StatsManager statsManager, InventoryManager inventoryManager, PetManager petManager, FacebookManager facebookManager, YoutubeManager youtubeManager, GadgetManager gadgetManager, ThankManager thankManager) { super("Bonus", plugin); _repository = new BonusRepository(plugin, this, donationManager); @@ -178,7 +179,7 @@ public class BonusManager extends MiniClientPlugin implements I _npcManager = npcManager; _hologramManager = hologramManager; _inventoryManager = inventoryManager; - _boosterManager = boosterManager; + _thankManager = thankManager; System.out.print("HUB: "); System.out.print("DONATION MANAGER - > " + _donationManager.toString()); @@ -838,7 +839,7 @@ public class BonusManager extends MiniClientPlugin implements I if (entity.equals(_carlNpc.getEntity())) { updateDailyStreak(event.getPlayer()); - new BonusGui(_plugin, event.getPlayer(), this, _rewardManager, _facebookManager, _youtubeManager, _boosterManager).openInventory(); + new BonusGui(_plugin, event.getPlayer(), this, _rewardManager, _facebookManager, _youtubeManager, _thankManager).openInventory(); } } @@ -854,7 +855,7 @@ public class BonusManager extends MiniClientPlugin implements I if (event.getEntity().equals(_carlNpc.getEntity())) { updateDailyStreak(player); - new BonusGui(_plugin, player, this, _rewardManager, _facebookManager, _youtubeManager, _boosterManager).openInventory(); + new BonusGui(_plugin, player, this, _rewardManager, _facebookManager, _youtubeManager, _thankManager).openInventory(); } } } @@ -921,7 +922,7 @@ public class BonusManager extends MiniClientPlugin implements I if (canDaily(player)) availableRewards++; if (getPollManager().getNextPoll(_pollManager.Get(player), _clientManager.Get(player).GetRank()) != null) availableRewards++; if (!_facebookManager.hasRedeemed(player)) availableRewards++; - if (_boosterManager.getTipManager().Get(player).getTips() > 0) availableRewards++; + if (_thankManager.Get(player).getThankToClaim() > 0) availableRewards++; Hologram hologram; @@ -1000,7 +1001,7 @@ public class BonusManager extends MiniClientPlugin implements I } @Override - protected BonusClientData addPlayer(String player) + protected BonusClientData addPlayer(UUID uuid) { return new BonusClientData(); } @@ -1024,7 +1025,7 @@ public class BonusManager extends MiniClientPlugin implements I @EventHandler public void UnloadPlayer(final ClientUnloadEvent event) { - final BonusClientData clientData = Get(event.GetName()); + final BonusClientData clientData = Get(event.getUniqueId()); if (clientData.getHologram() != null) clientData.getHologram().stop(); @@ -1196,9 +1197,9 @@ public class BonusManager extends MiniClientPlugin implements I } @Override - public void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException + public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException { - Set(playerName, _repository.loadData(accountId, resultSet)); + Set(uuid, _repository.loadData(accountId, resultSet)); } @Override @@ -1207,9 +1208,9 @@ public class BonusManager extends MiniClientPlugin implements I return "SELECT * FROM bonus WHERE accountId = '" + accountId + "';"; } - public BoosterManager getBoosterManager() + public ThankManager getThankManager() { - return _boosterManager; + return _thankManager; } public DonationManager getDonationManager() diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/commands/GuiCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/commands/GuiCommand.java index 649f964e3..7ed6615fd 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/commands/GuiCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/commands/GuiCommand.java @@ -1,6 +1,5 @@ package mineplex.core.bonuses.commands; -import mineplex.core.boosters.BoosterManager; import org.bukkit.entity.Player; import mineplex.core.command.CommandBase; @@ -18,7 +17,7 @@ public class GuiCommand extends CommandBase @Override public void Execute(Player caller, String[] args) { - new BonusGui(Plugin.getPlugin(), caller, Plugin, Plugin.getRewardManager(), Plugin.getFacebookManager(), Plugin.getYoutubeManager(), Plugin.getBoosterManager()).openInventory(); + new BonusGui(Plugin.getPlugin(), caller, Plugin, Plugin.getRewardManager(), Plugin.getFacebookManager(), Plugin.getYoutubeManager(), Plugin.getThankManager()).openInventory(); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/BonusGui.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/BonusGui.java index e7bf20748..db9d174f5 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/BonusGui.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/BonusGui.java @@ -2,10 +2,10 @@ package mineplex.core.bonuses.gui; import mineplex.core.bonuses.BonusManager; import mineplex.core.bonuses.gui.buttons.*; -import mineplex.core.boosters.BoosterManager; import mineplex.core.facebook.FacebookManager; import mineplex.core.gui.SimpleGui; import mineplex.core.reward.RewardManager; +import mineplex.core.thank.ThankManager; import mineplex.core.youtube.YoutubeManager; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; @@ -15,7 +15,7 @@ public class BonusGui extends SimpleGui private BonusManager manager; - public BonusGui(Plugin plugin, Player player, BonusManager manager, RewardManager rewardManager, FacebookManager facebookManager, YoutubeManager youtubeManager, BoosterManager boosterManager) + public BonusGui(Plugin plugin, Player player, BonusManager manager, RewardManager rewardManager, FacebookManager facebookManager, YoutubeManager youtubeManager, ThankManager thankManager) { super(plugin, player, player.getName() + "'s Bonuses", 5 * 9); @@ -35,7 +35,7 @@ public class BonusGui extends SimpleGui setItem(23, new TwitterButton(player)); - setItem(25, new ClaimTipsButton(getPlugin(), player, this, manager, boosterManager)); + setItem(25, new ClaimTipsButton(getPlugin(), player, this, manager, thankManager)); setItem(33, new CarlSpinButton(getPlugin(), player, manager, rewardManager)); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/ClaimTipsButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/ClaimTipsButton.java index e8a3d062d..9121b1bda 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/ClaimTipsButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/ClaimTipsButton.java @@ -1,7 +1,6 @@ package mineplex.core.bonuses.gui.buttons; import mineplex.core.bonuses.BonusManager; -import mineplex.core.boosters.BoosterManager; import mineplex.core.common.currency.GlobalCurrency; import mineplex.core.common.util.C; import mineplex.core.common.util.F; @@ -11,7 +10,9 @@ import mineplex.core.gui.ItemRefresher; import mineplex.core.gui.pages.LoadingWindow; import mineplex.core.gui.pages.TimedMessageWindow; import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.recharge.Recharge; import mineplex.core.shop.item.ShopItem; +import mineplex.core.thank.ThankManager; import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; @@ -31,12 +32,12 @@ public class ClaimTipsButton implements GuiItem, Listener private ItemRefresher _gui; private BonusManager _bonusManager; - private BoosterManager _boosterManager; + private ThankManager _thankManager; - public ClaimTipsButton(Plugin plugin, Player player, ItemRefresher gui, BonusManager bonusManager, BoosterManager boosterManager) + public ClaimTipsButton(Plugin plugin, Player player, ItemRefresher gui, BonusManager bonusManager, ThankManager thankManager) { _bonusManager = bonusManager; - _boosterManager = boosterManager; + _thankManager = thankManager; _player = player; _plugin = plugin; _gui = gui; @@ -58,12 +59,17 @@ public class ClaimTipsButton implements GuiItem, Listener @Override public void click(ClickType clickType) { + if (!Recharge.Instance.use(_player, "Claim Tips Button", 1000, false, false)) + { + return; + } + if (isAvailable()) { _item = ItemStackFactory.Instance.CreateStack(Material.LAPIS_BLOCK, (byte)0, 1, ChatColor.BLUE + "Processing..."); refreshItem(); new LoadingWindow(getPlugin(), getPlayer(), 6*9); - _boosterManager.getTipManager().claimTips(getPlayer(), claimed -> { - if (claimed > 0) + _thankManager.claimThanks(getPlayer(), claimThankResult -> { + if (claimThankResult != null && claimThankResult.getClaimed() > 0) { // Woo, success! setItem(); @@ -73,17 +79,17 @@ public class ClaimTipsButton implements GuiItem, Listener new TimedMessageWindow(getPlugin(), getPlayer(), ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.LIME.getData(), 1, ChatColor.GREEN + "Amplifier Thanks Collected"), "Thanks Collected", 6*9, 20*3, getGui()).openInventory(); } - UtilPlayer.message(getPlayer(), F.main("Carl", "You collected " + F.currency(GlobalCurrency.TREASURE_SHARD, claimed) + " from Amplifiers!")); + UtilPlayer.message(getPlayer(), F.main("Carl", "You collected " + F.currency(GlobalCurrency.TREASURE_SHARD, claimThankResult.getClaimed()) + " from " + F.elem(claimThankResult.getUniqueThanks()) + " players!")); // Pending explosions are strange.. Not sure why we are using strings. Either way, lets display a rank reward effect _bonusManager.addPendingExplosion(getPlayer(), "RANK"); getPlayer().playSound(getPlayer().getLocation(), Sound.NOTE_PLING, 1, 1.6f); } - else if (claimed == 0) + else if (claimThankResult != null && claimThankResult.getClaimed() == 0) { // No tips to claim if (getPlayer().getOpenInventory() != null) { - new TimedMessageWindow(getPlugin(), getPlayer(), ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.RED.getData(), 1, ChatColor.RED + "No Thanks to Claim!"), "You have no thanks to claim!", 6*9, 20*3, getGui()).openInventory(); + new TimedMessageWindow(getPlugin(), getPlayer(), ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.RED.getData(), 1, ChatColor.RED + "No Thanks to Claim!"), "You have no thank to claim!", 6*9, 20*3, getGui()).openInventory(); } UtilPlayer.message(getPlayer(), F.main("Carl", "You have no rewards to claim!")); @@ -119,7 +125,7 @@ public class ClaimTipsButton implements GuiItem, Listener if (isAvailable()) { material = Material.EMERALD; - itemName = C.cGreen + C.Bold + "Game Amplifiers"; + itemName = C.cGreen + C.Bold + "Thank Rewards"; lore.add(" "); lore.add(C.cYellow + "Your Rewards"); lore.add(" " + C.cWhite + getTips() + " Treasure Shards"); @@ -129,10 +135,11 @@ public class ClaimTipsButton implements GuiItem, Listener else { material = Material.REDSTONE_BLOCK; - itemName = C.cRed + C.Bold + "Game Amplifiers"; + itemName = C.cRed + C.Bold + "Thank Rewards"; lore.add(" "); - lore.add(C.cGray + "Use Amplifiers to earn rewards"); + lore.add(C.cGray + "Earn Thank Rewards from players using /thank"); + lore.add(C.cGray + "on you, or by enabling Game Amplifiers."); lore.add(" "); lore.add(C.cWhite + "Get Amplifiers at " + C.cGreen + "mineplex.com/shop"); } @@ -153,7 +160,7 @@ public class ClaimTipsButton implements GuiItem, Listener private int getTips() { - return _boosterManager.getTipManager().Get(getPlayer()).getTips(); + return _thankManager.Get(_player).getThankToClaim(); } private boolean isAvailable() diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/DailyBonusButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/DailyBonusButton.java index ebc150b6c..f46ceca73 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/DailyBonusButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/DailyBonusButton.java @@ -13,6 +13,7 @@ import mineplex.core.gui.ItemRefresher; import mineplex.core.gui.pages.LoadingWindow; import mineplex.core.gui.pages.TimedMessageWindow; import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.recharge.Recharge; import mineplex.core.shop.item.ShopItem; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; @@ -69,6 +70,11 @@ public class DailyBonusButton implements GuiItem, Listener @Override public void click(ClickType clickType) { + if (!Recharge.Instance.use(_player, "Carl Daily Bonus", 1000, false, false)) + { + return; + } + if (isAvailable()) { _item = ItemStackFactory.Instance.CreateStack(Material.LAPIS_BLOCK, (byte)0, 1, ChatColor.BLUE + "Processing..."); refreshItem(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PollButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PollButton.java index dfb707a05..29054f2a6 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PollButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PollButton.java @@ -17,6 +17,7 @@ import mineplex.core.gui.pages.TimedMessageWindow; import mineplex.core.itemstack.ItemStackFactory; import mineplex.core.poll.Poll; import mineplex.core.poll.PollManager; +import mineplex.core.recharge.Recharge; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -109,6 +110,11 @@ public class PollButton extends SimpleGui implements GuiItem { @Override public void click(ClickType clickType) { + if (!Recharge.Instance.use(getPlayer(), "Poll Main Button", 1000, false, false)) + { + return; + } + if (_poll == null) { getPlayer().playSound(getPlayer().getLocation(), Sound.ITEM_BREAK, 1, 1.6f); @@ -195,6 +201,11 @@ public class PollButton extends SimpleGui implements GuiItem { @Override public void click(ClickType clickType) { + if (!Recharge.Instance.use(getPlayer(), "Poll Answer Button", 1000, false, false)) + { + return; + } + _create = true; _pollManager.answerPoll(getPlayer(), _poll, num + 1); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/RankBonusButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/RankBonusButton.java index 1f525f36b..31541dc59 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/RankBonusButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/RankBonusButton.java @@ -13,6 +13,7 @@ import mineplex.core.gui.ItemRefresher; import mineplex.core.gui.pages.LoadingWindow; import mineplex.core.gui.pages.TimedMessageWindow; import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.recharge.Recharge; import mineplex.core.shop.item.ShopItem; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; @@ -78,6 +79,11 @@ public class RankBonusButton implements GuiItem, Listener { @Override public void click(ClickType clickType) { + if (!Recharge.Instance.use(_player, "Claim Rank Bonus", 1000, false, false)) + { + return; + } + if (isAvailable() && _bonusManager.isPastAugust()) { _item = ItemStackFactory.Instance.CreateStack(Material.LAPIS_BLOCK, (byte)0, 1, ChatColor.BLUE + "Processing..."); refreshItem(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/YoutubeButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/YoutubeButton.java index dd741b450..4a7b1b10e 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/YoutubeButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/YoutubeButton.java @@ -5,6 +5,7 @@ import mineplex.core.common.jsonchat.JsonMessage; import mineplex.core.common.util.C; import mineplex.core.gui.GuiItem; import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.recharge.Recharge; import mineplex.core.youtube.YoutubeManager; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -59,6 +60,11 @@ public class YoutubeButton implements GuiItem @Override public void click(ClickType clickType) { + if (!Recharge.Instance.use(_player, "Use Youtube Button", 1000, false, false)) + { + return; + } + _player.closeInventory(); final String message; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterManager.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterManager.java index 4254f6594..eec3e3c22 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterManager.java @@ -1,6 +1,5 @@ package mineplex.core.boosters; -import com.mojang.authlib.properties.PropertyMap; import mineplex.core.MiniPlugin; import mineplex.core.account.CoreClientManager; import mineplex.core.boosters.command.BoosterCommand; @@ -10,7 +9,7 @@ import mineplex.core.boosters.event.BoosterItemGiveEvent; import mineplex.core.boosters.event.BoosterUpdateEvent; import mineplex.core.boosters.gui.BoosterShop; import mineplex.core.boosters.redis.BoosterUpdateRepository; -import mineplex.core.boosters.tips.BoosterTipManager; +import mineplex.core.boosters.tips.BoosterThankManager; import mineplex.core.common.util.C; import mineplex.core.common.util.Callback; import mineplex.core.common.util.UtilGear; @@ -19,12 +18,12 @@ import mineplex.core.common.util.UtilServer; import mineplex.core.donation.DonationManager; import mineplex.core.inventory.InventoryManager; import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.thank.ThankManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; @@ -64,8 +63,8 @@ public class BoosterManager extends MiniPlugin private CoreClientManager _clientManager; private DonationManager _donationManager; private InventoryManager _inventoryManager; + private BoosterThankManager _boosterThankManager; - private BoosterTipManager _tipManager; private BoosterShop _shop; private String _boosterGroup; @@ -74,7 +73,7 @@ public class BoosterManager extends MiniPlugin private long _cacheLastUpdated; private Map> _boosterCache = new HashMap<>(); - public BoosterManager(JavaPlugin plugin, String boosterGroup, CoreClientManager clientManager, DonationManager donationManager, InventoryManager inventoryManager) + public BoosterManager(JavaPlugin plugin, String boosterGroup, CoreClientManager clientManager, DonationManager donationManager, InventoryManager inventoryManager, ThankManager thankManager) { super("Booster Manager", plugin); @@ -84,7 +83,7 @@ public class BoosterManager extends MiniPlugin _donationManager = donationManager; _inventoryManager = inventoryManager; - _tipManager = new BoosterTipManager(plugin, clientManager, donationManager); + _boosterThankManager = new BoosterThankManager(plugin, clientManager, thankManager); _shop = new BoosterShop(this, clientManager, donationManager); try @@ -335,9 +334,9 @@ public class BoosterManager extends MiniPlugin handleBoosterUpdate(event.getBoosterMap()); } - public BoosterTipManager getTipManager() + public BoosterThankManager getBoosterThankManager() { - return _tipManager; + return _boosterThankManager; } /** diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java index a057c4071..25e8c2c64 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/BoosterRepository.java @@ -7,6 +7,7 @@ import com.google.gson.JsonObject; import com.mojang.authlib.properties.PropertyMap; import mineplex.core.common.api.ApiEndpoint; import mineplex.core.common.api.ApiFieldNamingStrategy; +import mineplex.core.common.api.ApiHost; import mineplex.core.common.api.ApiResponse; import java.util.Arrays; @@ -23,7 +24,7 @@ public class BoosterRepository extends ApiEndpoint { public BoosterRepository() { - super("/booster", new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy()) + super(ApiHost.AMPLIFIERS, "/booster", new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy()) // .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX").create()); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/command/ThankCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/command/ThankCommand.java index 0670ce643..b6a379fc0 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/command/ThankCommand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/command/ThankCommand.java @@ -2,7 +2,7 @@ package mineplex.core.boosters.command; import mineplex.core.boosters.Booster; import mineplex.core.boosters.BoosterManager; -import mineplex.core.boosters.tips.BoosterTipManager; +import mineplex.core.boosters.tips.BoosterThankManager; import mineplex.core.boosters.tips.TipAddResult; import mineplex.core.command.CommandBase; import mineplex.core.common.Rank; @@ -56,12 +56,12 @@ public class ThankCommand extends CommandBase } else { - Plugin.getTipManager().addTip(caller, booster, result -> + Plugin.getBoosterThankManager().addTip(caller, booster, result -> { if (result == TipAddResult.SUCCESS) { - UtilPlayer.message(caller, F.main("Tip", "You thanked " + F.name(booster.getPlayerName()) + ". They earned " + F.currency(GlobalCurrency.TREASURE_SHARD, BoosterTipManager.TIP_FOR_SPONSOR) + " and you got " - + F.currency(GlobalCurrency.TREASURE_SHARD, BoosterTipManager.TIP_FOR_TIPPER)) + " in return!"); + UtilPlayer.message(caller, F.main("Tip", "You thanked " + F.name(booster.getPlayerName()) + ". They earned " + F.currency(GlobalCurrency.TREASURE_SHARD, BoosterThankManager.TIP_FOR_SPONSOR) + " and you got " + + F.currency(GlobalCurrency.TREASURE_SHARD, BoosterThankManager.TIP_FOR_TIPPER)) + " in return!"); caller.playSound(caller.getLocation(), Sound.LEVEL_UP, 1f, 1f); } else if (result.getFriendlyMessage() != null) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterThankManager.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterThankManager.java new file mode 100644 index 000000000..c3ae99372 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterThankManager.java @@ -0,0 +1,93 @@ +package mineplex.core.boosters.tips; + +import mineplex.core.MiniPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.boosters.Booster; +import mineplex.core.common.util.Callback; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.recharge.Recharge; +import mineplex.core.thank.ThankManager; +import mineplex.core.thank.ThankResult; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +/** + * This class handles "thanking" Amplifiers. This is a way of rewarding players for activating Amplifiers. + * + * @author Shaun Bennett + */ +public class BoosterThankManager extends MiniPlugin +{ + public static final int TIP_FOR_SPONSOR = 5; + public static final int TIP_FOR_TIPPER = 5; + + private BoosterThankRepository _repository; + private CoreClientManager _clientManager; + private ThankManager _thankManager; + + public BoosterThankManager(JavaPlugin plugin, CoreClientManager clientManager, ThankManager thankManager) + { + super("Amplifier Thanks", plugin); + + _clientManager = clientManager; + _repository = new BoosterThankRepository(plugin); + _thankManager = thankManager; + } + + /** + * Attempt to "Thank" an Amplifier. This checks with {@link BoosterThankRepository} if a player hasn't already + * thanked that Amplifier. If they havent, we proceed to use {@link ThankManager} to send a thank you to the player + * who activated that Amplifier. + * + * @param player The player sending the thanks + * @param booster The Amplifier to be thanked + * @param callback Callback with the result of sending the thanks + */ + public void addTip(Player player, Booster booster, Callback callback) + { + if (!Recharge.Instance.use(player, "Amplifier Thanks", 1000 * 5, false, false)) + { + UtilPlayer.message(player, F.main("Amplifier", "Please wait before trying that again")); + callback.run(TipAddResult.ON_COOLDOWN); + return; + } + + int accountId = _clientManager.getAccountId(player); + + // Break out if client manager has a bad account id + if (accountId == -1) + { + callback.run(TipAddResult.INVALID_ACCOUNT_ID); + return; + } + + // You can't tip yourself, silly! + if (accountId == booster.getAccountId()) + { + callback.run(TipAddResult.CANNOT_TIP_SELF); + return; + } + + runAsync(() -> + { + if (_repository.checkAmplifierThank(accountId, booster.getId())) + { + // We can thank that amplifier! + _thankManager.thankPlayer(booster.getPlayerName(), booster.getAccountId(), player.getName(), accountId, + TIP_FOR_SPONSOR, TIP_FOR_TIPPER, "Amplifier", true, thankResult -> + runSync(() -> callback.run(fromThankResult(thankResult)))); + } + else + { + runSync(() -> callback.run(TipAddResult.ALREADY_TIPPED_BOOSTER)); + } + }); + } + + + private TipAddResult fromThankResult(ThankResult result) + { + return result == ThankResult.SUCCESS ? TipAddResult.SUCCESS : TipAddResult.UNKNOWN_ERROR; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterThankRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterThankRepository.java new file mode 100644 index 000000000..8fd26265e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterThankRepository.java @@ -0,0 +1,52 @@ +package mineplex.core.boosters.tips; + +import mineplex.core.database.MinecraftRepository; +import mineplex.database.routines.AddTip; +import mineplex.database.routines.CheckAmplifierThank; +import mineplex.database.routines.ClaimTips; +import mineplex.serverdata.database.DBPool; +import mineplex.serverdata.database.RepositoryBase; +import mineplex.serverdata.database.column.ColumnInt; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +/** + * @author Shaun Bennett + */ +public class BoosterThankRepository extends MinecraftRepository +{ + public BoosterThankRepository(JavaPlugin plugin) + { + super(plugin, DBPool.getAccount()); + } + + /** + * Checks the database if an accountId is allowed to thank a specific Amplifier. + * This will return true and update the database if the thank is okay, or false + * if that account ID has already thanked that Amplifier ID. + * + * @param accountId Account ID of the player trying to thank the Amplifier + * @param amplifierId The ID of the Amplifier the player is trying to thank + * @return True if the account id can thank the amplifier id, false otherwise + */ + public boolean checkAmplifierThank(int accountId, int amplifierId) + { + CheckAmplifierThank checkAmplifierThank = new CheckAmplifierThank(); + checkAmplifierThank.setInAccountId(accountId); + checkAmplifierThank.setInAmplifierId(amplifierId); + checkAmplifierThank.execute(jooq().configuration()); + return checkAmplifierThank.getCanThank() == 1; + } + + @Override + protected void initialize() + { + + } + + @Override + protected void update() + { + + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterTipManager.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterTipManager.java deleted file mode 100644 index ff31ce07e..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterTipManager.java +++ /dev/null @@ -1,133 +0,0 @@ -package mineplex.core.boosters.tips; - -import mineplex.core.MiniDbClientPlugin; -import mineplex.core.account.CoreClientManager; -import mineplex.core.boosters.Booster; -import mineplex.core.common.util.Callback; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.donation.DonationManager; -import mineplex.core.recharge.Recharge; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * @author Shaun Bennett - */ -public class BoosterTipManager extends MiniDbClientPlugin -{ - public static final int TIP_FOR_SPONSOR = 5; - public static final int TIP_FOR_TIPPER = 5; - - private BoosterTipRepository _repository; - private DonationManager _donationManager; - - public BoosterTipManager(JavaPlugin plugin, CoreClientManager clientManager, DonationManager donationManager) - { - super("Amplifier Thanks", plugin, clientManager); - - _donationManager = donationManager; - _repository = new BoosterTipRepository(plugin); - } - - public void addTip(Player player, Booster booster, Callback callback) - { - if (!Recharge.Instance.use(player, "Amplifier Thanks", 1000 * 5, false, false)) - { - UtilPlayer.message(player, F.main("Amplifier", "Please wait before trying that again")); - callback.run(TipAddResult.ON_COOLDOWN); - return; - } - - int accountId = ClientManager.getAccountId(player); - - // Break out if client manager has a bad account id - if (accountId == -1) - { - callback.run(TipAddResult.INVALID_ACCOUNT_ID); - return; - } - - // You can't tip yourself, silly! - if (accountId == booster.getAccountId()) - { - callback.run(TipAddResult.CANNOT_TIP_SELF); - return; - } - - runAsync(() -> { - TipAddResult result; - if (_repository.addTip(accountId, booster.getAccountId(), booster.getId(), TIP_FOR_SPONSOR)) - { - _donationManager.rewardCoinsUntilSuccess(null, "Tips", player.getName(), accountId, TIP_FOR_TIPPER); - result = TipAddResult.SUCCESS; - } - else - result = TipAddResult.ALREADY_TIPPED_BOOSTER; - - runSync(() -> callback.run(result)); - }); - } - - /** - * Claim all tips for a player and add those tips to their account (Treasure Shards) - * This will call a database routine that handles the tip process. - * - * The callback will return -1 on a failed attempt or 0 if there was no tips to claim - * @param player The player with tips to claim - * @param callback Callback returning the amount of tips claimed - */ - public void claimTips(Player player, Callback callback) - { - String playerName = player.getName(); - int accountId = ClientManager.getAccountId(player); - - if (accountId == -1) - { - // uh oh, invalid account id! - if (callback != null) callback.run(-1); - } - - runAsync(() -> { - int tips = _repository.claimTips(accountId); - runSync(() -> { - if (tips > 0) - { - _donationManager.rewardCoinsUntilSuccess(null, "Tips", playerName, accountId, tips); - } - - // Reset tips back to 0 - if (Get(player) != null) Get(player).setTips(0); - if (callback != null) callback.run(tips); - }); - }); - } - - @Override - public String getQuery(int accountId, String uuid, String name) - { - return "SELECT tips FROM Account.accountTip WHERE accountTip.accountId = " + accountId + ";"; - } - - @Override - protected PlayerTipData addPlayer(String player) - { - return new PlayerTipData(); - } - - @Override - public void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException - { - PlayerTipData data = new PlayerTipData(); - - while (resultSet.next()) - { - data.setTips(resultSet.getInt(1)); - } - - Set(playerName, data); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterTipRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterTipRepository.java deleted file mode 100644 index 6ece1a5b2..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/BoosterTipRepository.java +++ /dev/null @@ -1,55 +0,0 @@ -package mineplex.core.boosters.tips; - -import mineplex.core.database.MinecraftRepository; -import mineplex.database.routines.AddTip; -import mineplex.database.routines.ClaimTips; -import mineplex.serverdata.database.DBPool; -import mineplex.serverdata.database.RepositoryBase; -import mineplex.serverdata.database.column.ColumnInt; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -/** - * @author Shaun Bennett - */ -public class BoosterTipRepository extends MinecraftRepository -{ - public static String LOG_TIP = "INSERT INTO Account.accountTipLogs (accountId, boosterId) VALUES (?, ?)"; - public static String ADD_TIP = "INSERT INTO Account.accountTip (accountId, tips) VALUES (?, ?) ON DUPLICATE KEY UPDATE tips = tips + ?"; - - public BoosterTipRepository(JavaPlugin plugin) - { - super(plugin, DBPool.getAccount()); - } - - public boolean addTip(int tipperId, int receiverId, int boosterId, int tipAmount) - { - AddTip addTip = new AddTip(); - addTip.setTipperAccountId(tipperId); - addTip.setBoosterAccountId(receiverId); - addTip.setBoosterId(boosterId); - addTip.setTipAmount(tipAmount); - addTip.execute(jooq().configuration()); - return addTip.getSuccess() == 1; - } - - public int claimTips(int accountId) - { - ClaimTips claimTips = new ClaimTips(); - claimTips.setAccountId_in(accountId); - claimTips.execute(jooq().configuration()); - return claimTips.getTipsClaimed(); - } - - @Override - protected void initialize() - { - - } - - @Override - protected void update() - { - - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/TipAddResult.java b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/TipAddResult.java index 965a8e738..aa657b6e2 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/TipAddResult.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/boosters/tips/TipAddResult.java @@ -7,6 +7,7 @@ public enum TipAddResult { ALREADY_TIPPED_BOOSTER("You have already thanked this Amplifier!"), INVALID_ACCOUNT_ID("Uh oh, something went wrong. Try relogging"), + UNKNOWN_ERROR("An error occurred. Try again later"), CANNOT_TIP_SELF("You can't thank yourself, silly!"), ON_COOLDOWN(null), SUCCESS(null); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java b/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java index effa0f484..c27c6a00a 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java @@ -1,40 +1,5 @@ package mineplex.core.chat; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.nio.charset.Charset; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; -import java.util.function.Function; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.apache.commons.lang3.Validate; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.SignChangeEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.plugin.java.JavaPlugin; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; - import mineplex.core.MiniPlugin; import mineplex.core.account.CoreClientManager; import mineplex.core.achievement.AchievementManager; @@ -53,6 +18,39 @@ import mineplex.core.preferences.PreferencesManager; import mineplex.core.recharge.Recharge; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import org.apache.commons.lang3.Validate; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.Charset; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import java.util.function.Function; public class Chat extends MiniPlugin { @@ -69,7 +67,6 @@ public class Chat extends MiniPlugin private int _chatSlow = 0; private long _silenced = 0; - private boolean _threeSecondDelay = true; private List> _highPriorityFilters = new ArrayList<>(); private List> _lowPriorityFilters = new ArrayList<>(); @@ -349,15 +346,6 @@ public class Chat extends MiniPlugin event.setCancelled(true); return; } - else if (_threeSecondDelay && - _clientManager.Get(sender).GetRank() == Rank.ALL && - _achievements.getMineplexLevelNumber(sender, Rank.ALL) < 25 && - !Recharge.Instance.use(sender, "All Chat Message", 3000, false, false)) - { - UtilPlayer.message(sender, C.cYellow + "You can only chat once every 3 seconds to prevent spam."); - UtilPlayer.message(sender, C.cYellow + "Buy a Rank at " + C.cGreen + "www.mineplex.com/shop" + C.cYellow + " to remove this limit!"); - event.setCancelled(true); - } else if (!_clientManager.Get(sender).GetRank().has(Rank.MODERATOR) && !Recharge.Instance.use(sender, "Chat Message", 400, false, false)) { @@ -645,11 +633,6 @@ public class Chat extends MiniPlugin _playerLastMessage.remove(event.getPlayer().getUniqueId()); } - public void setThreeSecondDelay(boolean b) - { - _threeSecondDelay = b; - } - /** * If the function returns Boolean.TRUE then the message will be CANCELLED. */ diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java index cd40f9b06..a5c62b29c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/GadgetPage.java @@ -245,13 +245,13 @@ public class GadgetPage extends ShopPageBase itemLore.add(C.cWhiteB + "Cost: " + C.cAqua + gadget.getCost(GlobalCurrency.TREASURE_SHARD) + " Treasure Shards"); } - if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer().getName()).getBalance(GlobalCurrency.TREASURE_SHARD) >= gadget.getCost(GlobalCurrency.TREASURE_SHARD)) + if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.TREASURE_SHARD) >= gadget.getCost(GlobalCurrency.TREASURE_SHARD)) { itemLore.add(C.cBlack); itemLore.add(C.cWhiteB + "Cost: " + C.cAqua + gadget.getCost(GlobalCurrency.TREASURE_SHARD) + " Treasure Shards"); } - if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer().getName()).getBalance(GlobalCurrency.TREASURE_SHARD) >= gadget.getCost(GlobalCurrency.TREASURE_SHARD)) + if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.TREASURE_SHARD) >= gadget.getCost(GlobalCurrency.TREASURE_SHARD)) { itemLore.add(C.cBlack); itemLore.add(C.cGreen + "Click to Purchase"); @@ -335,7 +335,7 @@ public class GadgetPage extends ShopPageBase itemLore.add(C.cWhiteB + "Cost: " + C.cAqua + gadget.getCost(GlobalCurrency.TREASURE_SHARD) + " Treasure Shards"); } - if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer().getName()).getBalance(GlobalCurrency.TREASURE_SHARD) >= gadget.getCost(GlobalCurrency.TREASURE_SHARD)) + if (gadget.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.TREASURE_SHARD) >= gadget.getCost(GlobalCurrency.TREASURE_SHARD)) { itemLore.add(C.cBlack); itemLore.add(C.cGreen + "Click to Purchase"); @@ -372,7 +372,7 @@ public class GadgetPage extends ShopPageBase UtilPlayer.message(player, F.main("Disguise", "You cant buy things while you are disguised!")); return; } - getShop().openPageForPlayer(getPlayer(), new ConfirmationPage<>(player, this, new SalesPackageProcessor(player, GlobalCurrency.TREASURE_SHARD, gadget, getDonationManager(), () -> + getShop().openPageForPlayer(getPlayer(), new ConfirmationPage<>(player, this, new SalesPackageProcessor(player, GlobalCurrency.TREASURE_SHARD, (gadget instanceof ItemGadget ? ((ItemGadget) gadget).getAmmo() : gadget), getDonationManager(), () -> { getPlugin().getInventoryManager().addItemToInventory(getPlayer(), gadget.getName(), (gadget instanceof ItemGadget ? ((ItemGadget) gadget).getAmmo().getQuantity() : gadget.getQuantity())); refresh(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java index 314fd5879..4ab38eae7 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/Menu.java @@ -2,10 +2,25 @@ package mineplex.core.cosmetic.ui.page; import mineplex.core.account.CoreClientManager; import mineplex.core.common.currency.GlobalCurrency; -import mineplex.core.common.util.*; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.LineFormat; +import mineplex.core.common.util.UtilText; import mineplex.core.cosmetic.CosmeticManager; import mineplex.core.cosmetic.ui.CosmeticShop; -import mineplex.core.cosmetic.ui.button.open.*; +import mineplex.core.cosmetic.ui.button.open.OpenArrowTrails; +import mineplex.core.cosmetic.ui.button.open.OpenCostumes; +import mineplex.core.cosmetic.ui.button.open.OpenDeathAnimations; +import mineplex.core.cosmetic.ui.button.open.OpenDoubleJump; +import mineplex.core.cosmetic.ui.button.open.OpenGadgets; +import mineplex.core.cosmetic.ui.button.open.OpenGameModifiers; +import mineplex.core.cosmetic.ui.button.open.OpenHats; +import mineplex.core.cosmetic.ui.button.open.OpenMorphs; +import mineplex.core.cosmetic.ui.button.open.OpenMounts; +import mineplex.core.cosmetic.ui.button.open.OpenMusic; +import mineplex.core.cosmetic.ui.button.open.OpenParticles; +import mineplex.core.cosmetic.ui.button.open.OpenPets; +import mineplex.core.cosmetic.ui.button.open.OpenWinEffect; import mineplex.core.donation.DonationManager; import mineplex.core.gadget.types.Gadget; import mineplex.core.gadget.types.GadgetType; @@ -23,6 +38,7 @@ import org.bukkit.event.inventory.ClickType; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; +import java.util.Map; public class Menu extends ShopPageBase { @@ -96,7 +112,7 @@ public class Menu extends ShopPageBase Mount> mountActive = getPlugin().getMountManager().getActive(getPlayer()); for (Mount> mount : getPlugin().getMountManager().getMounts()) { - if (getDonationManager().Get(getPlayer().getName()).OwnsUnknownPackage(mount.getName())) + if (getDonationManager().Get(getPlayer()).OwnsUnknownPackage(mount.getName())) { mountOwned++; } @@ -108,7 +124,7 @@ public class Menu extends ShopPageBase int petMax = 0; for (Pet pet : getPlugin().getPetManager().getFactory().GetPets()) { - NautHashMap pets = getPlugin().getPetManager().Get(getPlayer()).getPets(); + Map pets = getPlugin().getPetManager().Get(getPlayer()).getPets(); if (pets != null && pets.containsKey(pet.getPetType())) { petOwned++; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/MountPage.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/MountPage.java index 29964074a..020297748 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/MountPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/MountPage.java @@ -59,7 +59,7 @@ public class MountPage extends ShopPageBase itemLore.add(C.cBlack); itemLore.addAll(Arrays.asList(mount.getDescription())); - if (!getDonationManager().Get(getPlayer().getName()).OwnsUnknownPackage(mount.getName())) + if (!getDonationManager().Get(getPlayer()).OwnsUnknownPackage(mount.getName())) { if (mount.getCost(GlobalCurrency.TREASURE_SHARD) == -1) { @@ -119,7 +119,7 @@ public class MountPage extends ShopPageBase } } - if (getDonationManager().Get(getPlayer().getName()).OwnsUnknownPackage(mount.getName())) + if (getDonationManager().Get(getPlayer()).OwnsUnknownPackage(mount.getName())) { if (mount.getActive().containsKey(getPlayer())) { @@ -144,7 +144,7 @@ public class MountPage extends ShopPageBase itemLore.add(C.cWhiteB + "Cost: " + C.cAqua + mount.getCost(GlobalCurrency.TREASURE_SHARD) + " Treasure Shards"); } - if (mount.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer().getName()).getBalance(GlobalCurrency.TREASURE_SHARD) >= mount.getCost(GlobalCurrency.TREASURE_SHARD)) + if (mount.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.TREASURE_SHARD) >= mount.getCost(GlobalCurrency.TREASURE_SHARD)) { itemLore.add(C.cBlack); itemLore.add(C.cGreen + "Click to Purchase"); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/PetPage.java b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/PetPage.java index a99e9135c..77b4c15ee 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/PetPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/cosmetic/ui/page/PetPage.java @@ -143,8 +143,8 @@ public class PetPage extends ShopPageBase itemLore.add(C.cBlack); itemLore.add(C.cWhiteB + "Cost: " + C.cAqua + pet.getCost(GlobalCurrency.TREASURE_SHARD) + " Treasure Shards"); } - - if (pet.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer().getName()).getBalance(GlobalCurrency.TREASURE_SHARD) >= pet.getCost(GlobalCurrency.TREASURE_SHARD)) + + if (pet.getCost(GlobalCurrency.TREASURE_SHARD) > 0 && getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.TREASURE_SHARD) >= pet.getCost(GlobalCurrency.TREASURE_SHARD)) { itemLore.add(C.cBlack); itemLore.add(C.cGreen + "Click to Purchase"); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java b/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java index e892c9f4d..a759cdcbc 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/creature/Creature.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import mineplex.core.Managers; import mineplex.core.MiniPlugin; import mineplex.core.updater.event.UpdateEvent; import mineplex.core.updater.UpdateType; @@ -55,6 +56,15 @@ public class Creature extends MiniPlugin return entity; } + public T SpawnEntity(Location location, Class entityType) + { + _spawnForce = true; + T entity = location.getWorld().spawn(location, entityType); + _spawnForce = false; + + return entity; + } + @EventHandler(priority = EventPriority.HIGHEST) public void eggThrow(PlayerEggThrowEvent event) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/customdata/CustomDataManager.java b/Plugins/Mineplex.Core/src/mineplex/core/customdata/CustomDataManager.java index 45893a07d..84e958429 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/customdata/CustomDataManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/customdata/CustomDataManager.java @@ -2,6 +2,7 @@ package mineplex.core.customdata; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.UUID; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -26,14 +27,14 @@ public class CustomDataManager extends MiniDbClientPlugin } @Override - public void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException + public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException { PlayerCustomData data = new PlayerCustomData(_repository); while (resultSet.next()) { data.setData(_repository.getKey(resultSet.getInt("customDataId")), resultSet.getInt("data")); } - Set(playerName, data); + Set(uuid, data); } @Override @@ -43,7 +44,7 @@ public class CustomDataManager extends MiniDbClientPlugin } @Override - protected PlayerCustomData addPlayer(String player) + protected PlayerCustomData addPlayer(UUID uuid) { return new PlayerCustomData(_repository); } @@ -56,7 +57,7 @@ public class CustomDataManager extends MiniDbClientPlugin if (accountId == -1) return; - runAsync(() -> _repository.saveData(name, accountId)); + runAsync(() -> _repository.saveData(name, player.getUniqueId(), accountId)); } public CorePlayer getCorePlayer(Player player) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/customdata/repository/CustomDataRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/customdata/repository/CustomDataRepository.java index 14600c963..7ef6ad563 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/customdata/repository/CustomDataRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/customdata/repository/CustomDataRepository.java @@ -4,6 +4,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Map; +import java.util.UUID; import mineplex.core.database.MinecraftRepository; import org.bukkit.plugin.java.JavaPlugin; @@ -68,9 +69,9 @@ public class CustomDataRepository extends MinecraftRepository }); } - public void saveData(String name, int accountId) + public void saveData(String name, UUID uuid, int accountId) { - PlayerCustomData data = _customDataManager.Get(name); + PlayerCustomData data = _customDataManager.Get(uuid); for (Map.Entry entry : data.getDataMap().entrySet()) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/delayedtask/DelayedTask.java b/Plugins/Mineplex.Core/src/mineplex/core/delayedtask/DelayedTask.java index d407ec093..cd71bfcca 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/delayedtask/DelayedTask.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/delayedtask/DelayedTask.java @@ -12,6 +12,8 @@ import mineplex.core.common.util.Callback; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import java.util.UUID; + public class DelayedTask extends MiniClientPlugin { public static DelayedTask Instance; @@ -58,9 +60,9 @@ public class DelayedTask extends MiniClientPlugin } @Override - protected DelayedTaskClient addPlayer(String player) + protected DelayedTaskClient addPlayer(UUID uuid) { - return new DelayedTaskClient(Bukkit.getPlayer(player)); + return new DelayedTaskClient(Bukkit.getPlayer(uuid)); } public boolean HasTask(Player player, String task) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseFactory.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseFactory.java index f84a661db..1fa8fca66 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseFactory.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseFactory.java @@ -35,7 +35,7 @@ public class DisguiseFactory case PIG_ZOMBIE: return new DisguisePigZombie(disguised); case PLAYER: - return new DisguisePlayer(disguised); + throw new UnsupportedOperationException("Player disguises must be initialized via constructor"); case SHEEP: return new DisguiseSheep(disguised); case SKELETON: diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseManager.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseManager.java index 154ec1ba6..282267d2b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguiseManager.java @@ -2,27 +2,46 @@ package mineplex.core.disguise; import com.mineplex.spigot.ChunkAddEntityEvent; import mineplex.core.MiniPlugin; -import mineplex.core.common.util.NautHashMap; -import mineplex.core.common.util.UtilEnt; +import mineplex.core.PlayerSelector; +import mineplex.core.ReflectivelyCreateMiniPlugin; import mineplex.core.common.util.UtilPlayer; -import mineplex.core.disguise.disguises.*; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTasks; +import mineplex.core.disguise.disguises.DisguiseBase; +import mineplex.core.disguise.disguises.DisguiseBlock; +import mineplex.core.disguise.disguises.DisguiseInsentient; +import mineplex.core.disguise.disguises.DisguiseLiving; +import mineplex.core.disguise.disguises.DisguisePlayer; import mineplex.core.packethandler.IPacketHandler; import mineplex.core.packethandler.PacketHandler; import mineplex.core.packethandler.PacketInfo; import mineplex.core.packethandler.PacketVerifier; -import mineplex.core.timing.TimingManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; -import net.minecraft.server.v1_8_R3.*; -import net.minecraft.server.v1_8_R3.PacketPlayOutEntity.PacketPlayOutRelEntityMove; -import net.minecraft.server.v1_8_R3.PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook; -import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo.PlayerInfoData; +import net.minecraft.server.v1_8_R3.BlockBed; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.Blocks; +import net.minecraft.server.v1_8_R3.Chunk; +import net.minecraft.server.v1_8_R3.EntityPlayer; +import net.minecraft.server.v1_8_R3.EntityTrackerEntry; +import net.minecraft.server.v1_8_R3.EnumDirection; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import net.minecraft.server.v1_8_R3.Packet; +import net.minecraft.server.v1_8_R3.PacketPlayOutBed; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityEquipment; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport; +import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk; +import net.minecraft.server.v1_8_R3.PacketPlayOutNamedEntitySpawn; +import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity; +import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving; +import net.minecraft.server.v1_8_R3.PacketPlayOutUpdateAttributes; +import net.minecraft.server.v1_8_R3.WorldServer; +import net.minecraft.server.v1_8_R3.WorldSettings; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockFace; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Entity; @@ -30,447 +49,285 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -import org.bukkit.event.player.*; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.ChunkUnloadEvent; -import org.bukkit.plugin.java.JavaPlugin; -import java.lang.reflect.Field; -import java.util.*; -import java.util.Map.Entry; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Predicate; +/* + * notes: rabbit jump has been removed (PacketPlayOutEntityStatus) because it didn't work for 1.9+ anyways + * + * contact samczsun before you make any major changes + */ +@ReflectivelyCreateMiniPlugin public class DisguiseManager extends MiniPlugin implements IPacketHandler { - public static DisguiseManager INSTANCE; + // A map of entityids which are disguised to their respective disguises + private Map> _spawnPacketMap = new HashMap<>(); - private NautHashMap _spawnPacketMap = new NautHashMap(); - private NautHashMap _movePacketMap = new NautHashMap(); - private NautHashMap _moveTempMap = new NautHashMap(); - private HashSet _goingUp = new HashSet(); - private NautHashMap _entityDisguiseMap = new NautHashMap(); - private NautHashMap> _disguisePlayerMap = new NautHashMap>(); - private HashSet _blockedNames = new HashSet(); - private NautHashMap> _futureDisguises = new NautHashMap>(); - private NautHashMap> _lastRabbitHop = new NautHashMap>(); + // The map which stores entity UUIDs once they have been unloaded + private Map> _entityDisguiseMap = new HashMap<>(); + + // The map of which players should a disguise be shown to + private Map> _disguisePlayerMap = new HashMap<>(); + + private HashSet _blockedNames = new HashSet<>(); private boolean _handlingPacket = false; - private Field _xChunk; - private Field _zChunk; - - private Chunk _bedChunk; - private boolean _bedPackets; - - - public DisguiseManager(JavaPlugin plugin, PacketHandler packetHandler) + private DisguiseManager() { - super("Disguise Manager", plugin); + super("Disguise Manager"); - packetHandler.addPacketHandler(this, PacketPlayOutAnimation.class, PacketPlayOutBed.class, - PacketPlayOutEntityStatus.class, PacketPlayOutMapChunk.class, PacketPlayOutMapChunkBulk.class, - PacketPlayOutNamedEntitySpawn.class, PacketPlayOutPlayerInfo.class, - PacketPlayOutEntity.PacketPlayOutRelEntityMove.class, PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook.class, - PacketPlayOutSpawnEntity.class, PacketPlayOutEntityVelocity.class, PacketPlayOutEntityDestroy.class, - PacketPlayOutEntityTeleport.class, PacketPlayOutEntityMetadata.class, PacketPlayOutSpawnEntityLiving.class, - PacketPlayOutUpdateAttributes.class, PacketPlayOutEntityEquipment.class, PacketPlayOutNamedSoundEffect.class); + require(PacketHandler.class) + .addPacketHandler(this, + PacketPlayOutNamedEntitySpawn.class, + PacketPlayOutPlayerInfo.class, + PacketPlayOutSpawnEntity.class, + PacketPlayOutEntityMetadata.class, + PacketPlayOutSpawnEntityLiving.class, + PacketPlayOutUpdateAttributes.class, + PacketPlayOutEntityEquipment.class + ); - INSTANCE = this; - - try - { - _bedChunk = new Chunk(((CraftWorld) Bukkit.getWorlds().get(0)).getHandle(), 0, 0); - Field cSection = Chunk.class.getDeclaredField("sections"); - cSection.setAccessible(true); - - ChunkSection chunkSection = new ChunkSection(0, true); - Block block = Block.getById(Material.BED_BLOCK.getId()); - - // block = ((Object[]) ReflectionManager.getNmsField(ReflectionManager.getNmsClass("Block"),"byId") - // .get(null))[Material.BED_BLOCK.getId()]; - - for (BlockFace face : new BlockFace[] - { - BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH - }) - { - int x = 1 + face.getModX(); - int z = 1 + face.getModZ(); - - chunkSection.setType(x, 0, z, block.fromLegacyData(face.ordinal())); - chunkSection.a(x, 0, z, 0); - chunkSection.b(x, 0, z, 0); - } - - ChunkSection[] chunkSections = new ChunkSection[16]; - chunkSections[0] = chunkSection; - cSection.set(_bedChunk, chunkSections); - - // TODO -// _bedChunk.world = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle(); - - _xChunk = Chunk.class.getField("locX"); - _xChunk.setAccessible(true); - - _zChunk = Chunk.class.getField("locZ"); - _zChunk.setAccessible(true); - } - catch (IllegalArgumentException e) - { - e.printStackTrace(); - } - catch (NoSuchFieldException e) - { - e.printStackTrace(); - } - catch (SecurityException e) - { - e.printStackTrace(); - } - catch (IllegalAccessException e) - { - e.printStackTrace(); - } - } - - public void addFutureDisguise(DisguiseBase disguise, Player... players) - { - final int entityId = UtilEnt.getNewEntityId(false); - - _futureDisguises.put(entityId, new HashMap.SimpleEntry(disguise, players)); - - Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() - { - public void run() - { - if (_futureDisguises.containsKey(entityId)) - { - Entry entry = _futureDisguises.remove(entityId); - - Entity entity = UtilEnt.getEntityById(entityId); - - if (entity != null) - { - entry.getKey().setEntity(entity); - - disguise(entry.getKey(), entry.getValue()); - } - } - } - }, 4); - } - - public void addViewerToDisguise(DisguiseBase disguise, Player player, boolean reapply) - { - _disguisePlayerMap.get(disguise).add(player); - - if (reapply) - refreshTrackers(disguise.GetEntity().getBukkitEntity(), new Player[] - { - player - }); + createBedChunk(); } + // We want to re-register entities that were reloaded by chunk loading @EventHandler - public void ChunkAddEntity(ChunkAddEntityEvent event) + public void onEntityAdd(ChunkAddEntityEvent event) { - DisguiseBase disguise = _entityDisguiseMap.get(event.getEntity().getUniqueId().toString()); + LinkedList disguises = _entityDisguiseMap.remove(event.getEntity().getUniqueId()); - if (disguise != null) + if (disguises != null) { - disguise.setEntity(event.getEntity()); - _spawnPacketMap.put(event.getEntity().getEntityId(), disguise); - _entityDisguiseMap.remove(event.getEntity().getUniqueId().toString()); - - if (disguise instanceof DisguiseRabbit) - { - _lastRabbitHop.put(disguise.GetEntityId(), new NautHashMap()); - } - } - } - - @EventHandler - public void chunkJoin(PlayerJoinEvent event) - { - if (!_bedPackets) - return; - - chunkMove(event.getPlayer(), event.getPlayer().getLocation(), null); - } - - private void chunkMove(Player player, Location newLoc, Location oldLoc) - { - for (Packet packet : getChunkMovePackets(player, newLoc, oldLoc)) - { - UtilPlayer.sendPacket(player, packet); + disguises.forEach(disguise -> disguise.setEntity(event.getEntity())); + _spawnPacketMap.put(event.getEntity().getEntityId(), disguises); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void chunkMove(PlayerMoveEvent event) - { - if (!_bedPackets) - return; - - Location to = event.getTo(); - Location from = event.getFrom(); - - int x1 = getChunk(to.getX()); - int z1 = getChunk(to.getZ()); - int x2 = getChunk(from.getX()); - int z2 = getChunk(from.getZ()); - - if (x1 != x2 || z1 != z2) - { - chunkMove(event.getPlayer(), to, from); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void chunkTeleport(PlayerTeleportEvent event) - { - if (!_bedPackets) - return; - - Location to = event.getTo(); - Location from = event.getFrom(); - - if (to.getWorld() == from.getWorld()) - { - int x1 = getChunk(to.getX()); - int z1 = getChunk(to.getZ()); - - int x2 = getChunk(from.getX()); - int z2 = getChunk(from.getZ()); - - if (x1 != x2 || z1 != z2) - { - final Player player = event.getPlayer(); - final Location prev = new Location(to.getWorld(), x1, 0, z1); - - chunkMove(player, null, from); - - Bukkit.getScheduler().scheduleSyncDelayedTask(_plugin, new Runnable() - { - public void run() - { - if (!player.isOnline()) - { - return; - } - - Location loc = player.getLocation(); - - if (player.getWorld() != loc.getWorld()) - { - return; - } - - int x2 = getChunk(loc.getX()); - int z2 = getChunk(loc.getZ()); - - if (prev.getBlockX() == x2 && prev.getBlockZ() == z2 && loc.getWorld() == prev.getWorld()) - { - chunkMove(player, loc, null); - } - - refreshBedTrackers(player); - } - }); - } - } - } - - @EventHandler - public void ChunkUnload(ChunkUnloadEvent event) + public void onEntityRemove(ChunkUnloadEvent event) { + Set careAbout = new HashSet<>(); for (Entity entity : event.getChunk().getEntities()) { if (_spawnPacketMap.containsKey(entity.getEntityId())) { - _entityDisguiseMap.put(entity.getUniqueId().toString(), _spawnPacketMap.get(entity.getEntityId())); - _spawnPacketMap.remove(entity.getEntityId()); - _lastRabbitHop.remove(entity.getEntityId()); + careAbout.add(entity); } } - } - public void clearDisguises() - { - _spawnPacketMap.clear(); - _movePacketMap.clear(); - _moveTempMap.clear(); - _goingUp.clear(); - _entityDisguiseMap.clear(); - _disguisePlayerMap.clear(); - - if (_bedPackets) + // Run it a tick later so that if someone else happened to cancel the event, we won't fall for it + runSync(() -> { - unregisterBedChunk(); - } - } - - private boolean containsSpawnDisguise(Player owner, int entityId) - { - return _spawnPacketMap.containsKey(entityId) - && (_spawnPacketMap.get(entityId).Global || (_disguisePlayerMap.containsKey(_spawnPacketMap.get(entityId)) && _disguisePlayerMap - .get(_spawnPacketMap.get(entityId)).contains(owner))); - } - - public void disguise(DisguiseBase disguise, boolean refreshTrackers, Player... players) - { - if (!disguise.GetEntity().isAlive()) - return; - - if (!_bedPackets && disguise instanceof DisguisePlayer && ((DisguisePlayer) disguise).getSleepingDirection() != null) - { - _bedPackets = true; - - for (Player player : Bukkit.getOnlinePlayers()) + for (Entity entity : careAbout) { - UtilPlayer.sendPacket(player, getBedChunkLoadPackets(player, player.getLocation())); - } - } - - if (players.length != 0) - { - disguise.Global = false; - } - - _spawnPacketMap.put(disguise.GetEntityId(), disguise); - _disguisePlayerMap.put(disguise, new HashSet()); - - if (disguise instanceof DisguiseRabbit) - { - _lastRabbitHop.put(disguise.GetEntityId(), new NautHashMap()); - } - - for (Player player : players) - addViewerToDisguise(disguise, player, false); - - if (disguise.GetEntity() instanceof EntityPlayer && disguise instanceof DisguisePlayer) - { - if (!(disguise.GetEntity()).getName().equalsIgnoreCase(((DisguisePlayer) disguise).getName())) - { - _blockedNames.add((disguise.GetEntity()).getName()); - } - } - - if (refreshTrackers) - { - refreshTrackers(disguise.GetEntity().getBukkitEntity(), - disguise.Global ? Bukkit.getOnlinePlayers().toArray(new Player[0]) : players); - } - } - - public void disguise(DisguiseBase disguise, Player... players) - { - disguise(disguise, true, players); - } - - public PacketPlayOutMapChunk[] getBedChunkLoadPackets(Player player, Location newLoc) - { - prepareChunk(newLoc); - - PacketPlayOutMapChunk[] packets = new PacketPlayOutMapChunk[2]; - - // Make unload - packets[0] = new PacketPlayOutMapChunk(_bedChunk, true, 0); - - // Make load - packets[1] = new PacketPlayOutMapChunk(_bedChunk, true, '\uffff'); - - return packets; - } - - public Packet getBedChunkUnloadPacket(Player player, Location oldLoc) - { - prepareChunk(oldLoc); - - return new PacketPlayOutMapChunk(_bedChunk, true, 0); - } - - private Packet[] getBedPackets(Location recieving, DisguisePlayer playerDisguise) - { - try - { - PacketPlayOutBed bedPacket = new PacketPlayOutBed(); - - bedPacket.a = playerDisguise.GetEntityId(); - - int chunkX = getChunk(recieving.getX()); - int chunkZ = getChunk(recieving.getZ()); - - bedPacket.b = new BlockPosition((chunkX * 16) + 1 + playerDisguise.getSleepingDirection().getModX(), 0, (chunkZ * 16) - + 1 + playerDisguise.getSleepingDirection().getModZ()); - - PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(playerDisguise.GetEntity()); - - teleportPacket.c += (int) (0.35D * 32); - - return new Packet[] + if (!entity.isValid()) { - bedPacket, teleportPacket - }; - } - catch (Exception ex) - { - ex.printStackTrace(); - } - - return null; + _entityDisguiseMap.put(entity.getUniqueId(), _spawnPacketMap.remove(entity.getEntityId())); + } + } + }); } - private int getChunk(double block) + private boolean containsSpawnDisguise(Player owner, DisguiseBase disguise) { - int chunk = (int) Math.floor(block / 16D) - 17; - chunk -= chunk % 8; - return chunk; + return disguise != null && (_disguisePlayerMap.containsKey(disguise) && _disguisePlayerMap.get(disguise).test(owner)); } - private ArrayList getChunkMovePackets(Player player, Location newLoc, Location oldLoc) + public void disguise(DisguiseBase disguise, Runnable after) { - ArrayList packets = new ArrayList(); + disguise(disguise, after, player -> true); + } - if (newLoc != null) + public void disguise(DisguiseBase disguise, Predicate accept) + { + disguise(disguise, null, accept); + } + + public void disguise(DisguiseBase disguise) + { + disguise(disguise, null, t -> true); + } + + public void disguise(DisguiseBase disguise, Runnable after, Predicate accept) + { + UtilTasks.onMainThread(() -> { - packets.addAll(Arrays.asList(getBedChunkLoadPackets(player, newLoc))); + // First, add everything to handle future disguises + DisguiseBase before = null; - EntityPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + LinkedList disguises = _spawnPacketMap.computeIfAbsent(disguise.getEntityId(), key -> new LinkedList<>()); - for (Entry> entry : _disguisePlayerMap.entrySet()) + before = disguises.peekFirst(); + + disguises.addFirst(disguise); + + _disguisePlayerMap.put(disguise, accept); + + // If the entity hasn't been spawned in yet, try to spawn it in and if that fails, remove everything + + boolean spawnedIn = false; + + if (!disguise.getEntity().valid) { - if (entry.getKey().Global || entry.getValue().contains(player)) + disguise.attemptToSpawn(); + if (!disguise.getEntity().valid) { - EntityTrackerEntry tracker = getEntityTracker(entry.getKey().GetEntity()); + disguises.remove(disguise); + _disguisePlayerMap.remove(disguise); + return; + } + spawnedIn = true; + } - if (tracker != null && tracker.trackedPlayers.contains(nmsPlayer)) + if (before != null) + { + before.onTransfer(disguise); + } + + // todo figure out what this does + if (disguise.getEntity() instanceof EntityPlayer && disguise instanceof DisguisePlayer) + { + if (!(disguise.getEntity()).getName().equalsIgnoreCase(((DisguisePlayer) disguise).getName())) + { + _blockedNames.add(disguise.getEntity().getName()); + } + } + + if (!spawnedIn) + { + refreshTrackers(disguise.getEntity().getBukkitEntity()); + } + + disguise.onDisguise(true); + + if (after != null) + { + after.run(); + } + }).run(); + } + + public boolean undisguise(DisguiseBase originalDisguise) + { + return undisguise(originalDisguise, UndisguiseReason.EXPLICIT); + } + + public boolean undisguise(DisguiseBase originalDisguise, UndisguiseReason reason) + { + if (originalDisguise == null) return false; + if (originalDisguise.getEntity() == null) return false; + + net.minecraft.server.v1_8_R3.Entity entity = originalDisguise.getEntity(); + + LinkedList activeDisguises = this._spawnPacketMap.get(originalDisguise.getEntityId()); + + if (activeDisguises == null) return false; + + if (!activeDisguises.contains(originalDisguise)) return false; + + if (entity.getBukkitEntity() instanceof Player) + { + _blockedNames.remove(entity.getName()); + } + + Predicate test = _disguisePlayerMap.remove(originalDisguise); + + if (originalDisguise instanceof DisguisePlayer) + { + for (Player player : UtilServer.getPlayersCollection()) + { + if (test.test(player)) + { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + entityPlayer.playerConnection.networkManager.handle(((DisguisePlayer) originalDisguise).getUndisguiseInfoPackets(true)); + if (reason != UndisguiseReason.QUIT) { - if (entry.getKey() instanceof DisguisePlayer - && ((DisguisePlayer) entry.getKey()).getSleepingDirection() != null) - { - - packets.addAll(Arrays.asList(getBedPackets(newLoc, (DisguisePlayer) entry.getKey()))); - } + entityPlayer.playerConnection.networkManager.handle(((DisguisePlayer) originalDisguise).getUndisguiseInfoPackets(false)); } } } } - if (oldLoc != null) + int index = activeDisguises.indexOf(originalDisguise); + + activeDisguises.remove(originalDisguise); + + if (activeDisguises.size() == 0) + _spawnPacketMap.remove(originalDisguise.getEntityId()); + + if (index == 0) { - packets.add(getBedChunkUnloadPacket(player, oldLoc)); + originalDisguise.onUndisguise(true); + if (activeDisguises.size() > 0) + { + activeDisguises.getFirst().onReturn(originalDisguise); + } + + if (reason != UndisguiseReason.QUIT) + { + refreshTrackers(entity.getBukkitEntity()); + } + } + else + { + originalDisguise.onUndisguise(false); } - return packets; + return true; } + @Deprecated + public void undisguise(Entity entity) + { + undisguise(getActiveDisguise(entity), UndisguiseReason.EXPLICIT); + } + + @Deprecated + /* + * @Deprecated Use getActiveDisguise instead + */ public DisguiseBase getDisguise(LivingEntity entity) + { + return getActiveDisguise(entity); + } + + public DisguiseBase getActiveDisguise(Entity entity) + { + return getActiveDisguise(entity.getEntityId()); + } + + public DisguiseBase getActiveDisguise(int entityId) + { + LinkedList list = _spawnPacketMap.get(entityId); + if (list != null && list.size() > 0) + { + return list.getFirst(); + } + return null; + } + + public LinkedList getAllDisguises(Entity entity) { return _spawnPacketMap.get(entity.getEntityId()); } private EntityTrackerEntry getEntityTracker(net.minecraft.server.v1_8_R3.Entity entity) { - return (EntityTrackerEntry) ((WorldServer) entity.world).tracker.trackedEntities.get(entity.getId()); + return ((WorldServer) entity.world).tracker.trackedEntities.get(entity.getId()); } public void handle(PacketInfo packetInfo) @@ -482,69 +339,27 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler final Player owner = packetInfo.getPlayer(); final PacketVerifier packetVerifier = packetInfo.getVerifier(); - if (packet instanceof PacketPlayOutRelEntityMoveLook || packet instanceof PacketPlayOutRelEntityMove) - { - int entityId = -1; - - if (packet instanceof PacketPlayOutRelEntityMoveLook) - { - entityId = ((PacketPlayOutRelEntityMoveLook) packet).a; - }/* - else if (packet instanceof PacketPlayOutEntityLook) - { - entityId = ((PacketPlayOutEntityLook) packet).a; - }*/ - else if (packet instanceof PacketPlayOutRelEntityMove) - { - PacketPlayOutRelEntityMove rPacket = (PacketPlayOutRelEntityMove) packet; - - if (rPacket.b != 0 || rPacket.c != 0 || rPacket.d != 0) - { - entityId = rPacket.a; - } - } - /*else if (packet instanceof PacketPlayOutEntityTeleport) - { - entityId = ((PacketPlayOutEntityTeleport) packet).a; - }*/ - - if (_lastRabbitHop.containsKey(entityId)) - { - NautHashMap rabbitHops = _lastRabbitHop.get(entityId); - - if (rabbitHops != null) - { - long last = rabbitHops.containsKey(owner.getEntityId()) ? System.currentTimeMillis() - - rabbitHops.get(owner.getEntityId()) : 1000; - - if (last > 500 || last < 100) - { - rabbitHops.put(owner.getEntityId(), System.currentTimeMillis()); - - PacketPlayOutEntityStatus entityStatus = new PacketPlayOutEntityStatus(); - - entityStatus.a = entityId; - entityStatus.b = (byte) 1; - - handlePacket(entityStatus, packetVerifier); - } - } - } - } - if (packet instanceof PacketPlayOutPlayerInfo) { - for (PlayerInfoData info : ((PacketPlayOutPlayerInfo) packet).b) + PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = ((PacketPlayOutPlayerInfo) packet); + Iterator iterator = packetPlayOutPlayerInfo.b.iterator(); + while (iterator.hasNext()) { - if (_blockedNames.contains(info.a().getName())) + PacketPlayOutPlayerInfo.PlayerInfoData next = iterator.next(); + if (_blockedNames.contains(next.a().getName())) { - packetInfo.setCancelled(true); - break; + iterator.remove(); } } + + if (packetPlayOutPlayerInfo.b.size() == 0) + { + packetInfo.setCancelled(true); + } } - else if (packet instanceof PacketPlayOutSpawnEntity || packet instanceof PacketPlayOutSpawnEntityLiving - || packet instanceof PacketPlayOutNamedEntitySpawn) + else if (packet instanceof PacketPlayOutSpawnEntity || + packet instanceof PacketPlayOutSpawnEntityLiving || + packet instanceof PacketPlayOutNamedEntitySpawn) { int entityId = -1; @@ -561,271 +376,128 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler entityId = ((PacketPlayOutNamedEntitySpawn) packet).a; } - if (_futureDisguises.containsKey(entityId)) + DisguiseBase latestDisguise = getActiveDisguise(entityId); + + if (latestDisguise != null) { - Entry entry = _futureDisguises.remove(entityId); - - Entity entity = UtilEnt.getEntityById(entityId); - - if (entity != null) + if (containsSpawnDisguise(owner, latestDisguise)) { - entry.getKey().setEntity(entity); + packetInfo.setCancelled(true); - boolean cancel = entry.getValue().length == 0; - - for (Player player : entry.getValue()) - { - if (player == owner) - { - cancel = true; - break; - } - } - - if (cancel) - { - packetInfo.setCancelled(true); - } - - disguise(entry.getKey(), false, entry.getValue()); + handleSpawnPackets(packetInfo.getVerifier(), latestDisguise); + } + else if (latestDisguise.isHideIfNotDisguised()) + { + packetInfo.setCancelled(true); } - } - - if (_spawnPacketMap.containsKey(entityId) - && (_spawnPacketMap.get(entityId).Global || _disguisePlayerMap.get(_spawnPacketMap.get(entityId)).contains( - owner))) - { - packetInfo.setCancelled(true); - - handleSpawnPackets(packetInfo, _spawnPacketMap.get(entityId)); } } else if (packet instanceof PacketPlayOutUpdateAttributes) { int entityId = ((PacketPlayOutUpdateAttributes) packet).a; - if (_spawnPacketMap.containsKey(entityId) - && owner.getEntityId() != entityId - && (_spawnPacketMap.get(entityId).Global || _disguisePlayerMap.get(_spawnPacketMap.get(entityId)).contains( - owner))) + DisguiseBase latestDisguise = getActiveDisguise(entityId); + + if (latestDisguise != null && containsSpawnDisguise(owner, latestDisguise)) { // Crash clients with meta to a block id. - if (_spawnPacketMap.get(entityId) instanceof DisguiseBlock) + if (latestDisguise instanceof DisguiseBlock) packetInfo.setCancelled(true); } } - /* - * Why is this here??? - else if (packet instanceof PacketPlayOutAnimation) - { - int entityId = ((PacketPlayOutAnimation) packet).a; - - if (containsSpawnDisguise(owner, entityId) && owner.getEntityId() != entityId) - { - packetInfo.setCancelled(true); - } - } - */ else if (packet instanceof PacketPlayOutEntityMetadata) { int entityId = ((PacketPlayOutEntityMetadata) packet).a; - if (containsSpawnDisguise(owner, entityId) && owner.getEntityId() != entityId) + DisguiseBase latestDisguise = getActiveDisguise(entityId); + + if (latestDisguise != null && containsSpawnDisguise(owner, latestDisguise) && owner.getEntityId() != entityId) { - handlePacket(_spawnPacketMap.get(entityId).GetMetaDataPacket(), packetVerifier); packetInfo.setCancelled(true); + handlePacket(latestDisguise.getMetadataPacket(), packetVerifier); } } else if (packet instanceof PacketPlayOutEntityEquipment) { int entityId = ((PacketPlayOutEntityEquipment) packet).a; - if (containsSpawnDisguise(owner, entityId) && _spawnPacketMap.get(entityId) instanceof DisguiseInsentient) + DisguiseBase latestDisguise = getActiveDisguise(entityId); + + if (latestDisguise != null && containsSpawnDisguise(owner, latestDisguise) && latestDisguise instanceof DisguiseInsentient) { - if (!((DisguiseInsentient) _spawnPacketMap.get(entityId)).armorVisible() - && ((PacketPlayOutEntityEquipment) packet).b != 0) + if (!((DisguiseInsentient) latestDisguise).armorVisible() && ((PacketPlayOutEntityEquipment) packet).b != 0) { packetInfo.setCancelled(true); } } } - else if (packet instanceof PacketPlayOutEntityVelocity) - { - PacketPlayOutEntityVelocity velocityPacket = (PacketPlayOutEntityVelocity) packet; - - // Only for viewers - if (velocityPacket.a == owner.getEntityId()) - { - if (velocityPacket.c > 0) - _goingUp.add(velocityPacket.a); - } - else if (velocityPacket.b == 0 && velocityPacket.c == 0 && velocityPacket.d == 0) - { - return; - } - else if (_spawnPacketMap.containsKey(velocityPacket.a)) - { - packetInfo.setCancelled(true); - } - } - else if (packet instanceof PacketPlayOutRelEntityMove) - { - final PacketPlayOutRelEntityMove movePacket = (PacketPlayOutRelEntityMove) packet; - - // Only for viewers - if (movePacket.a == owner.getEntityId()) - return; - - if (_goingUp.contains(movePacket.a) && movePacket.c != 0 && movePacket.c < 20) - { - _goingUp.remove(movePacket.a); - _movePacketMap.remove(movePacket.a); - } - - if (!containsSpawnDisguise(owner, movePacket.a)) - return; - - final PacketPlayOutEntityVelocity velocityPacket = new PacketPlayOutEntityVelocity(); - velocityPacket.a = movePacket.a; - velocityPacket.b = movePacket.b * 100; - velocityPacket.c = movePacket.c * 100; - velocityPacket.d = movePacket.d * 100; - - if (_movePacketMap.containsKey(movePacket.a)) - { - PacketPlayOutEntityVelocity lastVelocityPacket = _movePacketMap.get(movePacket.a); - - velocityPacket.b = (int) (.8 * lastVelocityPacket.b); - velocityPacket.c = (int) (.8 * lastVelocityPacket.c); - velocityPacket.d = (int) (.8 * lastVelocityPacket.d); - } - - _movePacketMap.put(movePacket.a, velocityPacket); - - packetVerifier.bypassProcess(velocityPacket); - - if (_goingUp.contains(movePacket.a) && movePacket.c != 0 && movePacket.c > 20) - { - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() - { - public void run() - { - packetVerifier.bypassProcess(velocityPacket); - } - }); - } - - if (_spawnPacketMap.get(movePacket.a) instanceof DisguiseBlock) - { - - } - } - else if (packet instanceof PacketPlayOutRelEntityMoveLook) - { - final PacketPlayOutRelEntityMoveLook movePacket = (PacketPlayOutRelEntityMoveLook) packet; - - // Only for viewers - if (movePacket.a == owner.getEntityId()) - return; - - if (_goingUp.contains(movePacket.a) && movePacket.c != 0 && movePacket.c <= 20) - { - _goingUp.remove(movePacket.a); - _movePacketMap.remove(movePacket.a); - } - - if (!containsSpawnDisguise(owner, movePacket.a)) - return; - - final PacketPlayOutEntityVelocity velocityPacket = new PacketPlayOutEntityVelocity(); - velocityPacket.a = movePacket.a; - velocityPacket.b = movePacket.b * 100; - velocityPacket.c = movePacket.c * 100; - velocityPacket.d = movePacket.d * 100; - - if (_movePacketMap.containsKey(movePacket.a)) - { - PacketPlayOutEntityVelocity lastVelocityPacket = _movePacketMap.get(movePacket.a); - - velocityPacket.b = (int) (.8 * lastVelocityPacket.b); - velocityPacket.c = (int) (.8 * lastVelocityPacket.c); - velocityPacket.d = (int) (.8 * lastVelocityPacket.d); - } - - _movePacketMap.put(movePacket.a, velocityPacket); - - packetVerifier.bypassProcess(velocityPacket); - - if (_goingUp.contains(movePacket.a) && movePacket.c != 0 && movePacket.c > 20) - { - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() - { - public void run() - { - packetVerifier.bypassProcess(velocityPacket); - } - }); - } - } } private void handlePacket(Packet packet, PacketVerifier verifier) { + if (packet == null) return; _handlingPacket = true; verifier.process(packet); _handlingPacket = false; } - private void handleSpawnPackets(PacketInfo packetInfo, DisguiseBase disguise) + private void handleSpawnPackets(PacketVerifier packetVerifier, DisguiseBase disguise) { - final Player player = packetInfo.getPlayer(); - - final PacketVerifier packetVerifier = packetInfo.getVerifier(); - if (disguise instanceof DisguisePlayer) { - final DisguisePlayer pDisguise = (DisguisePlayer) disguise; - handlePacket(pDisguise.getNewInfoPacket(true), packetVerifier); - - PacketPlayOutNamedEntitySpawn namePacket = pDisguise.spawnBeforePlayer(player.getLocation()); - - namePacket.i.watch(0, (byte) 32, net.minecraft.server.v1_8_R3.Entity.META_ENTITYDATA, (byte) 32); - - handlePacket(namePacket, packetVerifier); - - if (pDisguise.getSleepingDirection() != null) + Packet infoPacket = pDisguise.getDisguiseInfoPackets(false); + if (infoPacket != null) { - for (Packet packet : getBedPackets(player.getLocation(), pDisguise)) - { - handlePacket(packet, packetVerifier); - } + handlePacket(infoPacket, packetVerifier); + } - } - else + infoPacket = pDisguise.getDisguiseInfoPackets(true); + if (infoPacket != null) { - handlePacket(new PacketPlayOutEntityTeleport(pDisguise.GetEntity()), packetVerifier); + handlePacket(infoPacket, packetVerifier); } + handlePacket(pDisguise.getSpawnPacket(), packetVerifier); + for (Packet packet : pDisguise.getEquipmentPackets()) { handlePacket(packet, packetVerifier); } - handlePacket(pDisguise.GetMetaDataPacket(), packetVerifier); + handlePacket(pDisguise.getMetadataPacket(), packetVerifier); - Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() + if (pDisguise.getSleepingDirection() != null) { - public void run() + for (Packet packet : getBedPackets(pDisguise)) { - handlePacket(pDisguise.getNewInfoPacket(false), packetVerifier); + handlePacket(packet, packetVerifier); } - }, 6); + } + + if (!pDisguise.showInTabList()) + { + Runnable r = () -> + { + PacketPlayOutPlayerInfo playerInfoPacketRemove = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoPacketRemove.new PlayerInfoData(pDisguise.getProfile(), 0, WorldSettings.EnumGamemode.SURVIVAL, null); + playerInfoPacketRemove.b.add(dataRemove); + handlePacket(playerInfoPacketRemove, packetVerifier); + }; + if (pDisguise.getShowInTabListDelay() == 0) + { + r.run(); + } + else + { + Bukkit.getScheduler().runTaskLater(UtilServer.getPlugin(), r, pDisguise.getShowInTabListDelay()); + } + } } else { - handlePacket(disguise.GetSpawnPacket(), packetVerifier); + handlePacket(disguise.getSpawnPacket(), packetVerifier); if (disguise instanceof DisguiseLiving) { @@ -844,233 +516,80 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler return _spawnPacketMap.containsKey(entity.getEntityId()); } - @EventHandler + @EventHandler(priority = EventPriority.MONITOR) public void PlayerQuit(PlayerQuitEvent event) { - for (DisguiseBase disguise : _disguisePlayerMap.keySet()) - { - _disguisePlayerMap.get(disguise).remove(event.getPlayer()); - } - - for (Integer disguise : _lastRabbitHop.keySet()) - { - _lastRabbitHop.get(disguise).remove(event.getPlayer().getEntityId()); - } - - undisguise(event.getPlayer()); + while (getActiveDisguise(event.getPlayer()) != null) + undisguise(getActiveDisguise(event.getPlayer()), UndisguiseReason.QUIT); } - private void prepareChunk(Location loc) + private void refreshTrackers(Entity entity) { - int chunkX = getChunk(loc.getX()); - int chunkZ = getChunk(loc.getZ()); + DisguiseBase activeDisguise = getActiveDisguise(entity); + Predicate tester = _disguisePlayerMap.getOrDefault(activeDisguise, test -> true); - try - { - _xChunk.set(_bedChunk, chunkX); - _zChunk.set(_bedChunk, chunkZ); - } - catch (Exception ex) - { - ex.printStackTrace(); - } - } - - private void refreshBedTrackers(final Player player) - { - for (final DisguiseBase disguise : this._disguisePlayerMap.keySet()) - { - if (!(disguise instanceof DisguisePlayer) || ((DisguisePlayer) disguise).getSleepingDirection() == null) - { - continue; - } - - final EntityTrackerEntry entityTracker = getEntityTracker(disguise.GetEntity()); - - if (entityTracker != null) - { - if (!entityTracker.trackedPlayers.contains(((CraftPlayer) player).getHandle())) - { - continue; - } - - Packet destroyPacket = new PacketPlayOutEntityDestroy(new int[] - { - disguise.GetEntityId() - }); - - entityTracker.clear(((CraftPlayer) player).getHandle()); - - UtilPlayer.sendPacket(player, destroyPacket); - - final World world = disguise.GetEntity().getBukkitEntity().getWorld(); - - Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() - { - public void run() - { - try - { - Entity entity = disguise.GetEntity().getBukkitEntity(); - - if (entity.getWorld() == world && entity.isValid()) - { - if (player.isOnline() && player.getWorld() == entity.getWorld()) - { - entityTracker.updatePlayer(((CraftPlayer) player).getHandle()); - } - } - } - catch (Exception ex) - { - ex.printStackTrace(); - } - } - }, 5); - } - } - } - - private void refreshTrackers(final Entity entity, final Player[] players) - { final EntityTrackerEntry entityTracker = getEntityTracker(((CraftEntity) entity).getHandle()); if (entityTracker != null) { - Packet destroyPacket = new PacketPlayOutEntityDestroy(new int[] - { - entity.getEntityId() - }); - - for (Player player : players) + if (entity.isValid()) { - entityTracker.clear(((CraftPlayer) player).getHandle()); - - UtilPlayer.sendPacket(player, destroyPacket); - } - - final World world = entity.getWorld(); - - Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), new Runnable() - { - public void run() + for (Player player : PlayerSelector.selectPlayers( + PlayerSelector.and( + PlayerSelector.inWorld(entity.getWorld()), + OfflinePlayer::isOnline, + tester + ) + ) + ) { - try + EntityPlayer handle = ((CraftPlayer) player).getHandle(); + entityTracker.clear(handle); + runSyncLater(() -> { - if (entity.getWorld() == world && entity.isValid()) - { - for (Player player : players) - { - if (player.isOnline() && player.getWorld() == entity.getWorld()) - { - entityTracker.updatePlayer(((CraftPlayer) player).getHandle()); - } - } - } - } - catch (Exception ex) - { - ex.printStackTrace(); - } - } - }, 5); - } - } - - public void removeViewerToDisguise(DisguiseBase disguise, Player player) - { - _disguisePlayerMap.get(disguise).remove(player); - - refreshTrackers(disguise.GetEntity().getBukkitEntity(), new Player[] - { - player - }); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void switchedWorld(PlayerChangedWorldEvent event) - { - if (!_bedPackets) - return; - - chunkMove(event.getPlayer(), event.getPlayer().getLocation(), null); - } - - @EventHandler - public void TeleportDisguises(UpdateEvent event) - { - if (event.getType() != UpdateType.SEC) - return; - - TimingManager.startTotal("Teleport Disguises"); - for (Player player : Bukkit.getOnlinePlayers()) - { - for (Player otherPlayer : Bukkit.getOnlinePlayers()) - { - if (player == otherPlayer) - continue; - - if (otherPlayer.getLocation().subtract(0, .5, 0).getBlock().getTypeId() != 0) - UtilPlayer.sendPacket(player, new PacketPlayOutEntityTeleport( - ((CraftPlayer) otherPlayer).getHandle())); - } - } - TimingManager.stopTotal("Teleport Disguises"); - } - - public void undisguise(LivingEntity entity) - { - if (!_spawnPacketMap.containsKey(entity.getEntityId())) - return; - - _lastRabbitHop.remove(entity.getEntityId()); - DisguiseBase disguise = _spawnPacketMap.remove(entity.getEntityId()); - Collection extends Player> players = (disguise.Global ? Bukkit.getOnlinePlayers() : _disguisePlayerMap.remove(disguise)); - - _movePacketMap.remove(entity.getEntityId()); - _moveTempMap.remove(entity.getEntityId()); - - if (entity instanceof Player) - { - _blockedNames.remove(((Player) entity).getName()); - } - - refreshTrackers(entity, players.toArray(new Player[0])); - - if (_bedPackets && disguise instanceof DisguisePlayer && ((DisguisePlayer) disguise).getSleepingDirection() != null) - { - for (DisguiseBase dis : _disguisePlayerMap.keySet()) - { - if (dis instanceof DisguisePlayer && ((DisguisePlayer) dis).getSleepingDirection() != null) - { - return; + /* + * This is like, the hackiest shit ever. + * + * Basically, we need to delay by an arbitrary amount of ticks (in this case, 5) because of the client. + * + * In the client, the renderer renders batches of 16x16x16, and entites are stored in ChunkSections. + * However, the data structure used is a HashMultimap, and the hashCode() method for Entity simply returns its entity id + * + * Now, due to an unfortunate coincidence, sending a PacketPlayOutEntityDestroy does not immediately remove an entity from the client. + * Instead, it queues it for removal on the next tick (why tf). This means that if we send a destroy and spawn packet one after the other, + * the process looks something like this + * + * Received PacketPlayOutEntityDestroy + * Queue removal of original entity + * Received PacketPlayOutSpawnLivingEntity + * Register entity in ChunkSection (based on entity id) + * --- next tick --- + * Removal of original entity from ChunkSection (which is now the new disguised entity + * + * So, what can we do? + * + * We could do this, where we delay an arbitrary amount of time and hope that the client processes the tick. + * However, a better long term solution would be to rewrite entity ids properly + */ + entityTracker.updatePlayer(((CraftPlayer) player).getHandle()); + }, 5L); } } - - unregisterBedChunk(); - } - } - - private void unregisterBedChunk() - { - _bedPackets = false; - - for (Player player : Bukkit.getOnlinePlayers()) - { - chunkMove(player, null, player.getLocation()); } } public void updateDisguise(DisguiseBase disguise) { - Collection extends Player> players = (disguise.Global ? Bukkit.getOnlinePlayers() : _disguisePlayerMap.get(disguise)); - - for (Player player : players) + Predicate tester = _disguisePlayerMap.get(disguise); + for (Player player : Bukkit.getOnlinePlayers()) { - if (disguise.GetEntity() == ((CraftPlayer) player).getHandle()) - continue; + if (tester.test(player)) + { + if (disguise.getEntity() == ((CraftPlayer) player).getHandle()) + continue; - UtilPlayer.sendPacket(player, disguise.GetMetaDataPacket()); + UtilPlayer.sendPacket(player, disguise.getMetadataPacket()); + } } } @@ -1080,27 +599,154 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler if (event.getType() != UpdateType.SLOWER || _disguisePlayerMap.isEmpty()) return; - for (Iterator disguiseIterator = _disguisePlayerMap.keySet().iterator(); disguiseIterator.hasNext();) + for (Iterator disguiseIterator = _disguisePlayerMap.keySet().iterator(); disguiseIterator.hasNext(); ) { DisguiseBase disguise = disguiseIterator.next(); - if (!(disguise.GetEntity() instanceof EntityPlayer)) + if (!(disguise.getEntity() instanceof EntityPlayer)) continue; - EntityPlayer disguisedPlayer = (EntityPlayer) disguise.GetEntity(); + EntityPlayer disguisedPlayer = (EntityPlayer) disguise.getEntity(); if (Bukkit.getPlayerExact(disguisedPlayer.getName()) == null || !disguisedPlayer.isAlive() || !disguisedPlayer.valid) disguiseIterator.remove(); - else - { - for (Iterator playerIterator = _disguisePlayerMap.get(disguise).iterator(); playerIterator.hasNext();) - { - Player player = playerIterator.next(); - - if (!player.isOnline() || !player.isValid()) - playerIterator.remove(); - } - } } } + + public enum UndisguiseReason + { + EXPLICIT, + QUIT + } + + /* + * ================================= + * HERE BEGINS STUFF SOLELY TO DEAL + * WITH MAKING PLAYERS LOOK LIKE + * THEY'RE ON BEDS + * + * DON'T TOUCH UNLESS YOU KNOW + * EXACTLY WHAT YOU'RE DOING + * ================================= + */ + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void switchedWorld(PlayerChangedWorldEvent event) + { + chunkMove(event.getPlayer()); + } + + @EventHandler + public void chunkJoin(PlayerJoinEvent event) + { + chunkMove(event.getPlayer()); + } + + private void chunkMove(Player player) + { + List packets = new ArrayList<>(); + + PacketPlayOutMapChunk chunk = new PacketPlayOutMapChunk(_bedChunk, true, '\uffff'); + chunk.a = BED_POS_NORTH[0] >> 4; + chunk.b = BED_POS_NORTH[2] >> 4; + + packets.add(chunk); + + EntityPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + + _spawnPacketMap.entrySet().stream() + .filter(entry -> entry.getValue().size() > 0 && entry.getValue().getFirst() instanceof DisguisePlayer && ((DisguisePlayer) entry.getValue().getFirst()).getSleepingDirection() != null) + .filter(entry -> this.containsSpawnDisguise(player, entry.getValue().getFirst())) + .forEach(entry -> + { + EntityTrackerEntry tracker = getEntityTracker(entry.getValue().getFirst().getEntity()); + + if (tracker != null && tracker.trackedPlayers.contains(nmsPlayer)) + { + packets.addAll(getBedPackets((DisguisePlayer) entry.getValue().getFirst())); + } + }); + + for (Packet packet : packets) + { + UtilPlayer.sendPacket(player, packet); + } + } + + /* + * Create the packets needed to make this DisguisePlayer appear as though laying on a bed + * + * fixme can we make this better at all?!?!?! + */ + private List getBedPackets(DisguisePlayer playerDisguise) + { + int[] coords = getCoordsFor(playerDisguise); + + List packets = new ArrayList<>(); + PacketPlayOutBed bedPacket = new PacketPlayOutBed(); + bedPacket.a = playerDisguise.getEntityId(); + bedPacket.b = new BlockPosition(coords[0], coords[1], coords[2]); + packets.add(bedPacket); + + int partitions = 3; + double posX = coords[0], posY = coords[1], posZ = coords[2]; + double targetX = playerDisguise.getEntity().locX, targetY = playerDisguise.getEntity().locY, targetZ = playerDisguise.getEntity().locZ; + + while (partitions > 1) + { + double d0 = posX + (targetX - posX) / (double) partitions; + double d1 = posY + (targetY - posY) / (double) partitions; + double d2 = posZ + (targetZ - posZ) / (double) partitions; + + + PacketPlayOutMapChunk chunk = new PacketPlayOutMapChunk(_bedChunk, true, '\uffff'); + chunk.a = (int) Math.floor(d0) >> 4; + chunk.b = (int) Math.floor(d2) >> 4; + packets.add(chunk); + partitions--; + + posX = d0; + posY = d1; + posZ = d2; + } + + PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(playerDisguise.getEntity()); + packets.add(teleportPacket); + + return packets; + } + + + private static final int[] BED_POS_NORTH = {-29999999, 0, -29999999}; + private static final int[] BED_POS_SOUTH = {-29999999, 0, -29999998}; + private static final int[] BED_POS_EAST = {-29999999, 0, -29999997}; + private static final int[] BED_POS_WEST = {-29999999, 0, -29999996}; + + private Chunk _bedChunk; + + private void createBedChunk() + { + this._bedChunk = new Chunk(MinecraftServer.getServer().getWorld(), 0, 0); + this._bedChunk.a(new BlockPosition(BED_POS_NORTH[0], BED_POS_NORTH[1], BED_POS_NORTH[2]), Blocks.BED.getBlockData().set(BlockBed.FACING, EnumDirection.NORTH)); + this._bedChunk.a(new BlockPosition(BED_POS_SOUTH[0], BED_POS_SOUTH[1], BED_POS_SOUTH[2]), Blocks.BED.getBlockData().set(BlockBed.FACING, EnumDirection.SOUTH)); + this._bedChunk.a(new BlockPosition(BED_POS_EAST[0], BED_POS_EAST[1], BED_POS_EAST[2]), Blocks.BED.getBlockData().set(BlockBed.FACING, EnumDirection.EAST)); + this._bedChunk.a(new BlockPosition(BED_POS_WEST[0], BED_POS_WEST[1], BED_POS_WEST[2]), Blocks.BED.getBlockData().set(BlockBed.FACING, EnumDirection.WEST)); + } + + private int[] getCoordsFor(DisguisePlayer player) + { + BlockFace facing = player.getSleepingDirection(); + switch (facing) + { + case NORTH: + return BED_POS_SOUTH; + case SOUTH: + return BED_POS_NORTH; + case EAST: + return BED_POS_WEST; + case WEST: + return BED_POS_EAST; + } + throw new IllegalArgumentException("Unsupported blockface " + facing); + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguisePlayerBean.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguisePlayerBean.java deleted file mode 100644 index 3403768bb..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/DisguisePlayerBean.java +++ /dev/null @@ -1,34 +0,0 @@ -package mineplex.core.disguise; - -import mineplex.serverdata.data.Data; - -public class DisguisePlayerBean implements Data -{ - private int _accountID; - private String _disguisedPlayer; - private String _playerName; - public DisguisePlayerBean(int playerAccountID, String playerName, String disguiseAs) - { - this._accountID = playerAccountID; - this._disguisedPlayer = disguiseAs; - this._playerName = playerName; - - } - public int getAccountID() - { - return _accountID; - } - public String getDisguisedPlayer() - { - return _disguisedPlayer; - } - public String getPlayerName() - { - return _playerName; - } - @Override - public String getDataId() - { - return _accountID+_playerName; - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/PlayerDisguiseManager.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/PlayerDisguiseManager.java deleted file mode 100644 index 82e27bb5f..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/PlayerDisguiseManager.java +++ /dev/null @@ -1,71 +0,0 @@ -package mineplex.core.disguise; - -import mineplex.core.MiniPlugin; -import mineplex.core.account.CoreClient; -import mineplex.core.account.CoreClientManager; -import mineplex.core.common.Rank; -import mineplex.serverdata.Region; -import mineplex.serverdata.redis.RedisDataRepository; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.event.EventHandler; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; - -public class PlayerDisguiseManager extends MiniPlugin -{ - private CoreClientManager _clients; - private RedisDataRepository _redis; - public PlayerDisguiseManager(JavaPlugin plugin, CoreClientManager clients) - { - super("Player Disguise Manager", plugin); - this._clients = clients; - - _redis = new RedisDataRepository(Region.ALL, DisguisePlayerBean.class, "disguisedPlayer"); - } - - @EventHandler - public void onDisguisedPlayerQuit(PlayerQuitEvent event) - { - CoreClient client = _clients.Get(event.getPlayer()); - if(client.isDisguised()) - { - _redis.addElement(new DisguisePlayerBean(client.getAccountId(), client.GetPlayerName(), client.getDisguisedAs()), 60*60*12); // 12 hours - } - } - - @EventHandler - public void onDisguisedPlayerJoin(PlayerJoinEvent event) - { - new BukkitRunnable() - { - @Override - public void run() - { - CoreClient client = _clients.Get(event.getPlayer()); - - if(!client.GetRank().has(Rank.JNR_DEV) && client.GetRank() != Rank.YOUTUBE_SMALL && client.GetRank() != Rank.TWITCH && client.GetRank() != Rank.YOUTUBE) - return; - - if(_redis.elementExists(client.getAccountId()+client.GetPlayerName())) - { - DisguisePlayerBean bean = _redis.getElement(client.getAccountId()+client.GetPlayerName()); - Bukkit.getPluginManager().callEvent(new PlayerCommandPreprocessEvent(event.getPlayer(), "/Disguise " + bean.getDisguisedPlayer())); - event.setJoinMessage(""); - } - } - }.runTaskLater(getPlugin(), 7); - } - - @EventHandler - public void onPlayerUndisguise(PlayerUndisguiseEvent event) - { - CoreClient client = _clients.Get(event.getPlayer()); - _redis.removeElement(client.getAccountId()+client.GetPlayerName()); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseAmbient.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseAmbient.java index 547787e0d..d72e9aafb 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseAmbient.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseAmbient.java @@ -1,9 +1,11 @@ package mineplex.core.disguise.disguises; +import org.bukkit.entity.EntityType; + public abstract class DisguiseAmbient extends DisguiseInsentient { - public DisguiseAmbient(org.bukkit.entity.Entity entity) + public DisguiseAmbient(EntityType entityType, org.bukkit.entity.Entity entity) { - super(entity); + super(entityType, entity); } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseArmorStand.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseArmorStand.java index 520ef6ff2..ed3cade7d 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseArmorStand.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseArmorStand.java @@ -1,5 +1,6 @@ package mineplex.core.disguise.disguises; +import org.bukkit.entity.EntityType; import org.bukkit.util.Vector; import net.minecraft.server.v1_8_R3.EntityArmorStand; @@ -12,7 +13,7 @@ public class DisguiseArmorStand extends DisguiseInsentient { public DisguiseArmorStand(org.bukkit.entity.Entity entity) { - super(entity); + super(EntityType.ARMOR_STAND, entity); DataWatcher.a(10, (byte) 0, EntityArmorStand.META_ARMOR_OPTION, (byte) 0); @@ -47,7 +48,7 @@ public class DisguiseArmorStand extends DisguiseInsentient } @Override - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBase.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBase.java index 5b325b952..7c742b3c4 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBase.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBase.java @@ -1,12 +1,5 @@ package mineplex.core.disguise.disguises; -import java.util.ArrayList; -import java.util.List; - -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; -import org.bukkit.entity.Player; - import mineplex.core.common.DummyEntity; import mineplex.core.common.util.UtilPlayer; import net.minecraft.server.v1_8_R3.DataWatcher; @@ -14,48 +7,72 @@ import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.EntityTrackerEntry; import net.minecraft.server.v1_8_R3.IntHashMap; +import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata; +import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; import net.minecraft.server.v1_8_R3.WorldServer; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public abstract class DisguiseBase { protected Entity Entity; protected DataWatcher DataWatcher; - + private DisguiseBase _soundDisguise; - - public boolean Global = true; - - public DisguiseBase(org.bukkit.entity.Entity entity) - { - if (entity != null) + + private EntityType _disguiseType; + + /** + * Whether the disguised entity should be entirely hidden from a player if that player does not receive the disguise + */ + private boolean _hideIfNotDisguised = false; + + public DisguiseBase(EntityType entityType, org.bukkit.entity.Entity entity) + { + if (entity == null) { - setEntity(entity); + throw new NullPointerException("Entity cannot be null (did you mean to pass in an unspawned entity?)"); } + this._disguiseType = entityType; + + setEntity(entity); + DataWatcher = new DataWatcher(new DummyEntity(null)); - DataWatcher.a(0, Byte.valueOf((byte) 0), Entity.META_ENTITYDATA, (byte) 0); - DataWatcher.a(1, Short.valueOf((short) 300), Entity.META_AIR, 300); + DataWatcher.a(0, (byte) 0, net.minecraft.server.v1_8_R3.Entity.META_ENTITYDATA, (byte) 0); + DataWatcher.a(1, (short) 300, net.minecraft.server.v1_8_R3.Entity.META_AIR, 300); _soundDisguise = this; } + public void attemptToSpawn() + { + this.Entity.world.addEntity(this.Entity, CreatureSpawnEvent.SpawnReason.CUSTOM); + } + public void setEntity(org.bukkit.entity.Entity entity) { Entity = ((CraftEntity) entity).getHandle(); } - + public void UpdateDataWatcher() { - DataWatcher.watch(0, Entity.getDataWatcher().getByte(0), Entity.META_ENTITYDATA, Entity.getDataWatcher().getByte(0)); - DataWatcher.watch(1, Entity.getDataWatcher().getShort(1), Entity.META_AIR, (int) Entity.getDataWatcher().getShort(1)); + DataWatcher.watch(0, Entity.getDataWatcher().getByte(0), net.minecraft.server.v1_8_R3.Entity.META_ENTITYDATA, Entity.getDataWatcher().getByte(0)); + DataWatcher.watch(1, Entity.getDataWatcher().getShort(1), net.minecraft.server.v1_8_R3.Entity.META_AIR, (int) Entity.getDataWatcher().getShort(1)); } - - public abstract Packet GetSpawnPacket(); - public Packet GetMetaDataPacket() + public abstract Packet getSpawnPacket(); + + public Packet getMetadataPacket() { UpdateDataWatcher(); return new PacketPlayOutEntityMetadata(Entity.getId(), DataWatcher, true); @@ -71,7 +88,7 @@ public abstract class DisguiseBase if (tracker.get(Entity.getId()) == null) return; - Packet packet = GetMetaDataPacket(); + Packet packet = getMetadataPacket(); for (EntityPlayer player : tracker.get(Entity.getId()).trackedPlayers) { @@ -82,53 +99,99 @@ public abstract class DisguiseBase public void setSoundDisguise(DisguiseBase soundDisguise) { _soundDisguise = soundDisguise; - + if (_soundDisguise == null) _soundDisguise = this; } - + public void playHurtSound() { Entity.world.makeSound(Entity, _soundDisguise.getHurtSound(), _soundDisguise.getVolume(), _soundDisguise.getPitch()); } - - public void playHurtSound(Location location) - { - Entity.world.makeSound(location.getX(), location.getY(), location.getZ(), _soundDisguise.getHurtSound(), _soundDisguise.getVolume(), _soundDisguise.getPitch()); - } - public Entity GetEntity() + public Entity getEntity() { return Entity; } - public int GetEntityId() + public int getEntityId() { return Entity.getId(); } - + protected abstract String getHurtSound(); - + protected abstract float getVolume(); - + protected abstract float getPitch(); - + public List getTrackedPlayers() { List players = new ArrayList<>(); IntHashMap tracker = ((WorldServer) Entity.world).tracker.trackedEntities; - for(EntityPlayer ep : tracker.get(Entity.getId()).trackedPlayers) + if (tracker.get(Entity.getId()) == null) + { + System.out.println("Tracker did not contain " + Entity.getId() + " " + Entity.getCustomName() + " " + Entity.dead + " " + Entity.locX + " " + Entity.locY + " " + Entity.locZ); + return Collections.emptyList(); + } + for (EntityPlayer ep : tracker.get(Entity.getId()).trackedPlayers) { players.add(ep.getBukkitEntity()); } return players; } - + public void sendPacket(Packet... packet) { - for(Player p : getTrackedPlayers()) { - UtilPlayer.sendPacket(p, packet); + List trackedPlayers = getTrackedPlayers(); + for (Packet p : packet) + { + if (p instanceof PacketPlayOutPlayerInfo) + { + MinecraftServer.getServer().getPlayerList().sendAll(p); + } + else + { + for (Player player : trackedPlayers) + { + UtilPlayer.sendPacket(player, p); + } + } } } - + + public void onDisguise(boolean isActive) + { + + } + + public void onUndisguise(boolean wasActive) + { + + } + + public void onTransfer(DisguiseBase other) + { + + } + + public void onReturn(DisguiseBase other) + { + + } + + public void setHideIfNotDisguised(boolean hideIfNotDisguised) + { + this._hideIfNotDisguised = hideIfNotDisguised; + } + + public boolean isHideIfNotDisguised() + { + return this._hideIfNotDisguised; + } + + public EntityType getDisguiseType() + { + return this._disguiseType; + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java index f0406a88e..735ae8914 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseBlock.java @@ -5,6 +5,7 @@ import java.util.Random; import net.minecraft.server.v1_8_R3.MathHelper; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity; +import org.bukkit.entity.EntityType; public class DisguiseBlock extends DisguiseBase { @@ -15,7 +16,7 @@ public class DisguiseBlock extends DisguiseBase public DisguiseBlock(org.bukkit.entity.Entity entity, int blockId, int blockData) { - super(entity); + super(EntityType.FALLING_BLOCK, entity); _blockId = blockId; _blockData = blockData; @@ -32,7 +33,7 @@ public class DisguiseBlock extends DisguiseBase } @Override - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(); packet.a = Entity.getId(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCaveSpider.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCaveSpider.java index 530f69a5c..09b3d076a 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCaveSpider.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCaveSpider.java @@ -35,5 +35,4 @@ public class DisguiseCaveSpider extends DisguiseMonster { return "mob.spider.say"; } - } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCreature.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCreature.java index a1db97615..2e00319f0 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCreature.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseCreature.java @@ -7,22 +7,13 @@ import org.bukkit.entity.*; public abstract class DisguiseCreature extends DisguiseInsentient { - private final EntityType _disguiseType; - public DisguiseCreature(EntityType disguiseType, org.bukkit.entity.Entity entity) { - super(entity); - - _disguiseType = disguiseType; - } - - public EntityType getDisguiseType() - { - return _disguiseType; + super(disguiseType, entity); } @SuppressWarnings("deprecation") - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseHuman.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseHuman.java index 5a42eb867..344af0254 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseHuman.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseHuman.java @@ -1,12 +1,13 @@ package mineplex.core.disguise.disguises; import net.minecraft.server.v1_8_R3.EntityHuman; +import org.bukkit.entity.EntityType; public abstract class DisguiseHuman extends DisguiseLiving { - public DisguiseHuman(org.bukkit.entity.Entity entity) + public DisguiseHuman(EntityType disguiseType, org.bukkit.entity.Entity entity) { - super(entity); + super(disguiseType, entity); byte skin = 0; skin |= (1 << 0); //Enable Cape diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseInsentient.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseInsentient.java index 349073a17..843af0c09 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseInsentient.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseInsentient.java @@ -4,14 +4,15 @@ import mineplex.core.common.*; import net.minecraft.server.v1_8_R3.EntityInsentient; import org.bukkit.*; +import org.bukkit.entity.EntityType; public abstract class DisguiseInsentient extends DisguiseLiving { private boolean _showArmor; - public DisguiseInsentient(org.bukkit.entity.Entity entity) + public DisguiseInsentient(EntityType disguiseType, org.bukkit.entity.Entity entity) { - super(entity); + super(disguiseType, entity); DataWatcher.a(3, Byte.valueOf((byte) 0), EntityInsentient.META_CUSTOMNAME_VISIBLE, false); DataWatcher.a(2, "", EntityInsentient.META_CUSTOMNAME, ""); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseLiving.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseLiving.java index 0f426bf2d..2a1dd6ea2 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseLiving.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseLiving.java @@ -5,6 +5,7 @@ import java.util.Random; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; +import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import net.minecraft.server.v1_8_R3.EntityLiving; @@ -17,9 +18,9 @@ public abstract class DisguiseLiving extends DisguiseBase private boolean _invisible; private ItemStack[] _equipment = new ItemStack[5]; - public DisguiseLiving(org.bukkit.entity.Entity entity) + public DisguiseLiving(EntityType disguiseType, org.bukkit.entity.Entity entity) { - super(entity); + super(disguiseType, entity); DataWatcher.a(6, Float.valueOf(1.0F), EntityLiving.META_HEALTH, 1F); DataWatcher.a(7, Integer.valueOf(0), EntityLiving.META_POTION_COLOR, 0); @@ -88,7 +89,7 @@ public abstract class DisguiseLiving extends DisguiseBase { PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(); - packet.a = GetEntityId(); + packet.a = getEntityId(); packet.b = nmsSlot; packet.c = CraftItemStack.asNMSCopy(itemstack); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseMagmaCube.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseMagmaCube.java index 3bbd587b7..e39715d04 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseMagmaCube.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseMagmaCube.java @@ -4,12 +4,13 @@ import net.minecraft.server.v1_8_R3.EntitySlime; import net.minecraft.server.v1_8_R3.MathHelper; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving; +import org.bukkit.entity.EntityType; public class DisguiseMagmaCube extends DisguiseInsentient { public DisguiseMagmaCube(org.bukkit.entity.Entity entity) { - super(entity); + super(EntityType.MAGMA_CUBE, entity); DataWatcher.a(16, new Byte((byte) 1), EntitySlime.META_SIZE, 1); } @@ -24,7 +25,7 @@ public class DisguiseMagmaCube extends DisguiseInsentient return DataWatcher.getByte(16); } - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguisePlayer.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguisePlayer.java index 921a36831..7b45bada6 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguisePlayer.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguisePlayer.java @@ -1,67 +1,149 @@ package mineplex.core.disguise.disguises; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; import com.mojang.authlib.GameProfile; import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.UtilMath; +import mineplex.core.disguise.playerdisguise.PlayerDisguiseManager; +import mineplex.core.thread.ThreadPool; +import mineplex.core.utils.UtilGameProfile; import net.minecraft.server.v1_8_R3.*; import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo.EnumPlayerInfoAction; -import org.bukkit.Location; import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftInventory; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; public class DisguisePlayer extends DisguiseHuman { - private Entity _entity; - private GameProfile _profile; - private boolean _sneaking; - private BlockFace _sleeping; - private boolean _sendSkinToSelf; + private String _requestedUsername; - public DisguisePlayer(org.bukkit.entity.Entity entity) + // If _requestedSkinData is not null, that will be used + private SkinData _requestedSkinData; + private String _requestedSkin; + + private GameProfile _originalProfile; + private GameProfile _profile; + + private BlockFace _sleeping; + + private boolean _sendSkinToSelf = true; + private boolean _showInTabList = false; + private int _showInTabListDelay = 30; + + private DisguisePlayer(Entity entity) { - super(entity); - _entity = entity; + super(EntityType.PLAYER, entity); + this._originalProfile = entity instanceof Player ? UtilGameProfile.getGameProfile((Player) entity) : null; } - public DisguisePlayer(org.bukkit.entity.Entity entity, GameProfile profile) + /** + * Using this constructor, this DisguisePlayer will be given the same GameProfile as provided + */ + public DisguisePlayer(Entity entity, GameProfile gameProfile) { this(entity); - setProfile(profile); + this._profile = UtilGameProfile.clone(gameProfile); } - public void setProfile(GameProfile profile) + /** + * @param username The username to disguise this player as, AND the username of the player whose skin will be used + */ + public DisguisePlayer(Entity entity, String username) { - GameProfile newProfile = new GameProfile(UUID.randomUUID(), profile.getName()); - - newProfile.getProperties().putAll(profile.getProperties()); - - _profile = newProfile; + this(entity, username, username); + } + + /** + * @param username The username to disguise this entity as + * @param skin The username of the player whose skin will be used + */ + public DisguisePlayer(Entity entity, String username, String skin) + { + this(entity); + + this._requestedUsername = username; + this._requestedSkin = skin; + } + + public DisguisePlayer(Entity entity, String username, SkinData skinData) + { + this(entity); + + this._requestedUsername = username; + this._requestedSkinData = skinData; + } + + /** + * If this DisguisePlayer has been initialized with a requested username and requested skin, it must be initialized + * + * @param onComplete The Runnable which will be run once initialized. Can be null. It will be run on a separate thread if initialization took place, and the current thread if not + * + * @returns A Future which, upon completion, implies the task is done + */ + public Future initialize(Runnable onComplete) + { + if (this._profile != null && this._profile.isComplete()) + { + onComplete.run(); + return CompletableFuture.completedFuture(null); + } + + return ThreadPool.ASYNC.submit(() -> + { + try + { + GameProfile profileOfUsername = UtilGameProfile.getProfileByName(_requestedUsername, true, null).get(); + + if (_requestedSkinData == null) + { + GameProfile profileOfSkin = UtilGameProfile.getProfileByName(_requestedSkin, true, null).get(); + _requestedSkinData = SkinData.constructFromGameProfile(profileOfSkin, true, true); + } + + this._profile = new GameProfile(profileOfUsername.getId(), profileOfUsername.getName()); + this._profile.getProperties().put("textures", _requestedSkinData.getProperty()); + } + catch (Exception e) + { + // fixme handle + e.printStackTrace(); + } + finally + { + onComplete.run(); + } + }, null); + } + + public GameProfile getProfile() + { + return _profile; + } + + public void setSendSkinDataToSelf(boolean sendToSelf) + { + _sendSkinToSelf = sendToSelf; + } + + public boolean getSendSkinDataToSelf() + { + return _sendSkinToSelf; + } + + public void showInTabList(boolean show, int delay) + { + this._showInTabList = show; + this._showInTabListDelay = delay; } - - public GameProfile getProfile() - { - return _profile; - } - - public void setSkinData(SkinData skin) - { - _profile.getProperties().put("textures", skin.getSkinProperty()); - } - - /** - * Currently not working. - */ - public void setSendSkinDataToSelf(boolean sendToSelf) - { - _sendSkinToSelf = sendToSelf; - } - - public boolean getSendSkinDataToSelf() - { - return _sendSkinToSelf; - } public BlockFace getSleepingDirection() { @@ -69,31 +151,44 @@ public class DisguisePlayer extends DisguiseHuman } /** - * Don't use this if the disguise is already on as it will not work the way you want it to. Contact libraryaddict if you need + * Don't use this if the disguise is already on as it will not work the way you want it to. Contact samczsun if you need * that added. + * + * BlockFace.NORTH = feet pointing north + * BlockFace.SOUTH = feet pointing south + * etc etc */ public void setSleeping(BlockFace sleeping) { _sleeping = sleeping; } - public void setSneaking(boolean sneaking) + public PacketPlayOutPlayerInfo getDisguiseInfoPackets(boolean add) { - _sneaking = sneaking; - } + if (!add && _originalProfile == null) + return null; - public boolean getSneaking() - { - return _sneaking; - } - - public Packet getNewInfoPacket(boolean add) - { PacketPlayOutPlayerInfo newDisguiseInfo = new PacketPlayOutPlayerInfo(); newDisguiseInfo.a = add ? EnumPlayerInfoAction.ADD_PLAYER : EnumPlayerInfoAction.REMOVE_PLAYER; - PacketPlayOutPlayerInfo.PlayerInfoData info = newDisguiseInfo.new PlayerInfoData(_profile, 90, - WorldSettings.EnumGamemode.SURVIVAL, null); + PacketPlayOutPlayerInfo.PlayerInfoData info = newDisguiseInfo.new PlayerInfoData(add ? _profile : _originalProfile, UtilMath.r(120), + getAppropriateGamemode(), null); + + newDisguiseInfo.b.add(info); + + return newDisguiseInfo; + } + + public Packet getUndisguiseInfoPackets(boolean remove) + { + if (!remove && _originalProfile == null) + return null; + + PacketPlayOutPlayerInfo newDisguiseInfo = new PacketPlayOutPlayerInfo(); + newDisguiseInfo.a = remove ? EnumPlayerInfoAction.REMOVE_PLAYER : EnumPlayerInfoAction.ADD_PLAYER; + + PacketPlayOutPlayerInfo.PlayerInfoData info = newDisguiseInfo.new PlayerInfoData(remove ? _profile : _originalProfile, UtilMath.r(120), + getAppropriateGamemode(), null); newDisguiseInfo.b.add(info); @@ -107,32 +202,26 @@ public class DisguisePlayer extends DisguiseHuman byte b0 = DataWatcher.getByte(0); - if (_sneaking) + if (Entity.isSneaking()) + { DataWatcher.watch(0, Byte.valueOf((byte) (b0 | 1 << 1)), EntityHuman.META_ENTITYDATA, (byte) (b0 | 1 << 1)); + } else + { DataWatcher.watch(0, Byte.valueOf((byte) (b0 & ~(1 << 1))), EntityHuman.META_ENTITYDATA, (byte) (b0 & ~(1 << 1))); - } + } - public PacketPlayOutNamedEntitySpawn spawnBeforePlayer(Location spawnLocation) - { - Location loc = spawnLocation.add(spawnLocation.getDirection().normalize().multiply(30)); - loc.setY(Math.max(loc.getY(), 0)); + if (Entity instanceof EntityPlayer) + { + EntityPlayer entityPlayer = (EntityPlayer) Entity; - PacketPlayOutNamedEntitySpawn packet = new PacketPlayOutNamedEntitySpawn(); - packet.a = Entity.getId(); - packet.b = _profile.getId(); - packet.c = MathHelper.floor(loc.getX() * 32.0D); - packet.d = MathHelper.floor(loc.getY() * 32.0D); - packet.e = MathHelper.floor(loc.getZ() * 32.0D); - packet.f = (byte) ((int) (loc.getYaw() * 256.0F / 360.0F)); - packet.g = (byte) ((int) (loc.getPitch() * 256.0F / 360.0F)); - packet.i = DataWatcher; - - return packet; + DataWatcher.watch(10, entityPlayer.getDataWatcher().getByte(10), EntityPlayer.META_SKIN, entityPlayer.getDataWatcher().getByte(10)); + DataWatcher.watch(16, (byte) 0, EntityPlayer.META_CAPE, (byte) 1); + } } @Override - public PacketPlayOutNamedEntitySpawn GetSpawnPacket() + public PacketPlayOutNamedEntitySpawn getSpawnPacket() { PacketPlayOutNamedEntitySpawn packet = new PacketPlayOutNamedEntitySpawn(); packet.a = Entity.getId(); @@ -140,8 +229,8 @@ public class DisguisePlayer extends DisguiseHuman packet.c = MathHelper.floor(Entity.locX * 32.0D); packet.d = MathHelper.floor(Entity.locY * 32.0D); packet.e = MathHelper.floor(Entity.locZ * 32.0D); - packet.f = (byte) ((int) (Entity.yaw * 256.0F / 360.0F)); - packet.g = (byte) ((int) (Entity.pitch * 256.0F / 360.0F)); + packet.f = (byte) ((int) ((Entity.isFakeHead() ? Entity.fakePitch : Entity.pitch) * 256.0F / 360.0F)); + packet.g = (byte) ((int) ((Entity.isFakeHead() ? Entity.fakePitch : Entity.pitch) * 256.0F / 360.0F)); packet.i = DataWatcher; return packet; @@ -151,18 +240,213 @@ public class DisguisePlayer extends DisguiseHuman { return _profile.getName(); } - - public void sendHit() - { - PacketPlayOutAnimation packet = new PacketPlayOutAnimation(); - packet.a = GetEntityId(); - packet.b = 0; - - sendPacket(packet); - } - public org.bukkit.entity.Entity getEntity() + public void sendHit() { - return _entity; + PacketPlayOutAnimation packet = new PacketPlayOutAnimation(); + packet.a = getEntityId(); + packet.b = 0; + + sendPacket(packet); } -} + + @Override + public void onDisguise(boolean isActive) + { + if (this.Entity instanceof EntityPlayer) + { + if (_sendSkinToSelf) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + // First construct the packet which will remove the previous disguise from the tab list + PacketPlayOutPlayerInfo playerInfoPacketRemove = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoPacketRemove.new PlayerInfoData(_originalProfile, entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoPacketRemove.b.add(dataRemove); + + // This packet will add the new disguised name into the tab list + // We have to create a new profile with the original ID because when we respawn the caller, their UUID stays the same + PacketPlayOutPlayerInfo playerInfoPacket = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoPacket.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoPacket.b.add(data); + + // This packet does the magic. It forces a new player to be created client-side which causes the skin to reload + PacketPlayOutRespawn respawnPacket = new PacketPlayOutRespawn(entityPlayer.world.getWorld().getEnvironment().getId(), entityPlayer.getWorld().getDifficulty(), entityPlayer.getWorld().worldData.getType(), getAppropriateGamemode()); + + entityPlayer.playerConnection.networkManager.handle(playerInfoPacketRemove); + entityPlayer.playerConnection.networkManager.handle(playerInfoPacket); + entityPlayer.playerConnection.networkManager.handle(respawnPacket); + + update(entityPlayer); + } + } + } + + @Override + public void onUndisguise(boolean wasActive) + { + if (this.Entity instanceof EntityPlayer) + { + if (_sendSkinToSelf) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + // First construct the packet which will remove the previous disguise from the tab list + PacketPlayOutPlayerInfo playerInfoPacketRemove = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoPacketRemove.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoPacketRemove.b.add(dataRemove); + + // This packet will add the new disguised name into the tab list + // We have to create a new profile with the original ID because when we respawn the caller, their UUID stays the same + + PacketPlayOutPlayerInfo playerInfoPacket = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoPacket.new PlayerInfoData(_originalProfile, entityPlayer.ping, entityPlayer.playerInteractManager.getGameMode(), null); + playerInfoPacket.b.add(data); + + // This packet does the magic. It forces a new player to be created client-side which causes the skin to reload + PacketPlayOutRespawn respawnPacket = new PacketPlayOutRespawn(entityPlayer.world.getWorld().getEnvironment().getId(), entityPlayer.getWorld().getDifficulty(), entityPlayer.getWorld().worldData.getType(), getAppropriateGamemode()); + + entityPlayer.playerConnection.networkManager.handle(playerInfoPacketRemove); + entityPlayer.playerConnection.networkManager.handle(playerInfoPacket); + entityPlayer.playerConnection.networkManager.handle(respawnPacket); + + update(entityPlayer); + } + } + } + + @Override + public void onTransfer(DisguiseBase disguise) + { + if (disguise instanceof DisguisePlayer) + { + if (((DisguisePlayer) disguise).getSendSkinDataToSelf() && _sendSkinToSelf && this.Entity instanceof EntityPlayer) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + PacketPlayOutPlayerInfo playerInfoRemove = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoRemove.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoRemove.b.add(data); + + entityPlayer.playerConnection.networkManager.handle(playerInfoRemove); + } + } + } + + @EventHandler + public void onReturn(DisguiseBase disguise) + { + if (disguise instanceof DisguisePlayer) + { + if (((DisguisePlayer) disguise).getSendSkinDataToSelf() && _sendSkinToSelf && this.Entity instanceof EntityPlayer) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + PacketPlayOutPlayerInfo playerInfoPacket = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoPacket.new PlayerInfoData(((DisguisePlayer) disguise)._originalProfile, entityPlayer.ping, entityPlayer.playerInteractManager.getGameMode(), null); + playerInfoPacket.b.add(data); + + entityPlayer.playerConnection.networkManager.handle(playerInfoPacket); + + PacketPlayOutPlayerInfo playerInfoAdd = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoAdd.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, entityPlayer.playerInteractManager.getGameMode(), null); + playerInfoAdd.b.add(dataRemove); + + entityPlayer.playerConnection.networkManager.handle(playerInfoAdd); + } + } + } + + public GameProfile getOriginalProfile() + { + return UtilGameProfile.clone(_originalProfile); + } + + private void update(EntityPlayer entityPlayer) + { + // And then we teleport them back to where they were + PacketPlayOutPosition positionPacket = new PacketPlayOutPosition(entityPlayer.locX, entityPlayer.locY, entityPlayer.locZ, entityPlayer.yaw, entityPlayer.pitch, new HashSet<>()); + + // Allow them to fly again + PacketPlayOutAbilities packetPlayOutAbilities = new PacketPlayOutAbilities(entityPlayer.abilities); + + // Give them their exp again + PacketPlayOutExperience exp = new PacketPlayOutExperience(entityPlayer.exp, entityPlayer.expTotal, entityPlayer.expLevel); + + entityPlayer.playerConnection.networkManager.handle(positionPacket); + entityPlayer.playerConnection.networkManager.handle(packetPlayOutAbilities); + entityPlayer.playerConnection.networkManager.handle(exp); + if (entityPlayer.activeContainer != entityPlayer.defaultContainer) + { + IInventory inv = ((CraftInventory) entityPlayer.activeContainer.getBukkitView().getTopInventory()).getInventory(); + String name; + if (inv instanceof ITileEntityContainer) + { + name = ((ITileEntityContainer) inv).getContainerName(); + } + else + { + name = "minecraft:chest"; + } + + entityPlayer.playerConnection.sendPacket(new PacketPlayOutOpenWindow(entityPlayer.activeContainer.windowId, name, inv.getScoreboardDisplayName(), inv.getSize())); + } + entityPlayer.updateInventory(entityPlayer.activeContainer); + entityPlayer.playerConnection.networkManager.handle(new PacketPlayOutHeldItemSlot(entityPlayer.inventory.itemInHandIndex)); + + AttributeMapServer attributemapserver = (AttributeMapServer) entityPlayer.getAttributeMap(); + Set set = attributemapserver.getAttributes(); + + entityPlayer.getBukkitEntity().injectScaledMaxHealth(set, true); + + entityPlayer.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(entityPlayer.getBukkitEntity().getScaledHealth(), entityPlayer.getFoodData().getFoodLevel(), entityPlayer.getFoodData().getSaturationLevel())); + entityPlayer.playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(entityPlayer.getId(), set)); + + for (MobEffect mobEffect : entityPlayer.getEffects()) + { + if (entityPlayer.playerConnection.networkManager.getVersion() > 47 || mobEffect.getEffectId() != 25) + entityPlayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(entityPlayer.getId(), mobEffect)); + } + } + + public boolean showInTabList() + { + return this._showInTabList; + } + + public int getShowInTabListDelay() + { + return this._showInTabListDelay; + } + + private WorldSettings.EnumGamemode getAppropriateGamemode() + { + if (Entity instanceof EntityPlayer) + { + return ((EntityPlayer) Entity).playerInteractManager.getGameMode(); + } + return WorldSettings.EnumGamemode.SURVIVAL; + } + + private GameProfile getSelfProfile() + { + GameProfile selfProfile = new GameProfile(getOriginalUUID(), this._profile.getName()); + selfProfile.getProperties().putAll(this._profile.getProperties()); + return selfProfile; + } + + private UUID getOriginalUUID() + { + if (this._originalProfile.getProperties().containsKey(PlayerDisguiseManager.ORIGINAL_UUID_KEY)) + { + try + { + return UUID.fromString(this._originalProfile.getProperties().get(PlayerDisguiseManager.ORIGINAL_UUID_KEY).iterator().next().getValue()); + } + catch (IllegalArgumentException ignored) + { + } + } + return this._originalProfile.getId(); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java index 426949661..1ebe31ae6 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java @@ -18,7 +18,7 @@ public class DisguiseRabbit extends DisguiseAnimal } @Override - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); @@ -75,5 +75,4 @@ public class DisguiseRabbit extends DisguiseAnimal return packet; } - } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java index 67e7547b0..a9f0b44f5 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java @@ -4,12 +4,13 @@ import net.minecraft.server.v1_8_R3.EntitySlime; import net.minecraft.server.v1_8_R3.MathHelper; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving; +import org.bukkit.entity.EntityType; public class DisguiseSlime extends DisguiseInsentient { public DisguiseSlime(org.bukkit.entity.Entity entity) { - super(entity); + super(EntityType.SLIME, entity); DataWatcher.a(16, new Byte((byte) 1), EntitySlime.META_SIZE, 1); } @@ -24,7 +25,7 @@ public class DisguiseSlime extends DisguiseInsentient return DataWatcher.getByte(16); } - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguiseCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguiseCommand.java new file mode 100644 index 000000000..1974687a7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguiseCommand.java @@ -0,0 +1,33 @@ +package mineplex.core.disguise.playerdisguise; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +public class DisguiseCommand extends CommandBase implements Listener +{ + DisguiseCommand(PlayerDisguiseManager plugin) + { + super(plugin, Rank.ADMIN, new Rank[]{Rank.YOUTUBE, Rank.TWITCH}, "disguise"); + } + + @Override + public void Execute(final Player caller, final String[] args) + { + if (args == null || args.length == 0) + { + Plugin.undisguise(caller); + return; + } + if (args.length > 2) + { + UtilPlayer.message(caller, F.help("/disguise [username of skin]", "Disguise yourself as 'username' with optional skin belonging to 'username of skin'", Rank.ADMIN)); + return; + } + + Plugin.disguise(caller, args[0], args.length > 1 ? args[1] : args[0]); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguisePlayerBean.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguisePlayerBean.java new file mode 100644 index 000000000..ab7878e08 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguisePlayerBean.java @@ -0,0 +1,137 @@ +package mineplex.core.disguise.playerdisguise; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.util.UUIDTypeAdapter; +import mineplex.serverdata.data.Data; + +import java.lang.reflect.Type; +import java.util.UUID; + +public class DisguisePlayerBean implements Data +{ + private static final Gson GSON; + + static + { + GSON = new GsonBuilder() + .registerTypeAdapter(GameProfile.class, new GameProfileSerializer()) + .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) + .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) + .create(); + } + + private int _accountID; + private String _playerName; + + private String _disguisedPlayer; + private String _disguisedSkin; + + private String _serializedGameProfile; + + public DisguisePlayerBean(int playerAccountID, String playerName, String disguiseAs, String disguiseSkin, GameProfile targetProfile) + { + this._accountID = playerAccountID; + this._playerName = playerName; + + this._disguisedPlayer = disguiseAs; + this._disguisedSkin = disguiseSkin; + + this._serializedGameProfile = serialize(targetProfile); + } + + public int getAccountID() + { + return _accountID; + } + + public String getDisguisedPlayer() + { + return _disguisedPlayer; + } + + public String getDisguisedSkin() + { + return this._disguisedSkin; + } + + public String getPlayerName() + { + return _playerName; + } + + @Override + public String getDataId() + { + return _accountID + _playerName; + } + + public GameProfile getGameProfile() + { + return deserialize(this._serializedGameProfile); + } + + private String serialize(GameProfile gameProfile) + { + return GSON.toJson(gameProfile); + } + + private GameProfile deserialize(String in) + { + return GSON.fromJson(in, GameProfile.class); + } + + private static class GameProfileSerializer implements JsonSerializer, JsonDeserializer + { + private GameProfileSerializer() + { + } + + public GameProfile deserialize(JsonElement var1, Type var2, JsonDeserializationContext var3) throws JsonParseException + { + JsonObject var4 = (JsonObject) var1; + UUID var5 = var4.has("id") ? (UUID) var3.deserialize(var4.get("id"), UUID.class) : null; + String var6 = var4.has("name") ? var4.getAsJsonPrimitive("name").getAsString() : null; + GameProfile gameProfile = new GameProfile(var5, var6); + + if (var4.has("properties")) + { + PropertyMap propertyMap = var3.deserialize(var4.get("properties"), PropertyMap.class); + gameProfile.getProperties().putAll(propertyMap); + } + + return gameProfile; + } + + public JsonElement serialize(GameProfile var1, Type var2, JsonSerializationContext var3) + { + JsonObject var4 = new JsonObject(); + + if (var1.getId() != null) + { + var4.add("id", var3.serialize(var1.getId())); + } + + if (var1.getName() != null) + { + var4.addProperty("name", var1.getName()); + } + + if (var1.getProperties() != null) + { + var4.add("properties", var3.serialize(var1.getProperties())); + } + + return var4; + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/PlayerDisguiseManager.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/PlayerDisguiseManager.java new file mode 100644 index 000000000..e7ff8c3d6 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/PlayerDisguiseManager.java @@ -0,0 +1,631 @@ +package mineplex.core.disguise.playerdisguise; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.cosmetic.CosmeticManager; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguisePlayer; +import mineplex.core.disguise.playerdisguise.events.PlayerDisguisedEvent; +import mineplex.core.disguise.playerdisguise.events.PlayerPreDisguiseEvent; +import mineplex.core.disguise.playerdisguise.events.PlayerPreUndisguiseEvent; +import mineplex.core.disguise.playerdisguise.events.PlayerUndisguisedEvent; +import mineplex.core.event.JoinMessageBroadcastEvent; +import mineplex.core.friend.FriendManager; +import mineplex.core.packethandler.IPacketHandler; +import mineplex.core.packethandler.PacketHandler; +import mineplex.core.packethandler.PacketInfo; +import mineplex.core.preferences.PreferencesManager; +import mineplex.core.punish.Punish; +import mineplex.core.punish.PunishClient; +import mineplex.core.scoreboard.ScoreboardManager; +import mineplex.core.utils.UtilGameProfile; +import mineplex.serverdata.Region; +import mineplex.serverdata.data.PlayerStatus; +import mineplex.serverdata.redis.RedisDataRepository; +import mineplex.serverdata.servers.ServerManager; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import net.minecraft.server.v1_8_R3.PacketPlayOutNamedEntitySpawn; +import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_8_R3.PlayerList; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; + +@ReflectivelyCreateMiniPlugin +public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler +{ + public static final String ORIGINAL_UUID_KEY = "originalUUID"; + + private CoreClientManager _clients = require(CoreClientManager.class); + private DisguiseManager _disguise = require(DisguiseManager.class); + private Punish _punish = require(Punish.class); + private CosmeticManager _cosmetics = require(CosmeticManager.class); + private PreferencesManager _prefs = require(PreferencesManager.class); + + private RedisDataRepository _redis; + + // The list of usernames which cannot join because someone else is joining + private Set
+ * BlockFace.NORTH = feet pointing north + * BlockFace.SOUTH = feet pointing south + * etc etc */ public void setSleeping(BlockFace sleeping) { _sleeping = sleeping; } - public void setSneaking(boolean sneaking) + public PacketPlayOutPlayerInfo getDisguiseInfoPackets(boolean add) { - _sneaking = sneaking; - } + if (!add && _originalProfile == null) + return null; - public boolean getSneaking() - { - return _sneaking; - } - - public Packet getNewInfoPacket(boolean add) - { PacketPlayOutPlayerInfo newDisguiseInfo = new PacketPlayOutPlayerInfo(); newDisguiseInfo.a = add ? EnumPlayerInfoAction.ADD_PLAYER : EnumPlayerInfoAction.REMOVE_PLAYER; - PacketPlayOutPlayerInfo.PlayerInfoData info = newDisguiseInfo.new PlayerInfoData(_profile, 90, - WorldSettings.EnumGamemode.SURVIVAL, null); + PacketPlayOutPlayerInfo.PlayerInfoData info = newDisguiseInfo.new PlayerInfoData(add ? _profile : _originalProfile, UtilMath.r(120), + getAppropriateGamemode(), null); + + newDisguiseInfo.b.add(info); + + return newDisguiseInfo; + } + + public Packet getUndisguiseInfoPackets(boolean remove) + { + if (!remove && _originalProfile == null) + return null; + + PacketPlayOutPlayerInfo newDisguiseInfo = new PacketPlayOutPlayerInfo(); + newDisguiseInfo.a = remove ? EnumPlayerInfoAction.REMOVE_PLAYER : EnumPlayerInfoAction.ADD_PLAYER; + + PacketPlayOutPlayerInfo.PlayerInfoData info = newDisguiseInfo.new PlayerInfoData(remove ? _profile : _originalProfile, UtilMath.r(120), + getAppropriateGamemode(), null); newDisguiseInfo.b.add(info); @@ -107,32 +202,26 @@ public class DisguisePlayer extends DisguiseHuman byte b0 = DataWatcher.getByte(0); - if (_sneaking) + if (Entity.isSneaking()) + { DataWatcher.watch(0, Byte.valueOf((byte) (b0 | 1 << 1)), EntityHuman.META_ENTITYDATA, (byte) (b0 | 1 << 1)); + } else + { DataWatcher.watch(0, Byte.valueOf((byte) (b0 & ~(1 << 1))), EntityHuman.META_ENTITYDATA, (byte) (b0 & ~(1 << 1))); - } + } - public PacketPlayOutNamedEntitySpawn spawnBeforePlayer(Location spawnLocation) - { - Location loc = spawnLocation.add(spawnLocation.getDirection().normalize().multiply(30)); - loc.setY(Math.max(loc.getY(), 0)); + if (Entity instanceof EntityPlayer) + { + EntityPlayer entityPlayer = (EntityPlayer) Entity; - PacketPlayOutNamedEntitySpawn packet = new PacketPlayOutNamedEntitySpawn(); - packet.a = Entity.getId(); - packet.b = _profile.getId(); - packet.c = MathHelper.floor(loc.getX() * 32.0D); - packet.d = MathHelper.floor(loc.getY() * 32.0D); - packet.e = MathHelper.floor(loc.getZ() * 32.0D); - packet.f = (byte) ((int) (loc.getYaw() * 256.0F / 360.0F)); - packet.g = (byte) ((int) (loc.getPitch() * 256.0F / 360.0F)); - packet.i = DataWatcher; - - return packet; + DataWatcher.watch(10, entityPlayer.getDataWatcher().getByte(10), EntityPlayer.META_SKIN, entityPlayer.getDataWatcher().getByte(10)); + DataWatcher.watch(16, (byte) 0, EntityPlayer.META_CAPE, (byte) 1); + } } @Override - public PacketPlayOutNamedEntitySpawn GetSpawnPacket() + public PacketPlayOutNamedEntitySpawn getSpawnPacket() { PacketPlayOutNamedEntitySpawn packet = new PacketPlayOutNamedEntitySpawn(); packet.a = Entity.getId(); @@ -140,8 +229,8 @@ public class DisguisePlayer extends DisguiseHuman packet.c = MathHelper.floor(Entity.locX * 32.0D); packet.d = MathHelper.floor(Entity.locY * 32.0D); packet.e = MathHelper.floor(Entity.locZ * 32.0D); - packet.f = (byte) ((int) (Entity.yaw * 256.0F / 360.0F)); - packet.g = (byte) ((int) (Entity.pitch * 256.0F / 360.0F)); + packet.f = (byte) ((int) ((Entity.isFakeHead() ? Entity.fakePitch : Entity.pitch) * 256.0F / 360.0F)); + packet.g = (byte) ((int) ((Entity.isFakeHead() ? Entity.fakePitch : Entity.pitch) * 256.0F / 360.0F)); packet.i = DataWatcher; return packet; @@ -151,18 +240,213 @@ public class DisguisePlayer extends DisguiseHuman { return _profile.getName(); } - - public void sendHit() - { - PacketPlayOutAnimation packet = new PacketPlayOutAnimation(); - packet.a = GetEntityId(); - packet.b = 0; - - sendPacket(packet); - } - public org.bukkit.entity.Entity getEntity() + public void sendHit() { - return _entity; + PacketPlayOutAnimation packet = new PacketPlayOutAnimation(); + packet.a = getEntityId(); + packet.b = 0; + + sendPacket(packet); } -} + + @Override + public void onDisguise(boolean isActive) + { + if (this.Entity instanceof EntityPlayer) + { + if (_sendSkinToSelf) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + // First construct the packet which will remove the previous disguise from the tab list + PacketPlayOutPlayerInfo playerInfoPacketRemove = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoPacketRemove.new PlayerInfoData(_originalProfile, entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoPacketRemove.b.add(dataRemove); + + // This packet will add the new disguised name into the tab list + // We have to create a new profile with the original ID because when we respawn the caller, their UUID stays the same + PacketPlayOutPlayerInfo playerInfoPacket = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoPacket.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoPacket.b.add(data); + + // This packet does the magic. It forces a new player to be created client-side which causes the skin to reload + PacketPlayOutRespawn respawnPacket = new PacketPlayOutRespawn(entityPlayer.world.getWorld().getEnvironment().getId(), entityPlayer.getWorld().getDifficulty(), entityPlayer.getWorld().worldData.getType(), getAppropriateGamemode()); + + entityPlayer.playerConnection.networkManager.handle(playerInfoPacketRemove); + entityPlayer.playerConnection.networkManager.handle(playerInfoPacket); + entityPlayer.playerConnection.networkManager.handle(respawnPacket); + + update(entityPlayer); + } + } + } + + @Override + public void onUndisguise(boolean wasActive) + { + if (this.Entity instanceof EntityPlayer) + { + if (_sendSkinToSelf) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + // First construct the packet which will remove the previous disguise from the tab list + PacketPlayOutPlayerInfo playerInfoPacketRemove = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoPacketRemove.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoPacketRemove.b.add(dataRemove); + + // This packet will add the new disguised name into the tab list + // We have to create a new profile with the original ID because when we respawn the caller, their UUID stays the same + + PacketPlayOutPlayerInfo playerInfoPacket = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoPacket.new PlayerInfoData(_originalProfile, entityPlayer.ping, entityPlayer.playerInteractManager.getGameMode(), null); + playerInfoPacket.b.add(data); + + // This packet does the magic. It forces a new player to be created client-side which causes the skin to reload + PacketPlayOutRespawn respawnPacket = new PacketPlayOutRespawn(entityPlayer.world.getWorld().getEnvironment().getId(), entityPlayer.getWorld().getDifficulty(), entityPlayer.getWorld().worldData.getType(), getAppropriateGamemode()); + + entityPlayer.playerConnection.networkManager.handle(playerInfoPacketRemove); + entityPlayer.playerConnection.networkManager.handle(playerInfoPacket); + entityPlayer.playerConnection.networkManager.handle(respawnPacket); + + update(entityPlayer); + } + } + } + + @Override + public void onTransfer(DisguiseBase disguise) + { + if (disguise instanceof DisguisePlayer) + { + if (((DisguisePlayer) disguise).getSendSkinDataToSelf() && _sendSkinToSelf && this.Entity instanceof EntityPlayer) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + PacketPlayOutPlayerInfo playerInfoRemove = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoRemove.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, getAppropriateGamemode(), null); + playerInfoRemove.b.add(data); + + entityPlayer.playerConnection.networkManager.handle(playerInfoRemove); + } + } + } + + @EventHandler + public void onReturn(DisguiseBase disguise) + { + if (disguise instanceof DisguisePlayer) + { + if (((DisguisePlayer) disguise).getSendSkinDataToSelf() && _sendSkinToSelf && this.Entity instanceof EntityPlayer) + { + EntityPlayer entityPlayer = ((EntityPlayer) this.Entity); + + PacketPlayOutPlayerInfo playerInfoPacket = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData data = playerInfoPacket.new PlayerInfoData(((DisguisePlayer) disguise)._originalProfile, entityPlayer.ping, entityPlayer.playerInteractManager.getGameMode(), null); + playerInfoPacket.b.add(data); + + entityPlayer.playerConnection.networkManager.handle(playerInfoPacket); + + PacketPlayOutPlayerInfo playerInfoAdd = new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER); + PacketPlayOutPlayerInfo.PlayerInfoData dataRemove = playerInfoAdd.new PlayerInfoData(getSelfProfile(), entityPlayer.ping, entityPlayer.playerInteractManager.getGameMode(), null); + playerInfoAdd.b.add(dataRemove); + + entityPlayer.playerConnection.networkManager.handle(playerInfoAdd); + } + } + } + + public GameProfile getOriginalProfile() + { + return UtilGameProfile.clone(_originalProfile); + } + + private void update(EntityPlayer entityPlayer) + { + // And then we teleport them back to where they were + PacketPlayOutPosition positionPacket = new PacketPlayOutPosition(entityPlayer.locX, entityPlayer.locY, entityPlayer.locZ, entityPlayer.yaw, entityPlayer.pitch, new HashSet<>()); + + // Allow them to fly again + PacketPlayOutAbilities packetPlayOutAbilities = new PacketPlayOutAbilities(entityPlayer.abilities); + + // Give them their exp again + PacketPlayOutExperience exp = new PacketPlayOutExperience(entityPlayer.exp, entityPlayer.expTotal, entityPlayer.expLevel); + + entityPlayer.playerConnection.networkManager.handle(positionPacket); + entityPlayer.playerConnection.networkManager.handle(packetPlayOutAbilities); + entityPlayer.playerConnection.networkManager.handle(exp); + if (entityPlayer.activeContainer != entityPlayer.defaultContainer) + { + IInventory inv = ((CraftInventory) entityPlayer.activeContainer.getBukkitView().getTopInventory()).getInventory(); + String name; + if (inv instanceof ITileEntityContainer) + { + name = ((ITileEntityContainer) inv).getContainerName(); + } + else + { + name = "minecraft:chest"; + } + + entityPlayer.playerConnection.sendPacket(new PacketPlayOutOpenWindow(entityPlayer.activeContainer.windowId, name, inv.getScoreboardDisplayName(), inv.getSize())); + } + entityPlayer.updateInventory(entityPlayer.activeContainer); + entityPlayer.playerConnection.networkManager.handle(new PacketPlayOutHeldItemSlot(entityPlayer.inventory.itemInHandIndex)); + + AttributeMapServer attributemapserver = (AttributeMapServer) entityPlayer.getAttributeMap(); + Set set = attributemapserver.getAttributes(); + + entityPlayer.getBukkitEntity().injectScaledMaxHealth(set, true); + + entityPlayer.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(entityPlayer.getBukkitEntity().getScaledHealth(), entityPlayer.getFoodData().getFoodLevel(), entityPlayer.getFoodData().getSaturationLevel())); + entityPlayer.playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(entityPlayer.getId(), set)); + + for (MobEffect mobEffect : entityPlayer.getEffects()) + { + if (entityPlayer.playerConnection.networkManager.getVersion() > 47 || mobEffect.getEffectId() != 25) + entityPlayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(entityPlayer.getId(), mobEffect)); + } + } + + public boolean showInTabList() + { + return this._showInTabList; + } + + public int getShowInTabListDelay() + { + return this._showInTabListDelay; + } + + private WorldSettings.EnumGamemode getAppropriateGamemode() + { + if (Entity instanceof EntityPlayer) + { + return ((EntityPlayer) Entity).playerInteractManager.getGameMode(); + } + return WorldSettings.EnumGamemode.SURVIVAL; + } + + private GameProfile getSelfProfile() + { + GameProfile selfProfile = new GameProfile(getOriginalUUID(), this._profile.getName()); + selfProfile.getProperties().putAll(this._profile.getProperties()); + return selfProfile; + } + + private UUID getOriginalUUID() + { + if (this._originalProfile.getProperties().containsKey(PlayerDisguiseManager.ORIGINAL_UUID_KEY)) + { + try + { + return UUID.fromString(this._originalProfile.getProperties().get(PlayerDisguiseManager.ORIGINAL_UUID_KEY).iterator().next().getValue()); + } + catch (IllegalArgumentException ignored) + { + } + } + return this._originalProfile.getId(); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java index 426949661..1ebe31ae6 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseRabbit.java @@ -18,7 +18,7 @@ public class DisguiseRabbit extends DisguiseAnimal } @Override - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); @@ -75,5 +75,4 @@ public class DisguiseRabbit extends DisguiseAnimal return packet; } - } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java index 67e7547b0..a9f0b44f5 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/disguises/DisguiseSlime.java @@ -4,12 +4,13 @@ import net.minecraft.server.v1_8_R3.EntitySlime; import net.minecraft.server.v1_8_R3.MathHelper; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving; +import org.bukkit.entity.EntityType; public class DisguiseSlime extends DisguiseInsentient { public DisguiseSlime(org.bukkit.entity.Entity entity) { - super(entity); + super(EntityType.SLIME, entity); DataWatcher.a(16, new Byte((byte) 1), EntitySlime.META_SIZE, 1); } @@ -24,7 +25,7 @@ public class DisguiseSlime extends DisguiseInsentient return DataWatcher.getByte(16); } - public Packet GetSpawnPacket() + public Packet getSpawnPacket() { PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(); packet.a = Entity.getId(); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguiseCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguiseCommand.java new file mode 100644 index 000000000..1974687a7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguiseCommand.java @@ -0,0 +1,33 @@ +package mineplex.core.disguise.playerdisguise; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +public class DisguiseCommand extends CommandBase implements Listener +{ + DisguiseCommand(PlayerDisguiseManager plugin) + { + super(plugin, Rank.ADMIN, new Rank[]{Rank.YOUTUBE, Rank.TWITCH}, "disguise"); + } + + @Override + public void Execute(final Player caller, final String[] args) + { + if (args == null || args.length == 0) + { + Plugin.undisguise(caller); + return; + } + if (args.length > 2) + { + UtilPlayer.message(caller, F.help("/disguise [username of skin]", "Disguise yourself as 'username' with optional skin belonging to 'username of skin'", Rank.ADMIN)); + return; + } + + Plugin.disguise(caller, args[0], args.length > 1 ? args[1] : args[0]); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguisePlayerBean.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguisePlayerBean.java new file mode 100644 index 000000000..ab7878e08 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/DisguisePlayerBean.java @@ -0,0 +1,137 @@ +package mineplex.core.disguise.playerdisguise; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.util.UUIDTypeAdapter; +import mineplex.serverdata.data.Data; + +import java.lang.reflect.Type; +import java.util.UUID; + +public class DisguisePlayerBean implements Data +{ + private static final Gson GSON; + + static + { + GSON = new GsonBuilder() + .registerTypeAdapter(GameProfile.class, new GameProfileSerializer()) + .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) + .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) + .create(); + } + + private int _accountID; + private String _playerName; + + private String _disguisedPlayer; + private String _disguisedSkin; + + private String _serializedGameProfile; + + public DisguisePlayerBean(int playerAccountID, String playerName, String disguiseAs, String disguiseSkin, GameProfile targetProfile) + { + this._accountID = playerAccountID; + this._playerName = playerName; + + this._disguisedPlayer = disguiseAs; + this._disguisedSkin = disguiseSkin; + + this._serializedGameProfile = serialize(targetProfile); + } + + public int getAccountID() + { + return _accountID; + } + + public String getDisguisedPlayer() + { + return _disguisedPlayer; + } + + public String getDisguisedSkin() + { + return this._disguisedSkin; + } + + public String getPlayerName() + { + return _playerName; + } + + @Override + public String getDataId() + { + return _accountID + _playerName; + } + + public GameProfile getGameProfile() + { + return deserialize(this._serializedGameProfile); + } + + private String serialize(GameProfile gameProfile) + { + return GSON.toJson(gameProfile); + } + + private GameProfile deserialize(String in) + { + return GSON.fromJson(in, GameProfile.class); + } + + private static class GameProfileSerializer implements JsonSerializer, JsonDeserializer + { + private GameProfileSerializer() + { + } + + public GameProfile deserialize(JsonElement var1, Type var2, JsonDeserializationContext var3) throws JsonParseException + { + JsonObject var4 = (JsonObject) var1; + UUID var5 = var4.has("id") ? (UUID) var3.deserialize(var4.get("id"), UUID.class) : null; + String var6 = var4.has("name") ? var4.getAsJsonPrimitive("name").getAsString() : null; + GameProfile gameProfile = new GameProfile(var5, var6); + + if (var4.has("properties")) + { + PropertyMap propertyMap = var3.deserialize(var4.get("properties"), PropertyMap.class); + gameProfile.getProperties().putAll(propertyMap); + } + + return gameProfile; + } + + public JsonElement serialize(GameProfile var1, Type var2, JsonSerializationContext var3) + { + JsonObject var4 = new JsonObject(); + + if (var1.getId() != null) + { + var4.add("id", var3.serialize(var1.getId())); + } + + if (var1.getName() != null) + { + var4.addProperty("name", var1.getName()); + } + + if (var1.getProperties() != null) + { + var4.add("properties", var3.serialize(var1.getProperties())); + } + + return var4; + } + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/PlayerDisguiseManager.java b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/PlayerDisguiseManager.java new file mode 100644 index 000000000..e7ff8c3d6 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/disguise/playerdisguise/PlayerDisguiseManager.java @@ -0,0 +1,631 @@ +package mineplex.core.disguise.playerdisguise; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Rank; +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.cosmetic.CosmeticManager; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguisePlayer; +import mineplex.core.disguise.playerdisguise.events.PlayerDisguisedEvent; +import mineplex.core.disguise.playerdisguise.events.PlayerPreDisguiseEvent; +import mineplex.core.disguise.playerdisguise.events.PlayerPreUndisguiseEvent; +import mineplex.core.disguise.playerdisguise.events.PlayerUndisguisedEvent; +import mineplex.core.event.JoinMessageBroadcastEvent; +import mineplex.core.friend.FriendManager; +import mineplex.core.packethandler.IPacketHandler; +import mineplex.core.packethandler.PacketHandler; +import mineplex.core.packethandler.PacketInfo; +import mineplex.core.preferences.PreferencesManager; +import mineplex.core.punish.Punish; +import mineplex.core.punish.PunishClient; +import mineplex.core.scoreboard.ScoreboardManager; +import mineplex.core.utils.UtilGameProfile; +import mineplex.serverdata.Region; +import mineplex.serverdata.data.PlayerStatus; +import mineplex.serverdata.redis.RedisDataRepository; +import mineplex.serverdata.servers.ServerManager; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import net.minecraft.server.v1_8_R3.PacketPlayOutNamedEntitySpawn; +import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_8_R3.PlayerList; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; + +@ReflectivelyCreateMiniPlugin +public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler +{ + public static final String ORIGINAL_UUID_KEY = "originalUUID"; + + private CoreClientManager _clients = require(CoreClientManager.class); + private DisguiseManager _disguise = require(DisguiseManager.class); + private Punish _punish = require(Punish.class); + private CosmeticManager _cosmetics = require(CosmeticManager.class); + private PreferencesManager _prefs = require(PreferencesManager.class); + + private RedisDataRepository _redis; + + // The list of usernames which cannot join because someone else is joining + private Set