diff --git a/src/main/java/in/twizmwaz/cardinal/command/SettingCommands.java b/src/main/java/in/twizmwaz/cardinal/command/SettingCommands.java index 236ac4a1c..febc999ca 100644 --- a/src/main/java/in/twizmwaz/cardinal/command/SettingCommands.java +++ b/src/main/java/in/twizmwaz/cardinal/command/SettingCommands.java @@ -5,7 +5,7 @@ import com.sk89q.minecraft.util.commands.CommandException; import in.twizmwaz.cardinal.chat.ChatConstant; import in.twizmwaz.cardinal.chat.LocalizedChatMessage; -import in.twizmwaz.cardinal.event.PlayerVisibilityChangeEvent; +import in.twizmwaz.cardinal.event.PlayerSettingChangeEvent; import in.twizmwaz.cardinal.settings.Setting; import in.twizmwaz.cardinal.settings.SettingValue; import in.twizmwaz.cardinal.settings.Settings; @@ -48,11 +48,11 @@ public static void set(final CommandContext cmd, CommandSender sender) throws Co if (value == null) { throw new CommandException(ChatConstant.ERROR_NO_VALUE_MATCH.getMessage(ChatUtil.getLocale(sender))); } + SettingValue oldValue = setting.getValueByPlayer((Player) sender); setting.setValueByPlayer((Player) sender, value); sender.sendMessage(ChatColor.YELLOW + setting.getNames().get(0) + ": " + ChatColor.WHITE + value.getValue()); - if (Settings.getSettingByName("Observers") != null && setting.equals(Settings.getSettingByName("Observers"))) { - Bukkit.getServer().getPluginManager().callEvent(new PlayerVisibilityChangeEvent((Player) sender)); - } + + Bukkit.getServer().getPluginManager().callEvent(new PlayerSettingChangeEvent((Player) sender, setting, oldValue, value)); } @Command(aliases = {"toggle"}, desc = "Toggle a setting.", usage = "", min = 1) diff --git a/src/main/java/in/twizmwaz/cardinal/event/PlayerSettingChangeEvent.java b/src/main/java/in/twizmwaz/cardinal/event/PlayerSettingChangeEvent.java new file mode 100644 index 000000000..c87ec314c --- /dev/null +++ b/src/main/java/in/twizmwaz/cardinal/event/PlayerSettingChangeEvent.java @@ -0,0 +1,46 @@ +package in.twizmwaz.cardinal.event; + +import in.twizmwaz.cardinal.settings.Setting; +import in.twizmwaz.cardinal.settings.SettingValue; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerSettingChangeEvent extends PlayerEvent { + + private static final HandlerList handlers = new HandlerList(); + + private final Setting setting; + private final SettingValue newValue; + private final SettingValue oldValue; + + public PlayerSettingChangeEvent(Player player, Setting setting, SettingValue oldValue, SettingValue newValue) { + super(player); + + this.setting = setting; + this.newValue = newValue; + this.oldValue = oldValue; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public Setting getSetting() { + return setting; + } + + public SettingValue getOldValue() { + return oldValue; + } + + public SettingValue getNewValue() { + return newValue; + } + +} \ No newline at end of file diff --git a/src/main/java/in/twizmwaz/cardinal/event/PlayerVisibilityChangeEvent.java b/src/main/java/in/twizmwaz/cardinal/event/PlayerVisibilityChangeEvent.java deleted file mode 100644 index 54bf5b53f..000000000 --- a/src/main/java/in/twizmwaz/cardinal/event/PlayerVisibilityChangeEvent.java +++ /dev/null @@ -1,24 +0,0 @@ -package in.twizmwaz.cardinal.event; - -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; -import org.bukkit.event.player.PlayerEvent; - -public class PlayerVisibilityChangeEvent extends PlayerEvent { - - private static final HandlerList handlers = new HandlerList(); - - public PlayerVisibilityChangeEvent(Player player) { - super(player); - } - - public static HandlerList getHandlerList() { - return handlers; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - -} \ No newline at end of file diff --git a/src/main/java/in/twizmwaz/cardinal/module/ModuleFactory.java b/src/main/java/in/twizmwaz/cardinal/module/ModuleFactory.java index 0bbaeab0f..91d20b6b8 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/ModuleFactory.java +++ b/src/main/java/in/twizmwaz/cardinal/module/ModuleFactory.java @@ -34,6 +34,7 @@ import in.twizmwaz.cardinal.module.modules.killReward.KillRewardBuilder; import in.twizmwaz.cardinal.module.modules.killStreakCount.KillStreakBuilder; import in.twizmwaz.cardinal.module.modules.kit.KitBuilder; +import in.twizmwaz.cardinal.module.modules.longTntRender.LongTntRenderBuilder; import in.twizmwaz.cardinal.module.modules.mapNotification.MapNotificationBuilder; import in.twizmwaz.cardinal.module.modules.match.MatchModuleBuilder; import in.twizmwaz.cardinal.module.modules.matchTimer.MatchTimerBuilder; @@ -171,7 +172,8 @@ private void addBuilders() { ItemDropBuilder.class, GuiKeepModuleBuilder.class, RankModuleBuilder.class, - MultitradeBuilder.class + MultitradeBuilder.class, + LongTntRenderBuilder.class )); } diff --git a/src/main/java/in/twizmwaz/cardinal/module/modules/longTntRender/LongTntRender.java b/src/main/java/in/twizmwaz/cardinal/module/modules/longTntRender/LongTntRender.java new file mode 100644 index 000000000..bb56495c3 --- /dev/null +++ b/src/main/java/in/twizmwaz/cardinal/module/modules/longTntRender/LongTntRender.java @@ -0,0 +1,274 @@ +package in.twizmwaz.cardinal.module.modules.longTntRender; + +import com.mojang.authlib.GameProfile; +import in.twizmwaz.cardinal.event.PlayerSettingChangeEvent; +import in.twizmwaz.cardinal.module.TaskedModule; +import in.twizmwaz.cardinal.settings.Setting; +import in.twizmwaz.cardinal.settings.Settings; +import net.minecraft.server.v1_8_R3.DataWatcher; +import net.minecraft.server.v1_8_R3.IChatBaseComponent; +import net.minecraft.server.v1_8_R3.Packet; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityEquipment; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport; +import net.minecraft.server.v1_8_R3.PacketPlayOutNamedEntitySpawn; +import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_8_R3.PacketPlayOutScoreboardTeam; +import net.minecraft.server.v1_8_R3.WorldSettings; +import org.bukkit.Bukkit; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.ExplosionPrimeEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class LongTntRender implements TaskedModule { + + public HashMap entityIDs = new HashMap<>(); + public HashMap oldLocation = new HashMap<>(); + public HashMap> viewers = new HashMap<>(); + public List usedIDs = new ArrayList<>(); + public List toAdd = new ArrayList<>(); + + public List removeBlocks = new ArrayList<>(); + + private HashMap settings = new HashMap<>(); + + + public Setting setting = Settings.getSettingByName("TntRendering"); + + @Override + public void unload() { + HandlerList.unregisterAll(this); + } + + @Override + public void run() { + for (int i = 0; i < toAdd.size(); i++) { + TNTPrimed tnt = toAdd.get(0); + broadcastPacket(teamPacket(tnt, true)); + broadcastPacket(tabListPacket(tnt, true)); + toAdd.remove(0); + } + Map entityIDs2 = (Map)entityIDs.clone(); + for (Map.Entry entry : entityIDs2.entrySet()) { + TNTPrimed tnt = entry.getKey(); + Location old = oldLocation.get(tnt); + Location loc = tnt.getLocation(); + if (tnt.isDead()) { + broadcastPacket(tabListPacket(tnt, false)); + broadcastPacket(teamPacket(tnt, false)); + broadcastPacket(removeFakePlayerPacket(tnt)); + for (Player player : Bukkit.getOnlinePlayers()) { + if (settings.containsKey(player) && settings.get(player).equals("block")) player.sendBlockChange(old, old.getBlock().getType(), old.getBlock().getData()); + } + usedIDs.remove(usedIDs.indexOf(Integer.parseInt(getProfileFor(tnt).getName()))); + oldLocation.remove(tnt); + viewers.remove(tnt); + entityIDs.remove(tnt); + } else { + for (Player player : Bukkit.getOnlinePlayers()) { + if (settings.containsKey(player) && loc.distance(player.getLocation()) >= 63.0f) { + if (settings.get(player).equalsIgnoreCase("playerhead")) { + if (viewers.get(tnt).contains(player)) { + sendPacket(player, movePacket(tnt)); + } else { + createFakePlayerPacket(player, tnt); + viewers.get(tnt).add(player); + } + } else { + if (viewers.get(tnt).contains(player)) { + player.sendBlockChange(old, old.getBlock().getType(), old.getBlock().getData()); + player.sendBlockChange(loc, Material.TNT, (byte) 0); + } else { + player.sendBlockChange(loc, Material.TNT, (byte) 0); + viewers.get(tnt).add(player); + } + } + } else { + if (viewers.get(tnt).contains(player)) { + sendPacket(player, removeFakePlayerPacket(tnt)); + viewers.get(tnt).remove(player); + } + } + if (removeBlocks.contains(player)) { + player.sendBlockChange(old, old.getBlock().getType(), old.getBlock().getData()); + } + } + oldLocation.put(tnt, loc); + } + } + removeBlocks.clear(); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + if (!setting.getValueByPlayer(event.getPlayer()).getValue().equals("none")) { + settings.put(event.getPlayer(), setting.getValueByPlayer(event.getPlayer()).getValue()); + } + } + + @EventHandler + public void onSettingChange(PlayerSettingChangeEvent event) { + if (!event.getSetting().equals(setting)) return; + Player player = event.getPlayer(); + String oldValue = event.getOldValue().getValue(); + String newValue = event.getNewValue().getValue(); + if (oldValue.equals("block")) { + removeBlocks.add(player); + } else if(oldValue.equals("playerhead")) { + for (TNTPrimed tnt : entityIDs.keySet()) { + sendPacket(player, tabListPacket(tnt, false)); + sendPacket(player, teamPacket(tnt, false)); + sendPacket(player, removeFakePlayerPacket(tnt)); + } + } + if (!newValue.equals("none")) { + settings.put(event.getPlayer(), newValue); + } else { + settings.remove(event.getPlayer()); + } + for (TNTPrimed tnt : entityIDs.keySet()) { + viewers.get(tnt).remove(player); + } + + } + + @EventHandler + public void onTntSpawn(ExplosionPrimeEvent event) { + if (event.getEntity() instanceof TNTPrimed) toAdd.add((TNTPrimed) event.getEntity()); + } + + @EventHandler + public void onTntExplode(EntityExplodeEvent event){ + if (!(event.getEntity() instanceof TNTPrimed)) return; + Location actual = event.getLocation(); + for (Player player : Bukkit.getOnlinePlayers()) { + if (settings.containsKey(player) && actual.distance(player.getLocation()) >= 64.0f) player.playEffect(actual, Effect.EXPLOSION_HUGE, 0, 0, 0f, 0f, 0f, 1f, 256, 1); + } + } + + public GameProfile getProfileFor(TNTPrimed tnt) { + if (entityIDs.isEmpty()) { + entityIDs.put(tnt, new GameProfile(UUID.randomUUID(), "" + 1000)); + viewers.put(tnt, new ArrayList()); + usedIDs.add(1000); + } else if (!entityIDs.containsKey(tnt)){ + int i = Collections.max(usedIDs) + 1; + entityIDs.put(tnt, new GameProfile(UUID.randomUUID(), "" + i)); + viewers.put(tnt, new ArrayList()); + usedIDs.add(i); + } + return entityIDs.get(tnt); + } + + public int getIdFor(TNTPrimed tnt) { + return Integer.MAX_VALUE - Integer.parseInt(getProfileFor(tnt).getName()); + } + + public DataWatcher createFakePlayerWatcher(Player player) { + DataWatcher data = new DataWatcher(((CraftPlayer)player).getHandle()); + data.a(0, (byte) 0x20); + return data; + } + + public Packet teamPacket(TNTPrimed tnt, boolean state) { + PacketPlayOutScoreboardTeam teamPacket = new PacketPlayOutScoreboardTeam(); + + teamPacket.a = "\000TabView" + 80; // team name + teamPacket.b = "\000TabView" + 80; // team display name + teamPacket.c = ""; // team prefix + teamPacket.d = ""; // team suffix + teamPacket.e = "never"; // name tag visibility + teamPacket.f = -1; // color + teamPacket.g = Collections.singletonList(getProfileFor(tnt).getName()); // list of player names (string list) + teamPacket.h = state ? 3 : 4; // action (0 to add team, 3 to add player, 4 to remove player) + teamPacket.i = 0; // allowFriendlyFire() + canSeeFriendlyInvisibles() + return teamPacket; + } + + public Packet tabListPacket(TNTPrimed tnt, boolean state) { + PacketPlayOutPlayerInfo listPacket = new PacketPlayOutPlayerInfo(); + + listPacket.a = state ? PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER : PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER; + List dataList = Collections.singletonList(new PacketPlayOutPlayerInfo.PlayerInfoData(getProfileFor(tnt), 0, WorldSettings.EnumGamemode.SURVIVAL, IChatBaseComponent.ChatSerializer.a("{text:\"" + getProfileFor(tnt).getName() + "\"}"))); + try { + Field b = listPacket.getClass().getDeclaredField("b"); + b.setAccessible(true); + b.set(listPacket, dataList); + } catch (Exception e) { + e.printStackTrace(); + } + return listPacket; + } + + public void createFakePlayerPacket(Player player, TNTPrimed tnt) { + Location loc = tnt.getLocation(); + PacketPlayOutNamedEntitySpawn spawnPacket = new PacketPlayOutNamedEntitySpawn(); + + spawnPacket.a = getIdFor(tnt); + spawnPacket.b = getProfileFor(tnt).getId(); + spawnPacket.c = (int)(loc.getX() * 32); //x + spawnPacket.d = (int)((loc.getY() - 1.2) * 32); //y + spawnPacket.e = (int)(loc.getZ() * 32); //z + spawnPacket.f = 0; // yaw + spawnPacket.g = 0; // pitch + spawnPacket.h = 0; // item in hand + spawnPacket.i = createFakePlayerWatcher(player);// DataWatcher + spawnPacket.j = spawnPacket.i.c(); // List, from DataWatcher + DataWatcher.deepCopy(spawnPacket.j); // No idea what this is for, but the constructor for PacketPlayOutNamedEntitySpawn(EntityHuman) does it + + sendPacket(player, spawnPacket); + + PacketPlayOutEntityEquipment armorPacket = new PacketPlayOutEntityEquipment(getIdFor(tnt), 4, CraftItemStack.asNMSCopy(new ItemStack(Material.TNT))); + + sendPacket(player, armorPacket); + } + + + public Packet movePacket(TNTPrimed tnt) { + Location loc = tnt.getLocation(); + + PacketPlayOutEntityTeleport movePacket = new PacketPlayOutEntityTeleport(); + + movePacket.a = getIdFor(tnt); + movePacket.b = (int) (loc.getX() * 32.0D); + movePacket.c = (int) ((loc.getY() - 1.2) * 32.0D); + movePacket.d = (int) (loc.getZ() * 32.0D); + movePacket.e = 0; + movePacket.f = 0; + movePacket.g = false; + + return movePacket; + } + + public Packet removeFakePlayerPacket(TNTPrimed tnt) { + return new PacketPlayOutEntityDestroy(getIdFor(tnt)); + } + + public void broadcastPacket(Packet packet) { + for (Player player : Bukkit.getOnlinePlayers()) { + sendPacket(player, packet); + } + } + + public void sendPacket(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); + } +} \ No newline at end of file diff --git a/src/main/java/in/twizmwaz/cardinal/module/modules/longTntRender/LongTntRenderBuilder.java b/src/main/java/in/twizmwaz/cardinal/module/modules/longTntRender/LongTntRenderBuilder.java new file mode 100644 index 000000000..0c06e7128 --- /dev/null +++ b/src/main/java/in/twizmwaz/cardinal/module/modules/longTntRender/LongTntRenderBuilder.java @@ -0,0 +1,14 @@ +package in.twizmwaz.cardinal.module.modules.longTntRender; + +import in.twizmwaz.cardinal.match.Match; +import in.twizmwaz.cardinal.module.ModuleBuilder; +import in.twizmwaz.cardinal.module.ModuleCollection; + +public class LongTntRenderBuilder implements ModuleBuilder { + + @Override + public ModuleCollection load(Match match) { + return new ModuleCollection<>(new LongTntRender()); + } + +} diff --git a/src/main/java/in/twizmwaz/cardinal/module/modules/tnt/Tnt.java b/src/main/java/in/twizmwaz/cardinal/module/modules/tnt/Tnt.java index 352a5cd5b..c3df3a591 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/modules/tnt/Tnt.java +++ b/src/main/java/in/twizmwaz/cardinal/module/modules/tnt/Tnt.java @@ -15,8 +15,6 @@ import org.bukkit.event.entity.ExplosionPrimeEvent; import org.bukkit.util.Vector; -import java.util.ArrayList; -import java.util.List; public class Tnt implements Module { diff --git a/src/main/java/in/twizmwaz/cardinal/module/modules/visibility/Visibility.java b/src/main/java/in/twizmwaz/cardinal/module/modules/visibility/Visibility.java index 04ad7cc52..40b82517e 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/modules/visibility/Visibility.java +++ b/src/main/java/in/twizmwaz/cardinal/module/modules/visibility/Visibility.java @@ -4,7 +4,7 @@ import in.twizmwaz.cardinal.event.MatchEndEvent; import in.twizmwaz.cardinal.event.MatchStartEvent; import in.twizmwaz.cardinal.event.PlayerChangeTeamEvent; -import in.twizmwaz.cardinal.event.PlayerVisibilityChangeEvent; +import in.twizmwaz.cardinal.event.PlayerSettingChangeEvent; import in.twizmwaz.cardinal.match.Match; import in.twizmwaz.cardinal.match.MatchState; import in.twizmwaz.cardinal.module.Module; @@ -103,7 +103,8 @@ public void onPlayerChangeTeam(PlayerChangeTeamEvent event) { } @EventHandler - public void onPlayerVisibilityChange(PlayerVisibilityChangeEvent event) { + public void onPlayerSettingChange(PlayerSettingChangeEvent event) { + if (!event.getSetting().equals(Settings.getSettingByName("Observers"))) return; for (Player toSee : Bukkit.getOnlinePlayers()) { this.resetVisibility(event.getPlayer(), toSee, Teams.getTeamByPlayer(toSee)); } diff --git a/src/main/java/in/twizmwaz/cardinal/tabList/TabList.java b/src/main/java/in/twizmwaz/cardinal/tabList/TabList.java index ab7057028..7edd3985d 100644 --- a/src/main/java/in/twizmwaz/cardinal/tabList/TabList.java +++ b/src/main/java/in/twizmwaz/cardinal/tabList/TabList.java @@ -1,6 +1,5 @@ package in.twizmwaz.cardinal.tabList; -import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import in.twizmwaz.cardinal.Cardinal; @@ -74,7 +73,7 @@ public class TabList implements Listener { private HashMap fakePlayer = new HashMap<>(); private HashMap teamTitles = new HashMap<>(); private List emptyPlayers = new ArrayList<>(); - private HashMap entityIDs = new HashMap<>(); + private Map entityIDs = new HashMap<>(); private HashMap> playerView = new HashMap<>(); @@ -130,6 +129,8 @@ public void onCycleComplete(CycleCompleteEvent event) { if (columnsPerTeam == 0) columnsPerTeam = 1; resetTeams(); updateAll(null); + entityIDs.clear(); + entityIDs.put(null, 100); for (Player player : Bukkit.getOnlinePlayers()) { sendPlayersParts(player); } @@ -401,20 +402,15 @@ private void broadcastTabListPacket(PacketPlayOutPlayerInfo.EnumPlayerInfoAction } private void sendTabListPacket(Player player, PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile game, String displayName, int ping) { + if (displayName.equals(player.getPlayerListName())) displayName = displayName.replace(player.getName(), ChatColor.BOLD + player.getName()); PacketPlayOutPlayerInfo listPacket = new PacketPlayOutPlayerInfo(); - try { - Field a = listPacket.getClass().getDeclaredField("a"); - a.setAccessible(true); - a.set(listPacket, action); + listPacket.a = action; + + List dataList = Collections.singletonList(new PacketPlayOutPlayerInfo.PlayerInfoData(game, ping < 0 ? 1000 : ping, WorldSettings.EnumGamemode.SURVIVAL, IChatBaseComponent.ChatSerializer.a("{text:\"" + StringEscapeUtils.escapeJava(displayName) + "\"}"))); Field b = listPacket.getClass().getDeclaredField("b"); b.setAccessible(true); - List dataList = Lists.newArrayList(); - - if (displayName.equals(player.getPlayerListName())) displayName = displayName.replace(player.getName(), ChatColor.BOLD + player.getName()); - dataList.add(new PacketPlayOutPlayerInfo.PlayerInfoData(game, ping < 0 ? 1000 : ping, WorldSettings.EnumGamemode.SURVIVAL, IChatBaseComponent.ChatSerializer.a("{text:\"" + StringEscapeUtils.escapeJava(displayName) + "\"}"))); - b.set(listPacket, dataList); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ee8a6e4e2..0333eb3a6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,6 +26,7 @@ settings: - Scoreboard - Sounds - Stats +- TntRendering setting: Blood: values: @@ -97,3 +98,11 @@ setting: - 'off' - on[default] description: See your statistics at the end of the game + TntRendering: + aliases: + - tnt + values: + - playerhead[default] + - block + - none + description: How tnt further away from 64 blocks is displayed to you \ No newline at end of file