diff --git a/FightSystem_14/build.gradle b/FightSystem_14/build.gradle index 29ff288..1d2a18c 100644 --- a/FightSystem_14/build.gradle +++ b/FightSystem_14/build.gradle @@ -46,6 +46,8 @@ dependencies { implementation project(":FightSystem_9") implementation project(":FightSystem_8") + compileOnly 'it.unimi.dsi:fastutil:8.5.6' + compileOnly swdep("Spigot-1.14") compileOnly swdep("WorldEdit-1.15") compileOnly swdep("SpigotCore") diff --git a/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java b/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java index 934d9b6..f0554b1 100644 --- a/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java +++ b/FightSystem_14/src/de/steamwar/fightsystem/utils/BlockIdWrapper14.java @@ -21,18 +21,29 @@ package de.steamwar.fightsystem.utils; import com.comphenix.tinyprotocol.Reflection; import de.steamwar.core.Core; +import de.steamwar.fightsystem.Config; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Player; public class BlockIdWrapper14 implements BlockIdWrapper { - private static final Class worldServer = Reflection.getClass("{nms.server.level}.WorldServer"); private static final Class chunkProviderServer = Reflection.getClass("{nms.server.level}.ChunkProviderServer"); + private static final Reflection.MethodInvoker getChunkProvider = Reflection.getTypedMethod(worldServer, null, chunkProviderServer); + private static final Class playerChunkMap = Reflection.getClass("{nms.server.level}.PlayerChunkMap"); + private static final Reflection.FieldAccessor getPlayerChunkMap = Reflection.getField(chunkProviderServer, playerChunkMap, 0); + private static final Reflection.FieldAccessor entityTrackers = Reflection.getField(playerChunkMap, Int2ObjectMap.class, 0); private static final Class block = Reflection.getClass("{nms.world.level.block}.Block"); private static final Class iBlockData = Reflection.getClass("{nms.world.level.block.state}.IBlockData"); private static final Class blockPosition = Reflection.getClass("{nms.core}.BlockPosition"); + private final Int2ObjectMap trackers; + public BlockIdWrapper14() { + trackers = entityTrackers.get(getPlayerChunkMap.get(getChunkProvider.invoke(getWorldHandle.invoke(Config.world)))); + } + private static final Reflection.MethodInvoker getCombinedId = Reflection.getTypedMethod(block, null, int.class, iBlockData); private static final Reflection.MethodInvoker getNMS = Reflection.getTypedMethod(Reflection.getClass("{obc}.block.CraftBlock"), "getNMS", iBlockData); @Override @@ -41,11 +52,9 @@ public class BlockIdWrapper14 implements BlockIdWrapper { } private static final Reflection.MethodInvoker getByCombinedId = Reflection.getTypedMethod(block, null, iBlockData, int.class); - private static final Reflection.MethodInvoker getWorldHandle = Reflection.getTypedMethod(Reflection.getClass("{obc}.CraftWorld"), "getHandle", worldServer); private static final Reflection.ConstructorInvoker newBlockPosition = Reflection.getConstructor(blockPosition, int.class, int.class, int.class); private static final Reflection.MethodInvoker getTypeAndData = Reflection.getMethod(worldServer, null, blockPosition, iBlockData, int.class); private static final Reflection.MethodInvoker removeTileEntity = Reflection.getMethod(worldServer, Core.getVersion() > 15 ? "m" : "removeTileEntity", blockPosition); - private static final Reflection.MethodInvoker getChunkProvider = Reflection.getTypedMethod(worldServer, null, chunkProviderServer); private static final Reflection.MethodInvoker flagDirty = Reflection.getMethod(chunkProviderServer, null, blockPosition); @Override public void setBlock(World world, int x, int y, int z, int blockState) { @@ -58,6 +67,19 @@ public class BlockIdWrapper14 implements BlockIdWrapper { flagDirty.invoke(getChunkProvider.invoke(nworld), pos); } + private static final Class entityTracker = Reflection.getClass("{nms.server.level}.PlayerChunkMap$EntityTracker"); + private static final Reflection.MethodInvoker updatePlayer = Reflection.getMethod(entityTracker, Core.getVersion() > 15 ? "b" : "updatePlayer", entityPlayer); + @Override + public void trackEntity(Player player, int entity) { + updatePlayer.invoke(trackers.get(entity), getPlayer.invoke(player)); + } + + private static final Reflection.MethodInvoker clearPlayer = Reflection.getMethod(entityTracker, Core.getVersion() > 15 ? "a" : "clear", entityPlayer); + @Override + public void untrackEntity(Player player, int entity) { + clearPlayer.invoke(trackers.get(entity), getPlayer.invoke(player)); + } + private static final Reflection.MethodInvoker getMaterialByBlock = Reflection.getTypedMethod(Reflection.getClass("{obc}.util.CraftMagicNumbers"), "getMaterial", Material.class, block); private static final Reflection.MethodInvoker getBlockByBlockData = Reflection.getTypedMethod(iBlockData, null, block); @Override diff --git a/FightSystem_18/src/de/steamwar/fightsystem/utils/HullHiderWrapper18.java b/FightSystem_18/src/de/steamwar/fightsystem/utils/HullHiderWrapper18.java index 6087aab..8f81cf9 100644 --- a/FightSystem_18/src/de/steamwar/fightsystem/utils/HullHiderWrapper18.java +++ b/FightSystem_18/src/de/steamwar/fightsystem/utils/HullHiderWrapper18.java @@ -42,7 +42,7 @@ public class HullHiderWrapper18 implements HullHiderWrapper { changes.removeIf(change -> { BlockData data = Config.world.getBlockData(change.getX(), change.getY(), change.getZ()); - boolean unchanged = data.getMaterial() == Config.ObfuscateWith; + boolean unchanged = data.getMaterial() == Config.ObfuscateWith || Config.HiddenBlocks.contains(data.getMaterial()); if(!unchanged) blockdata.add(getState.invoke(data)); return unchanged; diff --git a/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java b/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java index cbf186a..f77fe95 100644 --- a/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java +++ b/FightSystem_8/src/de/steamwar/fightsystem/utils/BlockIdWrapper8.java @@ -19,11 +19,25 @@ package de.steamwar.fightsystem.utils; +import com.comphenix.tinyprotocol.Reflection; +import de.steamwar.fightsystem.Config; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Player; public class BlockIdWrapper8 implements BlockIdWrapper { + + private static final Class entityTracker = Reflection.getClass("{nms}.EntityTracker"); + private static final Reflection.FieldAccessor getEntityTracker = Reflection.getField(worldServer, entityTracker, 0); + private static final Class intHashMap = Reflection.getClass("{nms}.IntHashMap"); + private static final Reflection.FieldAccessor getTrackedEntities = Reflection.getField(entityTracker, intHashMap, 0); + + private final Object trackers; + public BlockIdWrapper8() { + trackers = getTrackedEntities.get(getEntityTracker.get(getWorldHandle.invoke(Config.world))); + } + @Override @SuppressWarnings("deprecation") public int blockToId(Block block) { @@ -39,6 +53,20 @@ public class BlockIdWrapper8 implements BlockIdWrapper { world.getBlockAt(x, y, z).setTypeIdAndData(blockState >> 4, (byte)(blockState & 0b1111), false); } + private static final Class entityTrackerEntry = Reflection.getClass("{nms}.EntityTrackerEntry"); + private static final Reflection.MethodInvoker get = Reflection.getTypedMethod(intHashMap, "get", Object.class, int.class); + private static final Reflection.MethodInvoker updatePlayer = Reflection.getMethod(entityTrackerEntry, "updatePlayer", entityPlayer); + @Override + public void trackEntity(Player player, int entity) { + updatePlayer.invoke(get.invoke(trackers, entity), getPlayer.invoke(player)); + } + + private static final Reflection.MethodInvoker clearPlayer = Reflection.getMethod(entityTrackerEntry, "a", entityPlayer); + @Override + public void untrackEntity(Player player, int entity) { + clearPlayer.invoke(get.invoke(trackers, entity), getPlayer.invoke(player)); + } + @Override @SuppressWarnings("deprecation") public Material idToMaterial(int blockState) { diff --git a/FightSystem_8/src/de/steamwar/fightsystem/utils/HullHiderWrapper8.java b/FightSystem_8/src/de/steamwar/fightsystem/utils/HullHiderWrapper8.java new file mode 100644 index 0000000..524842e --- /dev/null +++ b/FightSystem_8/src/de/steamwar/fightsystem/utils/HullHiderWrapper8.java @@ -0,0 +1,55 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2024 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.fightsystem.utils; + +import com.comphenix.tinyprotocol.Reflection; +import de.steamwar.fightsystem.Config; +import org.bukkit.Material; + +import java.util.List; + +public class HullHiderWrapper8 implements HullHiderWrapper { + + private static final Reflection.ConstructorInvoker newMultiBlockChange = Reflection.getConstructor("{nms}.PacketPlayOutMultiBlockChange", int.class, short[].class, Reflection.getClass("{nms}.Chunk")); + private static final Reflection.MethodInvoker getHandle = Reflection.getMethod("{obc}.CraftChunk", "getHandle"); + @Override + public Object generateBlockChangePacket(List changes) { + changes.removeIf(change -> { + Material material = Config.world.getBlockAt(change.getX(), change.getY(), change.getZ()).getType(); + return material == Config.ObfuscateWith || Config.HiddenBlocks.contains(material); + }); + + if(changes.isEmpty()) + return null; + + Hull.IntVector chunk = changes.get(0); + chunk = new Hull.IntVector(chunk.getX() >> 4, chunk.getY() >> 4, chunk.getZ() >> 4); + int xOffset = 16*chunk.getX(); + int zOffset = 16*chunk.getZ(); + short[] pos = new short[changes.size()]; + + for(int i = 0; i < changes.size(); i++) { + Hull.IntVector change = changes.get(i); + pos[i] = (short) (((change.getX()-xOffset) << 12) + ((change.getZ()-zOffset) << 8) + change.getY()); + } + + return newMultiBlockChange.invoke(pos.length, pos, getHandle.invoke(Config.world.getChunkAt(chunk.getX(), chunk.getZ()))); + } +} diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java index 399e63d..a6b825d 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/BlockIdWrapper.java @@ -19,16 +19,28 @@ package de.steamwar.fightsystem.utils; +import com.comphenix.tinyprotocol.Reflection; import de.steamwar.core.VersionDependent; import de.steamwar.fightsystem.FightSystem; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Player; public interface BlockIdWrapper { + Class worldServer = Reflection.getClass("{nms.server.level}.WorldServer"); + Reflection.MethodInvoker getWorldHandle = Reflection.getTypedMethod(Reflection.getClass("{obc}.CraftWorld"), "getHandle", worldServer); + + Class craftPlayer = Reflection.getClass("{obc}.entity.CraftPlayer"); + Class entityPlayer = Reflection.getClass("{nms.server.level}.EntityPlayer"); + Reflection.MethodInvoker getPlayer = Reflection.getTypedMethod(craftPlayer, "getHandle", entityPlayer); + BlockIdWrapper impl = VersionDependent.getVersionImpl(FightSystem.getPlugin()); Material idToMaterial(int blockState); int blockToId(Block block); void setBlock(World world, int x, int y, int z, int blockState); + + void trackEntity(Player player, int entity); + void untrackEntity(Player player, int entity); } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java index 3b96281..05ff3fc 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java @@ -106,19 +106,17 @@ public class Hull { return players.contains(player) && region.inRegion(location) && !visibility.get(new IntVector(location).toId(region)); } - @SuppressWarnings("deprecation") public void addPlayer(Player player) { if(players.add(player)) { for(Entity entity : entities) - player.hideEntity(FightSystem.getPlugin(), entity); + BlockIdWrapper.impl.untrackEntity(player, entity.getEntityId()); } } - @SuppressWarnings("deprecation") public void removePlayer(Player player, boolean activeRemoval) { if(players.remove(player) && activeRemoval) { for(Entity entity : entities) - player.showEntity(FightSystem.getPlugin(), entity); + BlockIdWrapper.impl.trackEntity(player, entity.getEntityId()); // techhider triggers block change sending } } @@ -128,12 +126,12 @@ public class Hull { if(region.inRegion(location) && !visibility.get(new IntVector(location).toId(region))) { //TODO more precise if(entities.add(entity)) { for(Player player : players) - player.hideEntity(FightSystem.getPlugin(), entity); + BlockIdWrapper.impl.untrackEntity(player, entity.getEntityId()); } } else { if(entities.remove(entity)) { for(Player player : players) - player.showEntity(FightSystem.getPlugin(), entity); + BlockIdWrapper.impl.trackEntity(player, entity.getEntityId()); } } } @@ -180,7 +178,6 @@ public class Hull { FightSystem.getPlugin().getLogger().log(Level.INFO, () -> "[HullHider] initialisation finished: " + (System.currentTimeMillis() - start) + " ms, visible blocks: " + visibility.cardinality()); } - @SuppressWarnings("deprecation") public void updateBlockVisibility(Block b, Material changedType) { IntVector root = new IntVector(b.getX(), b.getY(), b.getZ()); if (root.notInRegion(region)) @@ -211,7 +208,7 @@ public class Hull { if(uncoveredSet.contains(new IntVector(entity.getLocation()))) { //TODO more precise it.remove(); for(Player player : players) - player.showEntity(FightSystem.getPlugin(), entity); + BlockIdWrapper.impl.trackEntity(player, entity.getEntityId()); } } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java index 4daf4ad..c613a4a 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java @@ -56,13 +56,12 @@ import java.util.function.Function; public class HullHider implements Listener { - public static final boolean ENABLED = TechHiderWrapper.ENABLED && Core.getVersion() >= 18; private final Map hullMap = new HashMap<>(); private final Hull[] hulls; private final Map, BiFunction> packetHiders = new HashMap<>(); public HullHider() { - if(!ENABLED) { + if(!TechHiderWrapper.ENABLED) { hulls = new Hull[0]; return; } @@ -77,8 +76,8 @@ public class HullHider implements Listener { if(Core.getVersion() >= 9 && Core.getVersion() < 18) posHiderGenerator("{nms.network.protocol.game}.PacketPlayOutCustomSoundEffect", int.class, 8.0); - new StateDependentListener(ENABLED, FightState.Schem, this); - new StateDependent(ENABLED, FightState.Schem) { + new StateDependentListener(TechHiderWrapper.ENABLED, FightState.Schem, this); + new StateDependent(TechHiderWrapper.ENABLED, FightState.Schem) { @Override public void enable() { packetHiders.forEach(TinyProtocol.instance::addFilter); @@ -91,11 +90,11 @@ public class HullHider implements Listener { packetHiders.forEach(TinyProtocol.instance::removeFilter); } }.register(); - new StateDependentTask(ENABLED, FightState.Schem, this::onTick, 0, 1); + new StateDependentTask(TechHiderWrapper.ENABLED, FightState.Schem, this::onTick, 0, 1); } public void initialize(FightTeam team) { - if(!ENABLED) + if(!TechHiderWrapper.ENABLED) return; hullMap.get(team).initialize(); @@ -113,7 +112,7 @@ public class HullHider implements Listener { } public void updatePlayer(Player player) { - if(!ENABLED) + if(!TechHiderWrapper.ENABLED) return; FightTeam team = Fight.getPlayerTeam(player); @@ -145,7 +144,7 @@ public class HullHider implements Listener { } public boolean isBlockHidden(Player player, int x, int y, int z) { - if(!ENABLED) + if(!TechHiderWrapper.ENABLED) return false; for (Hull hull : hulls) @@ -156,7 +155,7 @@ public class HullHider implements Listener { } public boolean blockPrecise(Player player, int chunkX, int chunkY, int chunkZ) { - if(!ENABLED) + if(!TechHiderWrapper.ENABLED) return false; for (Hull hull : hulls)