From ce2a23f4b850fd0b9cfc82a5a2a9c3df1799898b Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 31 Oct 2026 15:00:37 +0100 Subject: [PATCH] Migrate BauSystem to the new TechHider and remove the legacy TechHider The new TechHider registers a permanent global filter, so BauSystem now uses a single BauTechHider that combines the hiding rules of the spectator techhider, /techhider and /xray per player. To support the different obfuscation blocks of these rules, ForPlayer now provides the obfuscation block per position. The ChunkHider now also checks single valued chunk sections, which were sent unfiltered before, and recalculates their block count if they change. Unhandled packet types are logged once; statistics, debug samples and ping responses are passed through. The legacy TechHider and its access widener entries are removed. --- BauSystem/BauSystem_Main/build.gradle.kts | 1 + .../features/techhider/BauTechHider.java | 137 ++++++++ .../features/techhider/HidingRule.java | 52 +++ .../features/techhider/TechHiderCommand.java | 31 +- .../features/world/SpectatorListener.java | 30 +- .../bausystem/features/xray/XrayCommand.java | 30 +- .../fightsystem/utils/TechHiderWrapper.java | 7 +- .../src/de/steamwar/hullhider/HullRegion.java | 4 + .../techhider/AccessPrivilegeProvider.java | 5 + .../src/de/steamwar/techhider/ChunkHider.java | 38 ++- .../steamwar/techhider/ObfuscationConfig.java | 2 + .../src/de/steamwar/techhider/TechHider.java | 22 +- .../steamwar/techhider/legacy/ChunkHider.java | 301 ------------------ .../techhider/legacy/ProtocolWrapper.java | 79 ----- .../steamwar/techhider/legacy/TechHider.java | 169 ---------- .../src/spigotcore.accesswidener | 31 -- 16 files changed, 295 insertions(+), 644 deletions(-) create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/BauTechHider.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/HidingRule.java delete mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ChunkHider.java delete mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ProtocolWrapper.java delete mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/TechHider.java diff --git a/BauSystem/BauSystem_Main/build.gradle.kts b/BauSystem/BauSystem_Main/build.gradle.kts index c387bc36..c320e674 100644 --- a/BauSystem/BauSystem_Main/build.gradle.kts +++ b/BauSystem/BauSystem_Main/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { annotationProcessor(libs.classindex) compileOnly(project(":SpigotCore", "default")) compileOnly(project(":KotlinCore", "default")) + implementation(project(":HiderCore")) compileOnly(libs.axiom) compileOnly(libs.authlib) diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/BauTechHider.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/BauTechHider.java new file mode 100644 index 00000000..a4fd51bf --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/BauTechHider.java @@ -0,0 +1,137 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 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.bausystem.features.techhider; + +import de.steamwar.bausystem.features.world.SpectatorListener; +import de.steamwar.bausystem.features.xray.XrayCommand; +import de.steamwar.linkage.Linked; +import de.steamwar.linkage.LinkedInstance; +import de.steamwar.techhider.AccessPrivilegeProvider; +import de.steamwar.techhider.TechHider; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +/** + * The single TechHider of the server. It combines the hiding rules of the spectator techhider, /techhider and /xray per player. + */ +@Linked +public class BauTechHider implements AccessPrivilegeProvider { + + private static final HidingRule[] NO_RULES = new HidingRule[0]; + + // Injected after construction, until then nothing is hidden + @LinkedInstance + public XrayCommand xrayCommand; + @LinkedInstance + public TechHiderCommand techHiderCommand; + @LinkedInstance + public SpectatorListener spectatorListener; + + public BauTechHider() { + new TechHider(this); + } + + @Override + public ForPlayer forPlayer(Player p) { + if (xrayCommand == null || techHiderCommand == null || spectatorListener == null) { + return new BauPlayerAccess(p, NO_RULES); + } + + // Region rules first: where rules overlap, the first one decides the obfuscation block + List rules = new ArrayList<>(); + xrayCommand.addHidingRules(p, rules); + techHiderCommand.addHidingRules(p, rules); + spectatorListener.addHidingRules(p, rules); + return new BauPlayerAccess(p, rules.toArray(NO_RULES)); + } + + @Override + public boolean isPlayerPrivilegedToPerformAction(Player p) { + return true; + } + + /** + * Snapshot of the hiding rules of one player, taken once per outgoing packet on the netty thread. + */ + private record BauPlayerAccess(Player player, HidingRule[] rules) implements ForPlayer { + + @Override + public Player getPlayer() { + return player; + } + + @Override + public boolean canAccessAllDataWithinChunk(int chunkX, int chunkZ) { + for (HidingRule rule : rules) { + if (rule.coversChunk(chunkX, chunkZ)) return false; + } + return true; + } + + @Override + public boolean canAccessPosition(int blockX, int blockY, int blockZ) { + return true; + } + + @Override + public boolean canAccessBlock(int blockX, int blockY, int blockZ, Block block) { + for (HidingRule rule : rules) { + if (rule.covers(blockX, blockY, blockZ) && rule.obfuscation().hidesBlock(block)) return false; + } + return true; + } + + @Override + public boolean canAccessBlockState(int blockX, int blockY, int blockZ, BlockState blockState) { + for (HidingRule rule : rules) { + if (rule.covers(blockX, blockY, blockZ) && rule.obfuscation().hidesBlockState(blockState)) return false; + } + return true; + } + + @Override + public boolean canAccessEntity(int entityId) { + return true; + } + + @Override + public boolean canAccessBlockEntity(int blockX, int blockY, int blockZ, BlockEntityType type) { + for (HidingRule rule : rules) { + if (rule.covers(blockX, blockY, blockZ) && rule.obfuscation().hidesBlockEntity(type)) return false; + } + return true; + } + + @Override + public BlockState getObfuscation(int blockX, int blockY, int blockZ) { + for (HidingRule rule : rules) { + if (rule.covers(blockX, blockY, blockZ)) return rule.obfuscation().getObfuscationState(); + } + // Only asked for positions a rule hides + return Blocks.END_STONE.defaultBlockState(); + } + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/HidingRule.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/HidingRule.java new file mode 100644 index 00000000..a7010e5a --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/HidingRule.java @@ -0,0 +1,52 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 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.bausystem.features.techhider; + +import de.steamwar.bausystem.region.Point; +import de.steamwar.bausystem.region.Region; +import de.steamwar.hullhider.HullRegion; +import de.steamwar.techhider.ObfuscationConfig; + +/** + * Hides the blocks of an obfuscation config within an area, or everywhere if the area is null. + */ +public record HidingRule(HullRegion area, ObfuscationConfig obfuscation) { + + public static HidingRule everywhere(ObfuscationConfig obfuscation) { + return new HidingRule(null, obfuscation); + } + + /** + * Covers the area including its extension. + */ + public static HidingRule of(Region.Area area, ObfuscationConfig obfuscation) { + Point min = area.getMinPoint(true); + Point max = area.getMaxPoint(true); + return new HidingRule(HullRegion.fromInclusive(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ()), obfuscation); + } + + public boolean covers(int x, int y, int z) { + return area == null || area.contains(x, y, z); + } + + public boolean coversChunk(int chunkX, int chunkZ) { + return area == null || !area.chunkOutside(chunkX, chunkZ); + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java index 2f401a59..b6fd7d8a 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java @@ -31,7 +31,7 @@ import de.steamwar.command.TypeMapper; import de.steamwar.core.CraftbukkitWrapper; import de.steamwar.linkage.Linked; import de.steamwar.linkage.LinkedInstance; -import de.steamwar.techhider.legacy.TechHider; +import de.steamwar.techhider.ObfuscationConfig; import net.md_5.bungee.api.ChatMessageType; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -41,6 +41,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Linked @@ -50,8 +51,9 @@ public class TechHiderCommand extends SWCommand implements Listener, ScoreboardE super("techhider", "hider", "obfuscate", "hide", "hide-tech"); } - private Map> techHiders = new HashMap<>(); - private Map> hidden = new HashMap<>(); + // Read on netty threads by the BauTechHider + private Map> hidingRules = new ConcurrentHashMap<>(); + private Map> hidden = new ConcurrentHashMap<>(); @LinkedInstance public XrayCommand xrayCommand; @@ -64,22 +66,15 @@ public class TechHiderCommand extends SWCommand implements Listener, ScoreboardE return; } - Optional techHider = techHiders.computeIfAbsent(region, rg -> { + Optional hidingRule = hidingRules.computeIfAbsent(region, rg -> { if (!region.getGameModeConfig().Techhider.Active) { return Optional.empty(); } - hidden.put(rg, new HashSet<>()); - - TechHider current = new TechHider((p, cX, cY) -> { - if (rg.getBuildArea().isChunkOutside(cX, cY)) return true; - return !hidden.get(rg).contains(p); - }, region.getGameModeConfig().Techhider.ObfuscateWith, region.getGameModeConfig().Techhider.HiddenBlocks, region.getGameModeConfig().Techhider.HiddenBlockEntities); - current.enable(); - - return Optional.of(current); + hidden.put(rg, ConcurrentHashMap.newKeySet()); + return Optional.of(HidingRule.of(rg.getBuildArea(), ObfuscationConfig.of(rg.getGameModeConfig().Techhider))); }); - if (!techHider.isPresent()) { + if (!hidingRule.isPresent()) { return; } @@ -128,6 +123,14 @@ public class TechHiderCommand extends SWCommand implements Listener, ScoreboardE hidden.values().forEach(set -> set.remove(event.getPlayer())); } + public void addHidingRules(Player player, List rules) { + hidden.forEach((region, players) -> { + if (players.contains(player)) { + hidingRules.getOrDefault(region, Optional.empty()).ifPresent(rules::add); + } + }); + } + public void disable(Region region, Player player) { hidden.computeIfPresent(region, (rg, set) -> { set.remove(player); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java index 645600cd..ae32e0c1 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java @@ -22,10 +22,11 @@ package de.steamwar.bausystem.features.world; import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.Permission; import de.steamwar.bausystem.config.BauServer; +import de.steamwar.bausystem.features.techhider.HidingRule; import de.steamwar.bausystem.utils.BauMemberUpdateEvent; import de.steamwar.linkage.Linked; import de.steamwar.sql.BauweltMember; -import de.steamwar.techhider.legacy.TechHider; +import de.steamwar.techhider.ObfuscationConfig; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -41,14 +42,18 @@ import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.player.*; import org.bukkit.util.Vector; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; @Linked public class SpectatorListener implements Listener { - private static final TechHider techHider; - private static final Set NO_TECHHIDER = new HashSet<>(); + private static final HidingRule SPECTATOR_RULE; + // Read on netty threads by the BauTechHider + private static final Set NO_TECHHIDER = ConcurrentHashMap.newKeySet(); static { Set materials = new HashSet<>(); @@ -99,19 +104,12 @@ public class SpectatorListener implements Listener { materials.add(Material.WATER); materials.remove(Material.BARRIER); materials.remove(Material.STONE); - techHider = new TechHider((TechHider.LocationEvaluator) (player, i, i1) -> { - return Permission.BUILD.hasPermission(player) || NO_TECHHIDER.contains(player); - }, Material.END_STONE, materials, new HashSet<>()); + SPECTATOR_RULE = HidingRule.everywhere(new ObfuscationConfig(Material.END_STONE, materials, Collections.emptySet())); } - private static void enableOrDisableTechhider() { - boolean enable = Bukkit.getOnlinePlayers() - .stream() - .anyMatch(player -> !(Permission.BUILD.hasPermission(player) || NO_TECHHIDER.contains(player))); - if (enable) { - techHider.enable(); - } else { - techHider.disable(); + public void addHidingRules(Player player, List rules) { + if (!(Permission.BUILD.hasPermission(player) || NO_TECHHIDER.contains(player))) { + rules.add(SPECTATOR_RULE); } } @@ -122,7 +120,6 @@ public class SpectatorListener implements Listener { NO_TECHHIDER.add(player); } resendChunks(player); - enableOrDisableTechhider(); } private static void resendChunks(Player player) { @@ -141,7 +138,6 @@ public class SpectatorListener implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { - enableOrDisableTechhider(); if (BauSystem.DEV_SERVER) return; if (event.getPlayer().getUniqueId().equals(BauServer.getInstance().getOwner())) { return; @@ -163,7 +159,6 @@ public class SpectatorListener implements Listener { @EventHandler public void onBauMemberUpdate(BauMemberUpdateEvent event) { - enableOrDisableTechhider(); if (!anySupervisorOnline(null) && !BauSystem.DEV_SERVER) { Bukkit.getOnlinePlayers().forEach(player -> { player.kickPlayer(""); @@ -180,7 +175,6 @@ public class SpectatorListener implements Listener { @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { NO_TECHHIDER.remove(event.getPlayer()); - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), SpectatorListener::enableOrDisableTechhider, 1); if (BauSystem.DEV_SERVER) return; if (!anySupervisorOnline(event.getPlayer())) { Bukkit.getOnlinePlayers().forEach(player -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java index aa90081c..0b334429 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java @@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.xray; import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.bausystem.BauSystem; +import de.steamwar.bausystem.features.techhider.HidingRule; import de.steamwar.bausystem.features.techhider.TechHiderCommand; import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.utils.ScoreboardElement; @@ -28,7 +29,7 @@ import de.steamwar.command.SWCommand; import de.steamwar.core.CraftbukkitWrapper; import de.steamwar.linkage.Linked; import de.steamwar.linkage.LinkedInstance; -import de.steamwar.techhider.legacy.TechHider; +import de.steamwar.techhider.ObfuscationConfig; import net.md_5.bungee.api.ChatMessageType; import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; import net.minecraft.server.level.ServerPlayer; @@ -43,6 +44,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerQuitEvent; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; @Linked @@ -52,9 +54,10 @@ public class XrayCommand extends SWCommand implements Listener, ScoreboardElemen super("xray"); } - private Map> techHiders = new HashMap<>(); + // Read on netty threads by the BauTechHider and the movement filter + private Map> hidingRules = new ConcurrentHashMap<>(); private Map> xrayedBlocks = new HashMap<>(); - private Map> hidden = new HashMap<>(); + private Map> hidden = new ConcurrentHashMap<>(); @LinkedInstance public TechHiderCommand techHiderCommand; @@ -67,19 +70,19 @@ public class XrayCommand extends SWCommand implements Listener, ScoreboardElemen return; } - Optional techHider = techHiders.computeIfAbsent(region, rg -> { + Optional hidingRule = hidingRules.computeIfAbsent(region, rg -> { if (!region.getGameModeConfig().Techhider.Active) { return Optional.empty(); } - hidden.put(rg, new HashSet<>()); + hidden.put(rg, ConcurrentHashMap.newKeySet()); Set blocks = new HashSet<>(Arrays.asList(region.getGameModeConfig().Techhider.ObfuscateWith)); if (blocks.contains(Material.END_STONE)) blocks.add(Material.END_STONE_BRICKS); xrayedBlocks.put(region, blocks); - return Optional.of(createXray(rg, blocks)); + return Optional.of(HidingRule.of(rg.getBuildArea(), new ObfuscationConfig(Material.STRUCTURE_VOID, blocks, Collections.emptySet()))); }); - if (!techHider.isPresent()) { + if (!hidingRule.isPresent()) { return; } @@ -139,13 +142,12 @@ public class XrayCommand extends SWCommand implements Listener, ScoreboardElemen } } - private TechHider createXray(Region rg, Set obfuscate) { - TechHider current = new TechHider((TechHider.LocationEvaluator) (p, cX, cY) -> { - if (rg.getBuildArea().isChunkOutside(cX, cY)) return true; - return !hidden.get(rg).contains(p); - }, Material.STRUCTURE_VOID, obfuscate, new HashSet<>()); - current.enable(); - return current; + public void addHidingRules(Player player, List rules) { + hidden.forEach((region, players) -> { + if (players.contains(player)) { + hidingRules.getOrDefault(region, Optional.empty()).ifPresent(rules::add); + } + }); } @EventHandler diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java index 1ccaad8e..6f0b1290 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java @@ -70,7 +70,7 @@ public class TechHiderWrapper extends StateDependent implements Listener { @Override public void enable() { ObfuscationConfig obfuscation = ObfuscationConfig.of(Config.GameModeConfig.Techhider); - new TechHider(obfuscation.getObfuscateWith(), newProvider(obfuscation)); + new TechHider(newProvider(obfuscation)); } private AccessPrivilegeProvider newProvider(ObfuscationConfig obfuscation) { @@ -150,6 +150,11 @@ public class TechHiderWrapper extends StateDependent implements Listener { public boolean canAccessBlockEntity(int blockX, int blockY, int blockZ, BlockEntityType type) { return !isHidden(blockX, blockY, blockZ) || !obfuscation.hidesBlockEntity(type); } + + @Override + public BlockState getObfuscation(int blockX, int blockY, int blockZ) { + return obfuscation.getObfuscationState(); + } } @Override diff --git a/HiderCore/src/de/steamwar/hullhider/HullRegion.java b/HiderCore/src/de/steamwar/hullhider/HullRegion.java index b8aacb0b..0006a2af 100644 --- a/HiderCore/src/de/steamwar/hullhider/HullRegion.java +++ b/HiderCore/src/de/steamwar/hullhider/HullRegion.java @@ -69,6 +69,10 @@ public final class HullRegion { return contains(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } + public boolean chunkOutside(int chunkX, int chunkZ) { + return chunkX < (minX >> 4) || chunkX > ((maxX - 1) >> 4) || chunkZ < (minZ >> 4) || chunkZ > ((maxZ - 1) >> 4); + } + /** * @return the index of the block within a bitset of {@link #volume()} bits, only valid for contained blocks */ diff --git a/HiderCore/src/de/steamwar/techhider/AccessPrivilegeProvider.java b/HiderCore/src/de/steamwar/techhider/AccessPrivilegeProvider.java index 38b9b463..be0599cb 100644 --- a/HiderCore/src/de/steamwar/techhider/AccessPrivilegeProvider.java +++ b/HiderCore/src/de/steamwar/techhider/AccessPrivilegeProvider.java @@ -53,5 +53,10 @@ public interface AccessPrivilegeProvider { boolean canAccessEntity(int entityId); boolean canAccessBlockEntity(int blockX, int blockY, int blockZ, BlockEntityType type); + + /** + * @return the block state sent instead of a block this player may not access at this position + */ + BlockState getObfuscation(int blockX, int blockY, int blockZ); } } diff --git a/HiderCore/src/de/steamwar/techhider/ChunkHider.java b/HiderCore/src/de/steamwar/techhider/ChunkHider.java index 9ad25a4e..6cabee7b 100644 --- a/HiderCore/src/de/steamwar/techhider/ChunkHider.java +++ b/HiderCore/src/de/steamwar/techhider/ChunkHider.java @@ -31,6 +31,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.entity.Player; +import java.util.Arrays; import java.util.List; import java.util.function.UnaryOperator; @@ -45,12 +46,6 @@ public class ChunkHider { private final int BLOCKS_PER_SECTION = 4096; private final int BIOMES_PER_SECTION = 64; - private final int blockIdUsedForHiding; - - public ChunkHider(Block blockUsedForObfuscation) { - blockIdUsedForHiding = Block.BLOCK_STATE_REGISTRY.getId(blockUsedForObfuscation.defaultBlockState()); - } - private int getLongsRequiredToEncodeEntries(int bitsPerEntry, int entryCount) { int entriesPerLong = Long.SIZE / bitsPerEntry; int dataLengthAsLongCount = (entryCount + entriesPerLong - 1) / entriesPerLong; @@ -89,9 +84,22 @@ public class ChunkHider { if (bitsPerBlock == 0) { int sectionBlockId = ProtocolUtils.readVarInt(in); - out.writeShort(blockCount); - out.writeByte(bitsPerBlock); - ProtocolUtils.writeVarInt(out, sectionBlockId); + int[] blockData = new int[BLOCKS_PER_SECTION]; + Arrays.fill(blockData, sectionBlockId); + int[] obfuscatedBlockData = obfuscateBlockDataArray(access, chunkX, chunkZ, yOffset, blockData); + + if (Arrays.equals(blockData, obfuscatedBlockData)) { + out.writeShort(blockCount); + out.writeByte(bitsPerBlock); + ProtocolUtils.writeVarInt(out, sectionBlockId); + } else { + // The client skips sections without non-air blocks, so the count has to include the obfuscation blocks + out.writeShort(countNonAirBlocks(obfuscatedBlockData)); + out.writeByte(15); + for (long rawDataSegment : encodeDirectBlockDataArray(obfuscatedBlockData)) { + out.writeLong(rawDataSegment); + } + } } else if (bitsPerBlock <= BIT_PER_BLOCK_INDIRECTION_LIMIT) { int palletLength = ProtocolUtils.readVarInt(in); int[] pallet = ProtocolUtils.readVarIntArray(in, palletLength); @@ -198,7 +206,7 @@ public class ChunkHider { if (access.canAccessPosition(worldX, worldY, worldZ) && access.canAccessBlock(worldX, worldY, worldZ, block) && access.canAccessBlockState(worldX, worldY, worldZ, blockState)) { obfuscatedData[blockDataIndex] = blockId; } else { - obfuscatedData[blockDataIndex] = blockIdUsedForHiding; + obfuscatedData[blockDataIndex] = Block.getId(access.getObfuscation(worldX, worldY, worldZ)); } } } @@ -207,6 +215,16 @@ public class ChunkHider { return obfuscatedData; } + private int countNonAirBlocks(int[] blockDataArray) { + int count = 0; + for (int blockId : blockDataArray) { + if (!Block.BLOCK_STATE_REGISTRY.byId(blockId).isAir()) { + count++; + } + } + return count; + } + private int[] resolveDirectBlockDataArray(long[] rawDataArray, byte bitsPerBlock) { SimpleBitStorage data = new SimpleBitStorage(bitsPerBlock, BLOCKS_PER_SECTION, rawDataArray); diff --git a/HiderCore/src/de/steamwar/techhider/ObfuscationConfig.java b/HiderCore/src/de/steamwar/techhider/ObfuscationConfig.java index cc8310a5..554abaa3 100644 --- a/HiderCore/src/de/steamwar/techhider/ObfuscationConfig.java +++ b/HiderCore/src/de/steamwar/techhider/ObfuscationConfig.java @@ -49,6 +49,7 @@ public final class ObfuscationConfig { } private final Block obfuscateWith; + private final BlockState obfuscationState; private final Set blocks; private final Set blockStates; private final Set> blockEntityTypes; @@ -59,6 +60,7 @@ public final class ObfuscationConfig { */ public ObfuscationConfig(Material obfuscateWith, Set hiddenBlocks, Set hiddenBlockEntities) { this.obfuscateWith = CraftMagicNumbers.getBlock(obfuscateWith); + this.obfuscationState = this.obfuscateWith.defaultBlockState(); this.blocks = hiddenBlocks.stream() .map(CraftMagicNumbers::getBlock) diff --git a/HiderCore/src/de/steamwar/techhider/TechHider.java b/HiderCore/src/de/steamwar/techhider/TechHider.java index eee198e6..af640d18 100644 --- a/HiderCore/src/de/steamwar/techhider/TechHider.java +++ b/HiderCore/src/de/steamwar/techhider/TechHider.java @@ -36,16 +36,20 @@ import net.minecraft.network.protocol.configuration.ClientboundUpdateEnabledFeat import net.minecraft.network.protocol.cookie.ClientboundCookieRequestPacket; import net.minecraft.network.protocol.game.*; import net.minecraft.network.protocol.login.*; +import net.minecraft.network.protocol.ping.ClientboundPongResponsePacket; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.ToIntFunction; +import java.util.logging.Level; /** * The TechHider follows the default-deny security principle, @@ -56,16 +60,14 @@ public class TechHider { private final Set> bypassingPackets; private final Map>, BiFunction, Packet>> packetProcessors; - private final BlockState blockStateUsedForObfuscation; + private final Set> loggedUnhandledPackets = ConcurrentHashMap.newKeySet(); private final ChunkHider chunkHider; private final AccessPrivilegeProvider privilegeProvider; // TODO handle packet bundle - public TechHider(Block blockUsedForObfuscation, AccessPrivilegeProvider privilegeProvider) { - this.blockStateUsedForObfuscation = blockUsedForObfuscation.defaultBlockState(); - - this.chunkHider = new ChunkHider(blockUsedForObfuscation); + public TechHider(AccessPrivilegeProvider privilegeProvider) { + this.chunkHider = new ChunkHider(); this.privilegeProvider = privilegeProvider; this.bypassingPackets = new HashSet<>(List.of( @@ -176,6 +178,9 @@ public class TechHider { ClientboundBlockChangedAckPacket.class, // 7.1.5 Acknowledge Block Change ClientboundChunkBatchFinishedPacket.class, // 7.1.12 Chunk Batch Finished (Delimiter) ClientboundChunkBatchStartPacket.class, // 7.1.13 Chunk Batch Start (Delimiter) + ClientboundAwardStatsPacket.class, // 7.1.4 Award Statistics: the player's own statistics + ClientboundDebugSamplePacket.class, // 7.1.28 Debug Sample: server tick timings + ClientboundPongResponsePacket.class, // Ping Response: answer to the client's own ping ClientboundChunksBiomesPacket.class, // 7.1.14 Chunk Biomes ClientboundContainerClosePacket.class, // 7.1.18 Close Container ClientboundSetChunkCacheCenterPacket.class, // 7.1.93 Set Center Chunk @@ -359,6 +364,9 @@ public class TechHider { if (processor != null) { return processor.apply(access.get(), packet); } else { + if (loggedUnhandledPackets.add(packet.getClass())) { + Bukkit.getLogger().log(Level.WARNING, "[TechHider] Dropping unhandled packet type " + packet.getClass().getName()); + } return null; } } @@ -438,7 +446,7 @@ public class TechHider { if (access.canAccessPosition(blockX, blockY, blockZ) && access.canAccessBlock(blockX, blockY, blockZ, block) && access.canAccessBlockState(blockX, blockY, blockZ, blockState)) { return packet; } else if (access.canAccessPosition(blockX, blockY, blockZ)) { - return new ClientboundBlockUpdatePacket(blockPos, blockStateUsedForObfuscation); + return new ClientboundBlockUpdatePacket(blockPos, access.getObfuscation(blockX, blockY, blockZ)); } else { return null; } @@ -491,7 +499,7 @@ public class TechHider { filteredStates.add(state); } else if (access.canAccessPosition(worldX, worldY, worldZ)) { filteredPos.add(posShort); - filteredStates.add(blockStateUsedForObfuscation); + filteredStates.add(access.getObfuscation(worldX, worldY, worldZ)); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ChunkHider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ChunkHider.java deleted file mode 100644 index bca91a11..00000000 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ChunkHider.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.techhider.legacy; - -import de.steamwar.core.ProtocolUtils; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import lombok.Getter; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.util.SimpleBitStorage; -import net.minecraft.world.level.block.entity.BlockEntityType; -import org.bukkit.entity.Player; - -import java.util.Collections; -import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.UnaryOperator; -import java.util.stream.Collectors; - -@Deprecated -public class ChunkHider { - public static final ChunkHider impl = new ChunkHider(); - - private static final UnaryOperator chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkWithLightPacket::new); - private static final UnaryOperator chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class, ClientboundLevelChunkPacketData::new); - - public BiFunction chunkHiderGenerator(TechHider techHider) { - return (p, packet) -> { - int chunkX = packet.getX(); - int chunkZ = packet.getZ(); - if (techHider.getLocationEvaluator().skipChunk(p, chunkX, chunkZ)) { - return packet; - } - - packet = chunkPacketCloner.apply(packet); - ClientboundLevelChunkPacketData dataWrapper = chunkDataCloner.apply(packet.getChunkData()); - - Set hiddenBlockEntities = techHider.getHiddenBlockEntities(); - dataWrapper.blockEntitiesData = dataWrapper.blockEntitiesData.stream() - .filter(te -> tileEntityVisible(hiddenBlockEntities, te)) - .collect(Collectors.toList()); - - ByteBuf in = Unpooled.wrappedBuffer(dataWrapper.buffer); - ByteBuf out = Unpooled.buffer(in.readableBytes() + 64); - for (int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) { - SectionHider section = new SectionHider(p, techHider, in, out, chunkX, yOffset / 16, chunkZ); - section.copyBlockCount(); - - blocks(section); - biomes(section); - } - - if (in.readableBytes() != 0) { - throw new IllegalStateException("ChunkHider21: Incomplete chunk data, " + in.readableBytes() + " bytes left"); - } - - byte[] data = new byte[out.readableBytes()]; - out.readBytes(data); - dataWrapper.buffer = data; - - packet.chunkData = dataWrapper; - return packet; - }; - } - - protected boolean tileEntityVisible(Set hiddenBlockEntities, ClientboundLevelChunkPacketData.BlockEntityInfo tile) { - BlockEntityType type = tile.type; - String path = BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type).getPath(); - return !hiddenBlockEntities.contains(path); - } - - private void blocks(SectionHider section) { - section.copyBitsPerBlock(); - - boolean singleValued = section.getBitsPerBlock() == 0; - if (singleValued) { - int value = ProtocolUtils.readVarInt(section.getIn()); - ProtocolUtils.writeVarInt(section.getOut(), !section.isSkipSection() && section.getObfuscate().contains(value) ? section.getTarget() : value); - return; - } else if (section.getBitsPerBlock() < 9) { - // Indirect (paletted) storage – only present when bitsPerBlock < 9 in 1.21+ - section.processPalette(); - } - - if (section.isSkipSection() || (!section.blockPrecise() && section.isPaletted())) { - section.skipNewDataArray(4096); - return; - } - - SimpleBitStorage values = new SimpleBitStorage(section.getBitsPerBlock(), 4096, section.readNewDataArray(4096)); - - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - int pos = (((y * 16) + z) * 16) + x; - - TechHider.State test = section.test(x, y, z); - - switch (test) { - case SKIP: - break; - case CHECK: - if (!section.getObfuscate().contains(values.get(pos))) { - break; - } - case HIDE: - values.set(pos, section.getTarget()); - break; - case HIDE_AIR: - default: - values.set(pos, section.getAir()); - } - } - } - } - - section.writeDataArray(values.getRaw()); - } - - private void biomes(SectionHider section) { - section.copyBitsPerBlock(); - if (section.getBitsPerBlock() == 0) { - section.copyVarInt(); - } else if (section.getBitsPerBlock() < 6) { - section.skipPalette(); - section.skipNewDataArray(64); - } else { - // Direct (global) biome IDs – no palette present - section.skipNewDataArray(64); - } - } - - @Getter - class SectionHider { - private final Player player; - private final TechHider techHider; - private final ByteBuf in; - private final ByteBuf out; - - private final int chunkX; - private final int chunkY; - private final int chunkZ; - private final int offsetX; - private final int offsetY; - private final int offsetZ; - - private final boolean skipSection; - - private boolean paletted; - private int bitsPerBlock; - private int blockCount; - private int air; - private int target; - private Set obfuscate; - - public SectionHider(Player player, TechHider techHider, ByteBuf in, ByteBuf out, int chunkX, int chunkY, int chunkZ) { - this.player = player; - this.techHider = techHider; - this.in = in; - this.out = out; - this.chunkX = chunkX; - this.chunkY = chunkY; - this.chunkZ = chunkZ; - this.offsetX = 16 * chunkX; - this.offsetY = 16 * chunkY; - this.offsetZ = 16 * chunkZ; - this.skipSection = techHider.getLocationEvaluator().skipChunkSection(player, chunkX, chunkY, chunkZ); - - this.paletted = false; - this.bitsPerBlock = 0; - this.air = TechHider.AIR_ID; - this.target = techHider.getObfuscationTargetId(); - this.obfuscate = techHider.getObfuscateIds(); - } - - public boolean blockPrecise() { - return techHider.getLocationEvaluator().blockPrecise(player, chunkX, chunkY, chunkZ); - } - - public TechHider.State test(int x, int y, int z) { - return techHider.getLocationEvaluator().check(player, offsetX + x, offsetY + y, offsetZ + z); - } - - public void copyBlockCount() { - this.blockCount = in.readShort(); - out.writeShort(blockCount); - } - - public void copyBitsPerBlock() { - bitsPerBlock = in.readByte(); - out.writeByte(bitsPerBlock); - } - - public int copyVarInt() { - int value = ProtocolUtils.readVarInt(in); - ProtocolUtils.writeVarInt(out, value); - return value; - } - - public void skipPalette() { - int paletteLength = copyVarInt(); - for (int i = 0; i < paletteLength; i++) { - copyVarInt(); - } - } - - public void processPalette() { - if (skipSection) { - skipPalette(); - return; - } - - int paletteLength = copyVarInt(); - if (paletteLength == 0) return; - - paletted = true; - air = 0; - target = 0; - - for (int i = 0; i < paletteLength; i++) { - int entry = ProtocolUtils.readVarInt(in); - if (obfuscate.contains(entry)) { - entry = techHider.getObfuscationTargetId(); - } - - if (entry == TechHider.AIR_ID) { - air = i; - } else if (entry == techHider.getObfuscationTargetId()) { - target = i; - } - - ProtocolUtils.writeVarInt(out, entry); - } - obfuscate = Collections.emptySet(); - } - - public void skipDataArray() { - int dataArrayLength = copyVarInt(); - out.writeBytes(in, dataArrayLength * 8); - } - - public void skipNewDataArray(int entries) { - if (bitsPerBlock == 0) { - return; - } - - char valuesPerLong = (char) (64 / bitsPerBlock); - int i1 = (entries + valuesPerLong - 1) / valuesPerLong; - out.writeBytes(in, i1 * Long.BYTES); - } - - public long[] readDataArray() { - long[] array = new long[copyVarInt()]; - for (int i = 0; i < array.length; i++) { - array[i] = in.readLong(); - } - - return array; - } - - public long[] readNewDataArray(int entries) { - if (bitsPerBlock == 0) { - return new long[entries]; - } - - char valuesPerLong = (char) (64 / bitsPerBlock); - int i1 = (entries + valuesPerLong - 1) / valuesPerLong; - long[] array = new long[i1]; - for (int i = 0; i < i1; i++) { - array[i] = in.readLong(); - } - - return array; - } - - public void writeDataArray(long[] array) { - for (long l : array) { - out.writeLong(l); - } - } - } -} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ProtocolWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ProtocolWrapper.java deleted file mode 100644 index cb7b8d05..00000000 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/ProtocolWrapper.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.techhider.legacy; - -import net.minecraft.core.SectionPos; -import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.function.BiFunction; - -@Deprecated -public class ProtocolWrapper { - public static final ProtocolWrapper impl = new ProtocolWrapper(); - - public BiFunction multiBlockChangeGenerator(TechHider techHider) { - return (p, packet) -> { - TechHider.LocationEvaluator locationEvaluator = techHider.getLocationEvaluator(); - SectionPos chunkCoords = packet.sectionPos; - int chunkX = chunkCoords.getX(); - int chunkY = chunkCoords.getY(); - int chunkZ = chunkCoords.getZ(); - if (locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ)) { - return packet; - } - - packet = TechHider.multiBlockChangeCloner.apply(packet); - final short[] oldPos = packet.positions; - final BlockState[] oldBlocks = packet.states; - ArrayList poss = new ArrayList<>(oldPos.length); - ArrayList blocks = new ArrayList<>(oldPos.length); - for (int i = 0; i < oldPos.length; i++) { - short pos = oldPos[i]; - BlockState block = oldBlocks[i]; - switch (locationEvaluator.check(p, 16 * chunkX + (pos >> 8 & 0xF), 16 * chunkY + (pos & 0xF), 16 * chunkZ + (pos >> 4 & 0xF))) { - case SKIP: - poss.add(pos); - blocks.add(block); - break; - case CHECK: - poss.add(pos); - blocks.add(techHider.iBlockDataHidden(block) ? (BlockState) techHider.getObfuscationTarget() : block); - break; - default: - break; - } - } - - if (blocks.isEmpty()) return null; - - short[] newPos = new short[poss.size()]; - for (int i = 0; i < newPos.length; i++) { - newPos[i] = poss.get(i); - } - - packet.positions = newPos; - packet.states = blocks.toArray(BlockState[]::new); - return packet; - }; - } -} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/TechHider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/TechHider.java deleted file mode 100644 index 5c9cd169..00000000 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/legacy/TechHider.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 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.techhider.legacy; - -import com.comphenix.tinyprotocol.TinyProtocol; -import de.steamwar.core.BlockIds; -import de.steamwar.core.ProtocolUtils; -import lombok.Getter; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; -import net.minecraft.network.protocol.game.*; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.Player; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.UnaryOperator; -import java.util.stream.Collectors; - -@Deprecated -public class TechHider { - - public static final Class blockPosition = BlockPos.class; - - public static final Class iBlockData = BlockState.class; - public static final Class block = Block.class; - - public boolean iBlockDataHidden(BlockState iBlockData) { - return obfuscateIds.contains(BlockIds.impl.getCombinedId(iBlockData)); - } - - public static final Object AIR = CraftMagicNumbers.getBlock(Material.AIR).defaultBlockState(); - public static final int AIR_ID = BlockIds.impl.materialToId(Material.AIR); - - private final Map, BiFunction> techhiders = new HashMap<>(); - @Getter - private final LocationEvaluator locationEvaluator; - @Getter - private final Object obfuscationTarget; - @Getter - private final int obfuscationTargetId; - @Getter - private final Set obfuscateIds; - @Getter - private final Set hiddenBlockEntities; - - public TechHider(LocationEvaluator locationEvaluator, Material obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { - this.locationEvaluator = locationEvaluator; - this.obfuscateIds = obfuscate.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet()); - this.hiddenBlockEntities = hiddenBlockEntities; - this.obfuscationTarget = CraftMagicNumbers.getBlock(obfuscationTarget).defaultBlockState(); - this.obfuscationTargetId = BlockIds.impl.materialToId(obfuscationTarget); - - techhiders.put(ClientboundBlockEventPacket.class, (player, o) -> this.blockActionHider(player, (ClientboundBlockEventPacket) o)); - techhiders.put(ClientboundBlockUpdatePacket.class, (player, o) -> this.blockChangeHider(player, (ClientboundBlockUpdatePacket) o)); - techhiders.put(ClientboundBlockEntityDataPacket.class, (player, o) -> this.tileEntityDataHider(player, (ClientboundBlockEntityDataPacket) o)); - techhiders.put(ClientboundSectionBlocksUpdatePacket.class, (BiFunction) ProtocolWrapper.impl.multiBlockChangeGenerator(this)); - techhiders.put(ClientboundLevelChunkWithLightPacket.class, (BiFunction) ChunkHider.impl.chunkHiderGenerator(this)); - techhiders.put(ServerboundUseItemOnPacket.class, (p, packet) -> locationEvaluator.suppressInteractions(p) ? null : packet); - techhiders.put(ServerboundInteractPacket.class, (p, packet) -> locationEvaluator.suppressInteractions(p) ? null : packet); - - } - - public void enable() { - techhiders.forEach((type, playerObjectBiFunction) -> TinyProtocol.instance.addFilter((Class) type, playerObjectBiFunction)); - } - - public void disable() { - techhiders.forEach(TinyProtocol.instance::removeFilter); - } - - public static final UnaryOperator multiBlockChangeCloner = ProtocolUtils.shallowCloneGenerator(ClientboundSectionBlocksUpdatePacket.class, ClientboundSectionBlocksUpdatePacket::new); - - private static final UnaryOperator blockChangeCloner = ProtocolUtils.shallowCloneGenerator(ClientboundBlockUpdatePacket.class, ClientboundBlockUpdatePacket::new); - - private ClientboundBlockUpdatePacket blockChangeHider(Player p, ClientboundBlockUpdatePacket packet) { - switch (locationEvaluator.checkBlockPos(p, packet.getPos())) { - case SKIP: - return packet; - case CHECK: - if (!iBlockDataHidden(packet.blockState)) { - return packet; - } - case HIDE: - packet = blockChangeCloner.apply(packet); - packet.blockState = (BlockState) obfuscationTarget; - return packet; - case HIDE_AIR: - default: - packet = blockChangeCloner.apply(packet); - packet.blockState = (BlockState) AIR; - return packet; - } - } - - private Object blockActionHider(Player p, ClientboundBlockEventPacket packet) { - if (locationEvaluator.checkBlockPos(p, packet.getPos()) == State.SKIP) { - return packet; - } - return null; - } - - private ClientboundBlockEntityDataPacket tileEntityDataHider(Player p, ClientboundBlockEntityDataPacket packet) { - switch (locationEvaluator.checkBlockPos(p, packet.getPos())) { - case SKIP: - return packet; - case CHECK: - if (packet.getType() != BlockEntityType.SIGN) { - return packet; - } - default: - return null; - } - } - - public enum State { - SKIP, - CHECK, - HIDE, - HIDE_AIR - } - - public interface LocationEvaluator { - default boolean suppressInteractions(Player player) { - return false; - } - - boolean skipChunk(Player player, int x, int z); - - default boolean skipChunkSection(Player player, int x, int y, int z) { - return skipChunk(player, x, z); - } - - default State check(Player player, int x, int y, int z) { - return skipChunkSection(player, ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(y), ProtocolUtils.posToChunk(z)) ? State.SKIP : State.CHECK; - } - - default State checkBlockPos(Player player, Vec3i pos) { - return check(player, pos.getX(), pos.getY(), pos.getZ()); - } - - default boolean blockPrecise(Player player, int x, int y, int z) { - return false; - } - } -} diff --git a/SpigotCore/SpigotCore_Main/src/spigotcore.accesswidener b/SpigotCore/SpigotCore_Main/src/spigotcore.accesswidener index 99170241..210a5faf 100644 --- a/SpigotCore/SpigotCore_Main/src/spigotcore.accesswidener +++ b/SpigotCore/SpigotCore_Main/src/spigotcore.accesswidener @@ -35,34 +35,3 @@ accessible field net/minecraft/network/protocol/game/ClientboundRotateHeadPacket mutable field net/minecraft/network/protocol/game/ClientboundRotateHeadPacket yHeadRot B accessible field net/minecraft/network/protocol/game/ClientboundRotateHeadPacket entityId I mutable field net/minecraft/network/protocol/game/ClientboundRotateHeadPacket entityId I - -# For legacy/ChunkHider -## transitive-extendable means that a public no args constructor is added without any super initialization -transitive-extendable class net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket -accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket chunkData Lnet/minecraft/network/protocol/game/ClientboundLevelChunkPacketData; -mutable field net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket chunkData Lnet/minecraft/network/protocol/game/ClientboundLevelChunkPacketData; - -## transitive-extendable means that a public no args constructor is added without any super initialization -transitive-extendable class net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData -accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData buffer [B -mutable field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData buffer [B -accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData blockEntitiesData Ljava/util/List; -mutable field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData blockEntitiesData Ljava/util/List; - -accessible class net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo -accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo type Lnet/minecraft/world/level/block/entity/BlockEntityType; -accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo packedXZ I -accessible field net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData$BlockEntityInfo y I - -# For legacy/TechHider -## transitive-extendable means that a public no args constructor is added without any super initialization -transitive-extendable class net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket -accessible field net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket sectionPos Lnet/minecraft/core/SectionPos; -accessible field net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket positions [S -mutable field net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket positions [S -accessible field net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket states [Lnet/minecraft/world/level/block/state/BlockState; -mutable field net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket states [Lnet/minecraft/world/level/block/state/BlockState; - -## transitive-extendable means that a public no args constructor is added without any super initialization -transitive-extendable class net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket -mutable field net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket blockState Lnet/minecraft/world/level/block/state/BlockState; \ No newline at end of file