Fix final formatting stuff

This commit is contained in:
2026-05-22 21:29:58 +02:00
parent 3bcff4c5ce
commit 4f9fe07951
14 changed files with 144 additions and 485 deletions
@@ -227,7 +227,7 @@ public class TinyProtocol {
}
}
public <T> void addFilter(Class<T> packetType, BiFunction<Player, ? super T, Object> filter) {
public <T extends Packet<?>> void addFilter(Class<T> packetType, BiFunction<Player, ? super T, Object> filter) {
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add((BiFunction) filter);
}
@@ -235,8 +235,8 @@ public class TinyProtocol {
packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter);
}
public void addGlobalClientboundFilter(BiFunction<Player, Object, Object> filter) {
globalClientboundFilters.add(filter);
public void addGlobalClientboundFilter(BiFunction<Player, Packet<?>, Object> filter) {
globalClientboundFilters.add((BiFunction) filter);
}
/**
@@ -453,7 +453,7 @@ public class TinyProtocol {
try {
msg = filterPacket(player, msg);
if(msg instanceof Packet<?>) {
if (msg instanceof Packet<?>) {
for (BiFunction<Player, Object, Object> filter : globalClientboundFilters) {
msg = filter.apply(player, msg);
if (msg == null) break;
@@ -24,9 +24,15 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import org.bukkit.entity.Player;
public interface AccessPrivilegeProvider {
boolean isEveryonePrivilegedToAccessAllDataWithinChunk(int chunkX, int chunkZ);
boolean isPlayerPrivilegedToAccessPosition(Player p, int blockX, int blockY, int blockZ);
boolean isPlayerPrivilegedToAccessBlock(Player p, int blockX, int blockY, int blockZ, Block block);
boolean isPlayerPrivilegedToAccessEntity(Player p, int entityId);
boolean isPlayerPrivilegedToAccessBlockEntity(Player p, int blockX, int blockY, int blockZ, BlockEntityType<?> type);
boolean isPlayerPrivalegedToPerformAction(Player p);
boolean isPlayerPrivilegedToPerformAction(Player p);
}
@@ -19,17 +19,12 @@
package de.steamwar.techhider;
import de.steamwar.Reflection;
import net.minecraft.core.IdMapper;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import org.bukkit.Material;
import org.bukkit.Registry;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import java.util.HashSet;
@@ -22,9 +22,6 @@ package de.steamwar.techhider;
import de.steamwar.Reflection;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
@@ -34,10 +31,9 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.List;
import java.util.function.UnaryOperator;
public class ChunkHider {
private static final UnaryOperator<Object> chunkPacketShallowCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class);
private static final UnaryOperator<Object> chunkDataShallowCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class);
@@ -54,18 +50,16 @@ public class ChunkHider {
private final int BLOCKS_PER_SECTION = 4096;
private final int BIOMES_PER_SECTION = 64;
private final byte BITS_PER_LONG = Long.SIZE;
private final int blockIdUsedForHiding;
private final AccessPrivilegeProvider accessPrivilegeProvider;
public ChunkHider(Block blockUsedForObfuscation, AccessPrivilegeProvider accessPrivilegeProvider) {
blockIdUsedForHiding = Block.BLOCK_STATE_REGISTRY.getId(blockUsedForObfuscation.defaultBlockState());
blockIdUsedForHiding = Block.BLOCK_STATE_REGISTRY.getId(blockUsedForObfuscation.defaultBlockState());
this.accessPrivilegeProvider = accessPrivilegeProvider;
}
private int getLongsRequiredToEncodeEntries(int bitsPerEntry, int entryCount) {
int entriesPerLong = BITS_PER_LONG / bitsPerEntry;
int entriesPerLong = Long.SIZE / bitsPerEntry;
int dataLengthAsLongCount = (entryCount + entriesPerLong - 1) / entriesPerLong;
return dataLengthAsLongCount;
@@ -75,7 +69,7 @@ public class ChunkHider {
int dataLengthAsLongCount = getLongsRequiredToEncodeEntries(bitsPerEntry, entryCount);
long[] dataArray = new long[dataLengthAsLongCount];
for(int i = 0; i < dataLengthAsLongCount; i++){
for (int i = 0; i < dataLengthAsLongCount; i++) {
dataArray[i] = dataSource.readLong();
}
@@ -98,22 +92,21 @@ public class ChunkHider {
byte bitsPerBlock = in.readByte();
if(bitsPerBlock == 0) {
if (bitsPerBlock == 0) {
int sectionBlockId = ProtocolUtils.readVarInt(in);
out.writeShort(blockCount);
out.writeByte(bitsPerBlock);
ProtocolUtils.writeVarInt(out, sectionBlockId);
}
else if (bitsPerBlock <= BIT_PER_BLOCK_INDIRECTION_LIMIT) {
} else if (bitsPerBlock <= BIT_PER_BLOCK_INDIRECTION_LIMIT) {
int palletLength = ProtocolUtils.readVarInt(in);
int[] pallet = ProtocolUtils.readVarIntArray(in, palletLength);
long[] rawData = readSectionDataFromBuffer(in, bitsPerBlock, BLOCKS_PER_SECTION);
long[] rawData = readSectionDataFromBuffer(in, bitsPerBlock, BLOCKS_PER_SECTION);
SimpleBitStorage data = new SimpleBitStorage(bitsPerBlock, BLOCKS_PER_SECTION, rawData);
int[] resolvedData = new int[BLOCKS_PER_SECTION];
for(int i = 0; i < BLOCKS_PER_SECTION; i++){
for (int i = 0; i < BLOCKS_PER_SECTION; i++) {
int palletReference = data.get(i);
resolvedData[i] = pallet[palletReference];
}
@@ -125,7 +118,7 @@ public class ChunkHider {
out.writeShort(blockCount);
out.writeByte(15);
for(long rawDataSegment : reEncodedData) {
for (long rawDataSegment : reEncodedData) {
out.writeLong(rawDataSegment);
}
/*
@@ -158,9 +151,8 @@ public class ChunkHider {
out.writeLong(rawDataSegment);
}*/
}
else {
long[] rawData = readSectionDataFromBuffer(in, bitsPerBlock, BLOCKS_PER_SECTION);
} else {
long[] rawData = readSectionDataFromBuffer(in, bitsPerBlock, BLOCKS_PER_SECTION);
int[] blockData = resolveDirectBlockDataArray(rawData, bitsPerBlock);
@@ -171,7 +163,7 @@ public class ChunkHider {
out.writeShort(blockCount);
out.writeByte(15);
for(long rawDataSegment : reEncodedData) {
for (long rawDataSegment : reEncodedData) {
out.writeLong(rawDataSegment);
}
}
@@ -205,15 +197,13 @@ public class ChunkHider {
int worldZ = sectionZ + (SECTION_SPAN_SIZE * chunkZ);
int blockId = blockDataArray[blockDataIndex];
BlockState blockState = Block.BLOCK_STATE_REGISTRY.byId(blockId);
BlockState blockState = Block.BLOCK_STATE_REGISTRY.byId(blockId);
Block block = blockState.getBlock();
if(accessPrivilegeProvider.isPlayerPrivilegedToAccessPosition(player, worldX, worldY, worldZ) && accessPrivilegeProvider.isPlayerPrivilegedToAccessBlock(player, worldX, worldY, worldZ, block)) {
if (accessPrivilegeProvider.isPlayerPrivilegedToAccessPosition(player, worldX, worldY, worldZ) && accessPrivilegeProvider.isPlayerPrivilegedToAccessBlock(player, worldX, worldY, worldZ, block)) {
obfuscatedData[blockDataIndex] = blockId;
}
else {
} else {
obfuscatedData[blockDataIndex] = blockIdUsedForHiding;
}
}
@@ -227,7 +217,7 @@ public class ChunkHider {
SimpleBitStorage data = new SimpleBitStorage(bitsPerBlock, BLOCKS_PER_SECTION, rawDataArray);
int[] resolvedData = new int[BLOCKS_PER_SECTION];
for(int i = 0; i < BLOCKS_PER_SECTION; i++){
for (int i = 0; i < BLOCKS_PER_SECTION; i++) {
resolvedData[i] = data.get(i);
}
@@ -238,7 +228,7 @@ public class ChunkHider {
int longsRequiredToEncodeData = getLongsRequiredToEncodeEntries(15, blockDataArray.length);
SimpleBitStorage reEncodedData = new SimpleBitStorage(15, BLOCKS_PER_SECTION, new long[longsRequiredToEncodeData]);
for(int i = 0; i < blockDataArray.length; i++) {
for (int i = 0; i < blockDataArray.length; i++) {
int blockId = blockDataArray[i];
reEncodedData.set(i, blockId);
@@ -256,7 +246,7 @@ public class ChunkHider {
levelChunkPacketDataField.set(clonedPacket, clonedPacketChunkData);
return clonedPacket;
return clonedPacket;
}
@@ -265,6 +255,7 @@ public class ChunkHider {
private static final Reflection.Field<BlockEntityType> blockEntityInfoTypeField = Reflection.getField(blockEntitiyInfoClass, BlockEntityType.class, 0);
private static final Reflection.Field<Integer> packedXZField = Reflection.getField(blockEntitiyInfoClass, int.class, 0);
private static final Reflection.Field<Integer> yField = Reflection.getField(blockEntitiyInfoClass, int.class, 1);
private List<Object> filterBlockEntities(Player player, List<Object> blockEntities) {
return blockEntities.stream()
.filter((blockEntityInfo) -> {
@@ -280,33 +271,30 @@ public class ChunkHider {
}).toList();
}
private void copyOverSectionBiomeData(ByteBuf oldData, ByteBuf newData){
private void copyOverSectionBiomeData(ByteBuf oldData, ByteBuf newData) {
short bitsPerBiome = oldData.readByte();
newData.writeByte(bitsPerBiome);
if(bitsPerBiome == 0) {
if (bitsPerBiome == 0) {
int sectionBiomeId = ProtocolUtils.readVarInt(oldData);
ProtocolUtils.writeVarInt(newData, sectionBiomeId);
}
else if(bitsPerBiome <= BIT_PER_BIOME_INDIRECTION_LIMIT) {
} else if (bitsPerBiome <= BIT_PER_BIOME_INDIRECTION_LIMIT) {
int palletLength = ProtocolUtils.readVarInt(oldData);
ProtocolUtils.writeVarInt(newData, palletLength);
for(int i = 0; i < palletLength; i++) {
for (int i = 0; i < palletLength; i++) {
int palletEntry = ProtocolUtils.readVarInt(oldData);
ProtocolUtils.writeVarInt(newData, palletEntry);
}
long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION);
for(long rawDataSegment : rawData ) {
long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION);
for (long rawDataSegment : rawData) {
newData.writeLong(rawDataSegment);
}
} else {
long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION);
for (long rawDataSegment : rawData) {
newData.writeLong(rawDataSegment);
}
}
else {
long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION);
for(long rawDataSegment : rawData ) {
newData.writeLong(rawDataSegment);
}
}
}
}
@@ -143,7 +143,7 @@ public class ProtocolUtils {
public static int[] readVarIntArray(ByteBuf buffer, int length) {
int[] array = new int[length];
for(int i = 0; i < length; i++) {
for (int i = 0; i < length; i++) {
array[i] = readVarInt(buffer);
}
@@ -162,8 +162,8 @@ public class ProtocolUtils {
} while (value != 0);
}
public static void writeVarIntArray(ByteBuf buf, int[] values){
for(int varInt : values) {
public static void writeVarIntArray(ByteBuf buf, int[] values) {
for (int varInt : values) {
writeVarInt(buf, varInt);
}
}
@@ -1,34 +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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.function.BiFunction;
public class ProtocolWrapper {
public static final ProtocolWrapper impl = new ProtocolWrapper();
}
@@ -25,10 +25,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.shorts.ShortArraySet;
import it.unimi.dsi.fastutil.shorts.ShortSets;
import net.minecraft.network.protocol.game.*;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.phys.Vec3;
import org.bukkit.entity.Player;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.PacketListener;
@@ -41,13 +37,11 @@ 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.login.ClientboundCustomQueryPacket;
import net.minecraft.network.protocol.login.ClientboundHelloPacket;
import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket;
import net.minecraft.network.protocol.login.ClientboundLoginFinishedPacket;
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.entity.Player;
import java.util.*;
import java.util.function.BiFunction;
@@ -59,20 +53,21 @@ import java.util.function.ToIntFunction;
* any packet must be explicitly whitelisted or processed in a
* way that is also compliant with the principle of default-deny.
*/
public abstract class TechHider implements AccessPrivilegeProvider {
public class TechHider {
private final Set<Class<?>> bypassingPackets;
private final Map<Class<? extends Packet<? extends PacketListener>>, BiFunction<Player, Packet<? extends PacketListener>, Packet<? extends PacketListener>>> packetProcessors;
private final Block blockUsedForObfuscation;
private final BlockState blockStateUsedForObfuscation;
private final ChunkHider chunkHider;
private final AccessPrivilegeProvider privilegeProvider;
// TODO handle packet bundle
protected TechHider(Block blockUsedForObfuscation) {
this.blockUsedForObfuscation = blockUsedForObfuscation;
public TechHider(Block blockUsedForObfuscation, AccessPrivilegeProvider privilegeProvider) {
this.blockStateUsedForObfuscation = blockUsedForObfuscation.defaultBlockState();
this.chunkHider = new ChunkHider(blockUsedForObfuscation, this);
this.chunkHider = new ChunkHider(blockUsedForObfuscation, privilegeProvider);
this.privilegeProvider = privilegeProvider;
this.bypassingPackets = new HashSet<>(List.of(
// --- 5.1.x Login Protocol ---
@@ -84,8 +79,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
ClientboundCookieRequestPacket.class, // 5.1.6 Cookie Request
// --- 6.1.x Configuration Protocol ---
ClientboundSelectKnownPacks.class,
ClientboundCustomPayloadPacket.class, // 6.1.2 Clientbound Plugin Message
ClientboundSelectKnownPacks.class, ClientboundCustomPayloadPacket.class, // 6.1.2 Clientbound Plugin Message
ClientboundFinishConfigurationPacket.class, // 6.1.4 Finish Configuration
ClientboundKeepAlivePacket.class, // 6.1.5 Clientbound Keep Alive
ClientboundPingPacket.class, // 6.1.6 Ping
@@ -98,7 +92,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
ClientboundCustomReportDetailsPacket.class, // 6.1.16 Custom Report Details
ClientboundServerLinksPacket.class, // 6.1.17 Server Links
ClientboundSystemChatPacket.class, // 6.1.18/19 Dialogs are often handled via System Chat or Custom
// Payloads
// Payloads
ClientboundServerDataPacket.class, // 6.1.20 Code of Conduct is usually in Server Data
// --- 7.1.x Play Protocol ---
@@ -237,7 +231,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
// 7.1.134 Projectile Power: projectile/entity signal.
processors.put(ClientboundProjectilePowerPacket.class, this.buildEntityPacketProcessor(ClientboundProjectilePowerPacket::getId));
// 7.1.123 Pickup Item: item/entity ids and pickup activity.
processors.put(ClientboundTakeItemEntityPacket.class, this.buildEntityPacketProcessor(ClientboundTakeItemEntityPacket::getItemId));
processors.put(ClientboundTakeItemEntityPacket.class, this.buildEntityPacketProcessor(ClientboundTakeItemEntityPacket::getItemId));
// 7.1.67 Combat Death: entity/player ids and death message context.
processors.put(ClientboundPlayerCombatKillPacket.class, this.buildEntityPacketProcessor(ClientboundPlayerCombatKillPacket::playerId));
// 7.1.52/53/55 Update Entity Position/Rotation: entity id and movement signal.
@@ -305,51 +299,50 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int blockZ = (int) pos.z;
return proccessPositionBasedPacket(p, blockX, blockY, blockZ, packet);
return proccessPositionBasedPacket(p, blockX, blockY, blockZ, packet);
});
this.packetProcessors = processors;
TinyProtocol.instance.addGlobalClientboundFilter((player, rawPacket) -> {
if(rawPacket instanceof ClientboundBundlePacket bundlePacket) {
List<Packet<? super ClientGamePacketListener>> processedPackets = new ArrayList<>();
try {
if (rawPacket instanceof ClientboundBundlePacket bundlePacket) {
List<Packet<? super ClientGamePacketListener>> processedPackets = new ArrayList<>();
for(Packet<? super ClientGamePacketListener> packet : bundlePacket.subPackets()) {
Packet<? super ClientGamePacketListener> processedPacket = (Packet<? super ClientGamePacketListener>) processPacket(player, packet);
for (Packet<? super ClientGamePacketListener> packet : bundlePacket.subPackets()) {
Packet<? super ClientGamePacketListener> processedPacket = (Packet<? super ClientGamePacketListener>) processPacket(player, packet);
if(processedPacket != null) {
processedPackets.add(processedPacket);
if (processedPacket != null) {
processedPackets.add(processedPacket);
}
}
}
return new ClientboundBundlePacket(processedPackets);
}
else if(rawPacket instanceof Packet) {
return processPacket(player, (Packet<?>) rawPacket);
}
else {
return new ClientboundBundlePacket(processedPackets);
} else {
return processPacket(player, rawPacket);
}
} catch (Throwable t) {
t.printStackTrace();
return null;
}
});
TinyProtocol.instance.addFilter(ServerboundUseItemOnPacket.class, (p, packet) -> isPlayerPrivalegedToPerformAction(p) ? packet : null);
TinyProtocol.instance.addFilter(ServerboundInteractPacket.class, (p, packet) -> isPlayerPrivalegedToPerformAction(p) ? packet : null);
TinyProtocol.instance.addFilter(ServerboundUseItemOnPacket.class, (p, packet) -> privilegeProvider.isPlayerPrivilegedToPerformAction(p) ? packet : null);
TinyProtocol.instance.addFilter(ServerboundInteractPacket.class, (p, packet) -> privilegeProvider.isPlayerPrivilegedToPerformAction(p) ? packet : null);
}
private Packet<?> processPacket(Player player, Packet<?> packet) {
if(bypassingPackets.contains(packet.getClass())) {
if (bypassingPackets.contains(packet.getClass())) {
return packet;
}
else if(packetProcessors.containsKey(packet.getClass())) {
return packetProcessors.get(packet.getClass()).apply(player, (Packet<? extends PacketListener>) packet);
}
else {
} else if (packetProcessors.containsKey(packet.getClass())) {
return packetProcessors.get(packet.getClass()).apply(player, packet);
} else {
return null;
}
}
private Packet<? extends PacketListener> processAddEntityPacket(Player player, ClientboundAddEntityPacket packet) {
if(isPlayerPrivilegedToAccessEntity(player, packet.getId()) && isPlayerPrivilegedToAccessPosition(player, (int) packet.getX(), (int) packet.getY(), (int) packet.getZ())) {
if (privilegeProvider.isPlayerPrivilegedToAccessEntity(player, packet.getId()) && privilegeProvider.isPlayerPrivilegedToAccessPosition(player, (int) packet.getX(), (int) packet.getY(), (int) packet.getZ())) {
return packet;
} else {
return null;
@@ -357,13 +350,14 @@ public abstract class TechHider implements AccessPrivilegeProvider {
}
private Packet<? extends PacketListener> processEntityPacket(Player player, int entityId, Packet<? extends PacketListener> packet) {
if(isPlayerPrivilegedToAccessEntity(player, entityId)) {
if (privilegeProvider.isPlayerPrivilegedToAccessEntity(player, entityId)) {
return packet;
} else {
return null;
}
}
private <TTargetPacket extends Packet<?>> BiFunction<Player, Packet<? extends PacketListener>, Packet<? extends PacketListener>> buildEntityPacketProcessor(ToIntFunction<TTargetPacket> entityIdExtractor) {
private <TTargetPacket extends Packet<?>> BiFunction<Player, Packet<? extends PacketListener>, Packet<? extends PacketListener>> buildEntityPacketProcessor(ToIntFunction<TTargetPacket> entityIdExtractor) {
return (p, rawPacket) -> {
TTargetPacket packet = (TTargetPacket) rawPacket;
return processEntityPacket(p, entityIdExtractor.applyAsInt(packet), packet);
@@ -371,25 +365,25 @@ public abstract class TechHider implements AccessPrivilegeProvider {
}
private final Reflection.Field<Integer> moveEntityPacketEntityIdField = Reflection.getField(ClientboundMoveEntityPacket.class, int.class, 0);
private Packet<?> processMoveEntityPacket(Player player, ClientboundMoveEntityPacket packet) {
int entityId = moveEntityPacketEntityIdField.get(packet);
if(isPlayerPrivilegedToAccessEntity(player, entityId)) {
if (privilegeProvider.isPlayerPrivilegedToAccessEntity(player, entityId)) {
return packet;
}
else {
} else {
return null;
}
}
private final Reflection.Field<Integer> rotateHeadPacketEntityIdField = Reflection.getField(ClientboundRotateHeadPacket.class, int.class, 0);
private final Reflection.Field<Integer> rotateHeadPacketEntityIdField = Reflection.getField(ClientboundRotateHeadPacket.class, int.class, 0);
private Packet<?> processRotateHeadPacket(Player player, ClientboundRotateHeadPacket packet) {
int entityId = rotateHeadPacketEntityIdField.get(packet);
if(isPlayerPrivilegedToAccessEntity(player, entityId)) {
if (privilegeProvider.isPlayerPrivilegedToAccessEntity(player, entityId)) {
return packet;
}
else {
} else {
return null;
}
}
@@ -397,9 +391,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
private Packet<?> processRemoveEntitiesPacket(Player player, ClientboundRemoveEntitiesPacket packet) {
IntList entityIdsToRemove = packet.getEntityIds();
IntList filteredEntitiesToRemove = entityIdsToRemove.intStream()
.filter((id) -> isPlayerPrivilegedToAccessEntity(player, id))
.collect(IntArrayList::new, IntList::add, IntList::addAll);
IntList filteredEntitiesToRemove = entityIdsToRemove.intStream().filter((id) -> privilegeProvider.isPlayerPrivilegedToAccessEntity(player, id)).collect(IntArrayList::new, IntList::add, IntList::addAll);
return new ClientboundRemoveEntitiesPacket(filteredEntitiesToRemove);
}
@@ -408,10 +400,9 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int fromEntityId = packet.getSourceId();
int toEntityId = packet.getDestId();
if(isPlayerPrivilegedToAccessEntity(player, fromEntityId) && isPlayerPrivilegedToAccessEntity(player, toEntityId)) {
if (privilegeProvider.isPlayerPrivilegedToAccessEntity(player, fromEntityId) && privilegeProvider.isPlayerPrivilegedToAccessEntity(player, toEntityId)) {
return packet;
}
else {
} else {
return null;
}
}
@@ -423,7 +414,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int blockY = blockPos.getY();
int blockZ = blockPos.getZ();
if (isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ) && isPlayerPrivilegedToAccessBlock(player, blockX, blockY, blockZ, block)) {
if (privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ) && privilegeProvider.isPlayerPrivilegedToAccessBlock(player, blockX, blockY, blockZ, block)) {
return packet;
} else {
return null;
@@ -437,9 +428,9 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int blockY = blockPos.getY();
int blockZ = blockPos.getZ();
if (isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ) && isPlayerPrivilegedToAccessBlock(player, blockX, blockY, blockZ, block)) {
if (privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ) && privilegeProvider.isPlayerPrivilegedToAccessBlock(player, blockX, blockY, blockZ, block)) {
return packet;
} else if(isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ)) {
} else if (privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ)) {
return new ClientboundBlockUpdatePacket(blockPos, blockStateUsedForObfuscation);
} else {
return null;
@@ -453,7 +444,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int blockY = blockPos.getY();
int blockZ = blockPos.getZ();
if (isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ) && isPlayerPrivilegedToAccessBlockEntity(player, blockX, blockY, blockZ, blockEntityType)) {
if (privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ) && privilegeProvider.isPlayerPrivilegedToAccessBlockEntity(player, blockX, blockY, blockZ, blockEntityType)) {
return packet;
} else {
return null;
@@ -464,10 +455,9 @@ public abstract class TechHider implements AccessPrivilegeProvider {
BlockPos blockPos = packet.getPos();
int entityBreakingBlockId = packet.getId();
if(isPlayerPrivilegedToAccessEntity(player, entityBreakingBlockId) && isPlayerPrivilegedToAccessPosition(player, blockPos.getX(), blockPos.getY(), blockPos.getZ())) {
if (privilegeProvider.isPlayerPrivilegedToAccessEntity(player, entityBreakingBlockId) && privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockPos.getX(), blockPos.getY(), blockPos.getZ())) {
return packet;
}
else {
} else {
return null;
}
}
@@ -475,6 +465,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
private final Reflection.Field<SectionPos> sectionPosField = Reflection.getField(ClientboundSectionBlocksUpdatePacket.class, SectionPos.class, 0);
private final Reflection.Field<short[]> oldPosField = Reflection.getField(ClientboundSectionBlocksUpdatePacket.class, short[].class, 0);
private final Reflection.Field<BlockState[]> oldStatesField = Reflection.getField(ClientboundSectionBlocksUpdatePacket.class, BlockState[].class, 0);
private ClientboundSectionBlocksUpdatePacket processSectionUpdate(Player p, ClientboundSectionBlocksUpdatePacket packet) {
SectionPos sectionPos = sectionPosField.get(packet);
short[] oldPos = oldPosField.get(packet);
@@ -493,11 +484,11 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int worldY = sectionPos.relativeToBlockY(posShort);
int worldZ = sectionPos.relativeToBlockZ(posShort);
if (isPlayerPrivilegedToAccessPosition(p, worldX, worldY, worldZ) && isPlayerPrivilegedToAccessBlock(p, worldX, worldY, worldZ, block)) {
if (privilegeProvider.isPlayerPrivilegedToAccessPosition(p, worldX, worldY, worldZ) && privilegeProvider.isPlayerPrivilegedToAccessBlock(p, worldX, worldY, worldZ, block)) {
// TODO statefull !!!
filteredPos.add(posShort);
filteredStates.add(state);
} else if(isPlayerPrivilegedToAccessPosition(p, worldX, worldY, worldZ)){
} else if (privilegeProvider.isPlayerPrivilegedToAccessPosition(p, worldX, worldY, worldZ)) {
modified = true;
filteredPos.add(posShort);
filteredStates.add(blockStateUsedForObfuscation);
@@ -518,11 +509,7 @@ public abstract class TechHider implements AccessPrivilegeProvider {
BlockState[] newStates = filteredStates.toArray(new BlockState[0]);
return new ClientboundSectionBlocksUpdatePacket(
sectionPos,
ShortSets.unmodifiable(new ShortArraySet(newPos)),
newStates
);
return new ClientboundSectionBlocksUpdatePacket(sectionPos, ShortSets.unmodifiable(new ShortArraySet(newPos)), newStates);
}
private Packet<?> processLevelParticlesPacket(Player player, ClientboundLevelParticlesPacket packet) {
@@ -530,30 +517,29 @@ public abstract class TechHider implements AccessPrivilegeProvider {
int blockY = (int) packet.getY();
int blockZ = (int) packet.getZ();
if(isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ)) {
return packet;
}
else {
return null;
}
}
private ClientboundLevelChunkWithLightPacket processChunkWithLight(Player p, ClientboundLevelChunkWithLightPacket packet) {
if(isEveryonePrivilegedToAccessAllDataWithinChunk(packet.getX(), packet.getZ())) {
return packet;
}
else {
return chunkHider.processLevelChunkWithLightPacket(p, packet);
}
}
private Packet<? extends PacketListener> proccessPositionBasedPacket(Player player, int blockX, int blockY, int blockZ, Packet<? extends PacketListener> packet) {
if(isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ)) {
if (privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ)) {
return packet;
} else {
return null;
}
}
private ClientboundLevelChunkWithLightPacket processChunkWithLight(Player p, ClientboundLevelChunkWithLightPacket packet) {
if (privilegeProvider.isEveryonePrivilegedToAccessAllDataWithinChunk(packet.getX(), packet.getZ())) {
return packet;
} else {
return chunkHider.processLevelChunkWithLightPacket(p, packet);
}
}
private Packet<? extends PacketListener> proccessPositionBasedPacket(Player player, int blockX, int blockY, int blockZ, Packet<? extends PacketListener> packet) {
if (privilegeProvider.isPlayerPrivilegedToAccessPosition(player, blockX, blockY, blockZ)) {
return packet;
} else {
return null;
}
}
private <TTargetPacket extends Packet<?>> BiFunction<Player, Packet<?>, Packet<?>> buildPositionBasedPacketProcessor(Function<TTargetPacket, BlockPos> positionExtractor) {
return (p, rawPacket) -> {
TTargetPacket packet = (TTargetPacket) rawPacket;
@@ -565,12 +551,4 @@ public abstract class TechHider implements AccessPrivilegeProvider {
return proccessPositionBasedPacket(p, blockX, blockY, blockZ, packet);
};
}
public abstract boolean isPlayerPrivilegedToAccessPosition(Player p, int blockX, int blockY, int blockZ);
public abstract boolean isPlayerPrivilegedToAccessBlock(Player p, int blockX, int blockY, int blockZ, Block block);
public abstract boolean isPlayerPrivilegedToAccessEntity(Player p, int entityId);
public abstract boolean isEveryonePrivilegedToAccessAllDataWithinChunk(int chunkX, int chunkZ);
public abstract boolean isPlayerPrivilegedToAccessBlockEntity(Player p, int blockX, int blockY, int blockZ, BlockEntityType<?> type);
public abstract boolean isPlayerPrivalegedToPerformAction(Player p);
}
@@ -1,68 +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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider.legacy;
import de.steamwar.Reflection;
import net.minecraft.core.IdMapper;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import org.bukkit.Material;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import java.util.HashSet;
import java.util.Set;
public class BlockIds {
public static final BlockIds impl = new BlockIds();
public int materialToId(Material material) {
return getCombinedId(getBlock(material).defaultBlockState());
}
private static final FluidState water = Fluids.WATER.getSource(false);
private static final Iterable<BlockState> registryBlockId = (Iterable<BlockState>) Reflection.getField(TechHider.block, IdMapper.class, 0).get(null);
public Set<Integer> materialToAllIds(Material material) {
Set<Integer> ids = new HashSet<>();
for (BlockState data : getBlock(material).getStateDefinition().getPossibleStates()) {
ids.add(getCombinedId(data));
}
if (material == Material.WATER) {
for (BlockState data : registryBlockId) {
if (data.getFluidState() == water) {
ids.add(getCombinedId(data));
}
}
}
return ids;
}
private Block getBlock(Material material) {
return CraftMagicNumbers.getBlock(material);
}
public int getCombinedId(BlockState blockData) {
return Block.getId(blockData);
}
}
@@ -20,6 +20,7 @@
package de.steamwar.techhider.legacy;
import de.steamwar.Reflection;
import de.steamwar.techhider.ProtocolUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter;
@@ -39,6 +40,7 @@ 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();
@@ -1,203 +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 <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider.legacy;
import com.google.common.primitives.Bytes;
import de.steamwar.Reflection;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
public class ProtocolUtils {
private ProtocolUtils() {
}
@Deprecated
public static BiFunction<Object, UnaryOperator<Object>, Object> arrayCloneGenerator(Class<?> elementClass) {
return (array, worker) -> {
int length = Array.getLength(array);
Object result = Array.newInstance(elementClass, length);
for (int i = 0; i < length; i++) {
Array.set(result, i, worker.apply(Array.get(array, i)));
}
return result;
};
}
public static UnaryOperator<Object> shallowCloneGenerator(Class<?> clazz) {
BiConsumer<Object, Object> filler = shallowFill(clazz);
return source -> {
Object clone = Reflection.newInstance(clazz);
filler.accept(source, clone);
return clone;
};
}
public static <T> UnaryOperator<T> shallowTypedCloneGenerator(Class<T> clazz) {
BiConsumer<Object, Object> filler = shallowFill(clazz);
return source -> {
Object clone = Reflection.newInstance(clazz);
filler.accept(source, clone);
return (T) clone;
};
}
private static BiConsumer<Object, Object> shallowFill(Class<?> clazz) {
if (clazz == null) {
return (source, clone) -> {
};
}
BiConsumer<Object, Object> superFiller = shallowFill(clazz.getSuperclass());
Field[] fds = clazz.getDeclaredFields();
List<Field> fields = new ArrayList<>();
for (Field field : fds) {
if (Modifier.isStatic(field.getModifiers())) continue;
field.setAccessible(true);
fields.add(field);
}
return (source, clone) -> {
superFiller.accept(source, clone);
try {
for (Field field : fields) {
field.set(clone, field.get(source));
}
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not set field", e);
}
};
}
public static int posToChunk(int c) {
int chunk = c / 16;
if (c < 0) chunk--;
return chunk;
}
@Deprecated
public static int readVarInt(byte[] array, int startPos) {
int numRead = 0;
int result = 0;
byte read;
do {
read = array[startPos + numRead];
int value = (read & 0b01111111);
result |= (value << (7 * numRead));
numRead++;
if (numRead > 5) {
break;
}
} while ((read & 0b10000000) != 0);
return result;
}
public static int readVarInt(ByteBuf buf) {
int numRead = 0;
int result = 0;
byte read;
do {
read = buf.readByte();
int value = (read & 0b01111111);
result |= (value << (7 * numRead));
if (++numRead > 5) throw new SecurityException("VarInt too long");
} while ((read & 0b10000000) != 0);
return result;
}
public static void writeVarInt(ByteBuf buf, int value) {
do {
int temp = value & 0b01111111;
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
value >>>= 7;
if (value != 0) {
temp |= 0b10000000;
}
buf.writeByte(temp);
} while (value != 0);
}
@Deprecated
public static int readVarIntLength(byte[] array, int startPos) {
int numRead = 0;
byte read;
do {
read = array[startPos + numRead];
numRead++;
if (numRead > 5) {
break;
}
} while ((read & 0b10000000) != 0);
return numRead;
}
@Deprecated
public static byte[] writeVarInt(int value) {
List<Byte> buffer = new ArrayList<>(5);
do {
byte temp = (byte) (value & 0b01111111);
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
value >>>= 7;
if (value != 0) {
temp |= 0b10000000;
}
buffer.add(temp);
} while (value != 0);
return Bytes.toArray(buffer);
}
@Deprecated
public static class ChunkPos {
final int x;
final int z;
public ChunkPos(int x, int z) {
this.x = x;
this.z = z;
}
public final int x() {
return x;
}
public final int z() {
return z;
}
}
}
@@ -29,6 +29,7 @@ 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();
@@ -88,8 +89,4 @@ public class ProtocolWrapper {
public boolean unfilteredTileEntityDataAction(Object packet) {
return tileEntityType.get(packet) != signType;
}
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return null;
}
}
@@ -21,6 +21,8 @@ package de.steamwar.techhider.legacy;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import de.steamwar.techhider.BlockIds;
import de.steamwar.techhider.ProtocolUtils;
import lombok.Getter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
@@ -39,6 +41,7 @@ import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
@Deprecated
public class TechHider {
public static final Class<?> blockPosition = BlockPos.class;
@@ -87,7 +90,7 @@ public class TechHider {
}
public void enable() {
techhiders.forEach(TinyProtocol.instance::addFilter);
techhiders.forEach((type, playerObjectBiFunction) -> TinyProtocol.instance.addFilter((Class) type, playerObjectBiFunction));
}
public void disable() {