Dieser Commit ist enthalten in:
Ursprung
a46fbbbedb
Commit
a52c03c387
@ -44,6 +44,8 @@ sourceSets {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":SpigotCore_Main")
|
implementation project(":SpigotCore_Main")
|
||||||
|
compileOnly project(":SpigotCore_8")
|
||||||
|
compileOnly project(":SpigotCore_9")
|
||||||
|
|
||||||
compileOnly files("${project.rootDir}/lib/Spigot-1.14.jar")
|
compileOnly files("${project.rootDir}/lib/Spigot-1.14.jar")
|
||||||
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
|
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
|
||||||
|
52
SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
Normale Datei
52
SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
Normale Datei
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 net.minecraft.server.v1_14_R1.*;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BlockIds14 implements BlockIds {
|
||||||
|
@Override
|
||||||
|
public int materialToId(Material material) {
|
||||||
|
return Block.getCombinedId(IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getBlockData());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Integer> materialToAllIds(Material material) {
|
||||||
|
Set<Integer> ids = new HashSet<>();
|
||||||
|
for(IBlockData data : IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getStates().a()) {
|
||||||
|
ids.add(Block.getCombinedId(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(material == Material.WATER){
|
||||||
|
Fluid water = FluidTypes.WATER.a(false);
|
||||||
|
for(IBlockData data : Block.REGISTRY_ID){
|
||||||
|
if(data.p() == water){
|
||||||
|
ids.add(Block.getCombinedId(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
}
|
141
SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java
Normale Datei
141
SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java
Normale Datei
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.LongBuffer;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ChunkHider14 extends ChunkHider9 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] dataHider(int obfuscationTarget, Set<Integer> obfuscate, byte[] data, Integer primaryBitMask) {
|
||||||
|
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while(primaryBitMask != 0){
|
||||||
|
while((primaryBitMask & 1) == 0){
|
||||||
|
primaryBitMask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.writeBytes(data, i, 2); // Block count
|
||||||
|
i += 2;
|
||||||
|
byte bitsPerBlock = data[i++];
|
||||||
|
buffer.writeByte(bitsPerBlock);
|
||||||
|
|
||||||
|
if(bitsPerBlock < 9){
|
||||||
|
int paletteLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int paletteLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, paletteLengthLength);
|
||||||
|
i += paletteLengthLength;
|
||||||
|
for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++){
|
||||||
|
int blockId = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int actPaletteLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
|
||||||
|
if(obfuscate.contains(blockId)){
|
||||||
|
buffer.writeBytes(ProtocolUtils.writeVarInt(obfuscationTarget));
|
||||||
|
}else{
|
||||||
|
buffer.writeBytes(data, i, actPaletteLength);
|
||||||
|
}
|
||||||
|
i += actPaletteLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
//We modify only the chunk palette for performance reasons
|
||||||
|
int dataArrayLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, dataArrayLength * 8 + dataArrayLengthLength);
|
||||||
|
i += dataArrayLengthLength;
|
||||||
|
i += dataArrayLength * 8;
|
||||||
|
}else{
|
||||||
|
//Full Chunk/no palette, so the chunk has to be crawled through
|
||||||
|
int dataArrayLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, dataArrayLengthLength);
|
||||||
|
i += dataArrayLengthLength;
|
||||||
|
|
||||||
|
ByteBuffer source = ByteBuffer.wrap(data, i, dataArrayLength * 8);
|
||||||
|
VariableValueArray values = new VariableValueArray(bitsPerBlock, dataArrayLength, source.asLongBuffer());
|
||||||
|
|
||||||
|
for(int pos = 0; pos < 4096; pos++){
|
||||||
|
if(obfuscate.contains(values.get(pos))){
|
||||||
|
values.set(pos, obfuscationTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(long l : values.backing)
|
||||||
|
buffer.writeLong(l);
|
||||||
|
|
||||||
|
i += dataArrayLength * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
primaryBitMask >>= 1;
|
||||||
|
}
|
||||||
|
buffer.writeBytes(data, i, data.length - i); // MC appends a 0 byte at the end if there is a full chunk, idk why
|
||||||
|
|
||||||
|
data = new byte[buffer.readableBytes()];
|
||||||
|
buffer.readBytes(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class VariableValueArray {
|
||||||
|
private final long[] backing;
|
||||||
|
private final int bitsPerValue;
|
||||||
|
private final long valueMask;
|
||||||
|
|
||||||
|
public VariableValueArray(int bitsPerEntry, int dataArrayLength, LongBuffer buffer) {
|
||||||
|
this.bitsPerValue = bitsPerEntry;
|
||||||
|
this.backing = new long[dataArrayLength];
|
||||||
|
buffer.get(backing);
|
||||||
|
this.valueMask = (1L << this.bitsPerValue) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get(int index) {
|
||||||
|
index *= bitsPerValue;
|
||||||
|
int i0 = index >> 6;
|
||||||
|
int i1 = index & 0x3f;
|
||||||
|
|
||||||
|
long value = backing[i0] >>> i1;
|
||||||
|
|
||||||
|
// The value is divided over two long values
|
||||||
|
if (i1 + bitsPerValue > 64) {
|
||||||
|
value |= backing[++i0] << 64 - i1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) (value & valueMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int index, int value) {
|
||||||
|
index *= bitsPerValue;
|
||||||
|
int i0 = index >> 6;
|
||||||
|
int i1 = index & 0x3f;
|
||||||
|
|
||||||
|
backing[i0] = this.backing[i0] & ~(this.valueMask << i1) | (value & valueMask) << i1;
|
||||||
|
int i2 = i1 + bitsPerValue;
|
||||||
|
// The value is divided over two long values
|
||||||
|
if (i2 > 64) {
|
||||||
|
i0++;
|
||||||
|
backing[i0] = backing[i0] & -(1L << i2 - 64) | value >> 64 - i1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java
Normale Datei
50
SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java
Normale Datei
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
public class ProtocolWrapper14 extends ProtocolWrapper8 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
UnaryOperator<Object> blockBreakCloner = ProtocolUtils.shallowCloneGenerator(blockBreakPacket);
|
||||||
|
Reflection.FieldAccessor<?> blockBreakPosition = Reflection.getField(blockBreakPacket, TechHider.blockPosition, 0);
|
||||||
|
Reflection.FieldAccessor<?> blockBreakBlockData = Reflection.getField(blockBreakPacket, TechHider.iBlockData, 0);
|
||||||
|
|
||||||
|
return (p, packet) -> {
|
||||||
|
Object pos = blockBreakPosition.get(packet);
|
||||||
|
if(bypass.bypass(p, ProtocolUtils.posToChunk(TechHider.blockPositionX.get(pos)), ProtocolUtils.posToChunk(TechHider.blockPositionZ.get(pos))))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if(ProtocolWrapper.impl.iBlockDataHidden(obfuscate, blockBreakBlockData.get(packet))){
|
||||||
|
packet = blockBreakCloner.apply(packet);
|
||||||
|
blockBreakBlockData.set(packet, obfuscationTarget);
|
||||||
|
}
|
||||||
|
return packet;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
52
SpigotCore_15/src/de/steamwar/techhider/BlockIds15.java
Normale Datei
52
SpigotCore_15/src/de/steamwar/techhider/BlockIds15.java
Normale Datei
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 net.minecraft.server.v1_15_R1.*;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BlockIds15 implements BlockIds {
|
||||||
|
@Override
|
||||||
|
public int materialToId(Material material) {
|
||||||
|
return Block.getCombinedId(IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getBlockData());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Integer> materialToAllIds(Material material) {
|
||||||
|
Set<Integer> ids = new HashSet<>();
|
||||||
|
for(IBlockData data : IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getStates().a()) {
|
||||||
|
ids.add(Block.getCombinedId(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(material == Material.WATER){
|
||||||
|
Fluid water = FluidTypes.WATER.a(false);
|
||||||
|
for(IBlockData data : Block.REGISTRY_ID){
|
||||||
|
if(data.getFluid() == water){
|
||||||
|
ids.add(Block.getCombinedId(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
}
|
@ -49,5 +49,8 @@ dependencies {
|
|||||||
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
|
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
|
||||||
|
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT'
|
||||||
|
compileOnly 'com.mojang:datafixerupper:4.0.26'
|
||||||
|
compileOnly 'io.netty:netty-all:4.1.68.Final'
|
||||||
|
compileOnly 'com.mojang:authlib:1.5.25'
|
||||||
compileOnly files("${project.rootDir}/lib/Spigot-1.18.jar")
|
compileOnly files("${project.rootDir}/lib/Spigot-1.18.jar")
|
||||||
}
|
}
|
||||||
|
57
SpigotCore_18/src/de/steamwar/techhider/BlockIds18.java
Normale Datei
57
SpigotCore_18/src/de/steamwar/techhider/BlockIds18.java
Normale Datei
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 net.minecraft.core.IRegistry;
|
||||||
|
import net.minecraft.resources.MinecraftKey;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.IBlockData;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidTypes;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BlockIds18 implements BlockIds {
|
||||||
|
@Override
|
||||||
|
public int materialToId(Material material) {
|
||||||
|
return Block.i(IRegistry.U.a(new MinecraftKey(material.name().toLowerCase())).n());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Integer> materialToAllIds(Material material) {
|
||||||
|
Set<Integer> ids = new HashSet<>();
|
||||||
|
for(IBlockData data : IRegistry.U.a(new MinecraftKey(material.name().toLowerCase())).m().a()){
|
||||||
|
ids.add(Block.i(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(material == Material.WATER){
|
||||||
|
Fluid water = FluidTypes.c.h();
|
||||||
|
for(IBlockData data : Block.o) {
|
||||||
|
if(data.o() == water) {
|
||||||
|
ids.add(Block.i(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
}
|
154
SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java
Normale Datei
154
SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java
Normale Datei
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
import net.minecraft.core.IRegistry;
|
||||||
|
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.TileEntityTypes;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ChunkHider18 implements ChunkHider {
|
||||||
|
@Override
|
||||||
|
public Class<?> mapChunkPacket() {
|
||||||
|
return ClientboundLevelChunkWithLightPacket.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final UnaryOperator<Object> chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class);
|
||||||
|
private static final UnaryOperator<Object> chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class);
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<Integer> chunkX = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<Integer> chunkZ = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1);
|
||||||
|
private static final Reflection.FieldAccessor<ClientboundLevelChunkPacketData> chunkData = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class, 0);
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<byte[]> dataField = Reflection.getField(ClientboundLevelChunkPacketData.class, byte[].class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<List> tileEntities = Reflection.getField(ClientboundLevelChunkPacketData.class, List.class, 0);
|
||||||
|
public static final Class<?> tileEntity = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$a");
|
||||||
|
protected static final Reflection.FieldAccessor<TileEntityTypes> entityType = Reflection.getField(tileEntity, TileEntityTypes.class, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set<Integer> obfuscate, Set<String> hiddenBlockEntities) {
|
||||||
|
return (p, packet) -> {
|
||||||
|
if(bypass.bypass(p, chunkX.get(packet), chunkZ.get(packet)))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
packet = chunkPacketCloner.apply(packet);
|
||||||
|
Object data = chunkDataCloner.apply(chunkData.get(packet));
|
||||||
|
|
||||||
|
tileEntities.set(data, ((List<?>)tileEntities.get(data)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList()));
|
||||||
|
|
||||||
|
World world = p.getWorld();
|
||||||
|
int sections = (world.getMaxHeight() - world.getMinHeight()) / 16;
|
||||||
|
dataField.set(data, dataHider(obfuscationTarget, obfuscate, dataField.get(data), sections));
|
||||||
|
|
||||||
|
chunkData.set(packet, data);
|
||||||
|
return packet;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
|
||||||
|
return !hiddenBlockEntities.contains(IRegistry.aa.b(entityType.get(tile)).a());
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] dataHider(int obfuscationTarget, Set<Integer> obfuscate, byte[] data, int sections) {
|
||||||
|
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while(sections-- > 0) {
|
||||||
|
buffer.writeBytes(data, i, 2); // Block count
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
i = containerWalker(data, buffer, i, 15, blockId -> obfuscate.contains(blockId) ? obfuscationTarget : blockId, (curI, dataArrayLength, bitsPerBlock) -> {
|
||||||
|
if(bitsPerBlock < 15) {
|
||||||
|
buffer.writeBytes(data, curI, dataArrayLength * 8);
|
||||||
|
} else {
|
||||||
|
ByteBuffer source = ByteBuffer.wrap(data, curI, dataArrayLength * 8);
|
||||||
|
long[] array = new long[dataArrayLength];
|
||||||
|
source.asLongBuffer().get(array);
|
||||||
|
SimpleBitStorage values = new SimpleBitStorage(bitsPerBlock, 4096, array);
|
||||||
|
|
||||||
|
for (int pos = 0; pos < 4096; pos++) {
|
||||||
|
if (obfuscate.contains(values.a(pos))) {
|
||||||
|
values.b(pos, obfuscationTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (long l : values.a())
|
||||||
|
buffer.writeLong(l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
i = containerWalker(data, buffer, i, 6, value -> value, (curI, dataArrayLength, bitsPerBlock) -> buffer.writeBytes(data, curI, dataArrayLength * 8));
|
||||||
|
}
|
||||||
|
buffer.writeBytes(data, i, data.length - i); // MC appends a 0 byte at the end if there is a full chunk, idk why
|
||||||
|
|
||||||
|
byte[] outdata = new byte[buffer.readableBytes()];
|
||||||
|
buffer.readBytes(outdata);
|
||||||
|
return outdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int containerWalker(byte[] data, ByteBuf buffer, int i, int globalPalette, IntFunction<Integer> palette, TriConsumer<Integer, Integer, Byte> dataArray) {
|
||||||
|
byte bitsPerBlock = data[i++];
|
||||||
|
buffer.writeByte(bitsPerBlock);
|
||||||
|
|
||||||
|
if(bitsPerBlock == 0) {
|
||||||
|
int paletteValue = ProtocolUtils.readVarInt(data, i);
|
||||||
|
i += ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(ProtocolUtils.writeVarInt(palette.apply(paletteValue)));
|
||||||
|
}else if(bitsPerBlock < globalPalette) {
|
||||||
|
int paletteLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int paletteLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, paletteLengthLength);
|
||||||
|
i += paletteLengthLength;
|
||||||
|
|
||||||
|
for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++) {
|
||||||
|
int paletteValue = ProtocolUtils.readVarInt(data, i);
|
||||||
|
i += ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(ProtocolUtils.writeVarInt(palette.apply(paletteValue)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataArrayLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, dataArrayLengthLength);
|
||||||
|
i += dataArrayLengthLength;
|
||||||
|
|
||||||
|
dataArray.accept(i, dataArrayLength, bitsPerBlock);
|
||||||
|
i += dataArrayLength * 8;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface TriConsumer<X, Y, Z> {
|
||||||
|
void accept(X x, Y y, Z z);
|
||||||
|
}
|
||||||
|
}
|
77
SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java
Normale Datei
77
SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java
Normale Datei
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import net.minecraft.core.IRegistry;
|
||||||
|
import net.minecraft.core.SectionPosition;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutBlockBreak;
|
||||||
|
import net.minecraft.world.level.block.entity.TileEntityTypes;
|
||||||
|
import net.minecraft.world.level.block.state.IBlockData;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
public class ProtocolWrapper18 implements ProtocolWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<SectionPosition> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPosition.class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<IBlockData[]> multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, IBlockData[].class, 0);
|
||||||
|
private static final BiFunction<Object, UnaryOperator<Object>, Object> iBlockDataArrayCloner = ProtocolUtils.arrayCloneGenerator(TechHider.iBlockData);
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
return (p, packet) -> {
|
||||||
|
Object chunkCoords = multiBlockChangeChunk.get(packet);
|
||||||
|
if(bypass.bypass(p, TechHider.blockPositionX.get(chunkCoords), TechHider.blockPositionZ.get(chunkCoords)))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
packet = TechHider.multiBlockChangeCloner.apply(packet);
|
||||||
|
multiBlockChangeBlocks.set(packet, iBlockDataArrayCloner.apply(multiBlockChangeBlocks.get(packet), block -> ProtocolWrapper.impl.iBlockDataHidden(obfuscate, block) ? obfuscationTarget : block));
|
||||||
|
return packet;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<TileEntityTypes> tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, TileEntityTypes.class, 0);
|
||||||
|
@Override
|
||||||
|
public boolean unfilteredTileEntityDataAction(Object packet) {
|
||||||
|
return tileEntityType.get(packet) != TileEntityTypes.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
return (p, packet) -> {
|
||||||
|
PacketPlayOutBlockBreak breakPacket = (PacketPlayOutBlockBreak) packet;
|
||||||
|
if(bypass.bypass(p, ProtocolUtils.posToChunk(TechHider.blockPositionX.get(breakPacket.b())), ProtocolUtils.posToChunk(TechHider.blockPositionZ.get(breakPacket.b()))))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if(!ProtocolWrapper.impl.iBlockDataHidden(obfuscate, breakPacket.c()))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) obfuscationTarget, breakPacket.d(), breakPacket.a());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean iBlockDataHidden(Set<Material> obfuscate, Object iBlockData) {
|
||||||
|
return obfuscate.contains(Material.getMaterial(IRegistry.U.b(((IBlockData) iBlockData).b()).a().toUpperCase()));
|
||||||
|
}
|
||||||
|
}
|
@ -45,10 +45,12 @@ sourceSets {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":SpigotCore_Main")
|
implementation project(":SpigotCore_Main")
|
||||||
implementation project(":SpigotCore_14")
|
implementation project(":SpigotCore_14")
|
||||||
|
compileOnly project(":SpigotCore_18")
|
||||||
|
|
||||||
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
|
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
|
||||||
|
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
|
||||||
compileOnly 'com.mojang:brigadier:1.0.18'
|
compileOnly 'com.mojang:brigadier:1.0.18'
|
||||||
|
compileOnly 'com.mojang:datafixerupper:4.0.26'
|
||||||
compileOnly files("${project.rootDir}/lib/Spigot-1.19.jar")
|
compileOnly files("${project.rootDir}/lib/Spigot-1.19.jar")
|
||||||
}
|
}
|
||||||
|
57
SpigotCore_19/src/de/steamwar/techhider/BlockIds19.java
Normale Datei
57
SpigotCore_19/src/de/steamwar/techhider/BlockIds19.java
Normale Datei
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 net.minecraft.core.IRegistry;
|
||||||
|
import net.minecraft.resources.MinecraftKey;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.IBlockData;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidTypes;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BlockIds19 implements BlockIds {
|
||||||
|
@Override
|
||||||
|
public int materialToId(Material material) {
|
||||||
|
return Block.i(IRegistry.V.a(new MinecraftKey(material.name().toLowerCase())).m());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Integer> materialToAllIds(Material material) {
|
||||||
|
Set<Integer> ids = new HashSet<>();
|
||||||
|
for(IBlockData data : IRegistry.V.a(new MinecraftKey(material.name().toLowerCase())).k().a()){
|
||||||
|
ids.add(Block.i(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(material == Material.WATER){
|
||||||
|
Fluid water = FluidTypes.c.h();
|
||||||
|
for(IBlockData data : Block.o) {
|
||||||
|
if(data.p() == water) {
|
||||||
|
ids.add(Block.i(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
}
|
31
SpigotCore_19/src/de/steamwar/techhider/ChunkHider19.java
Normale Datei
31
SpigotCore_19/src/de/steamwar/techhider/ChunkHider19.java
Normale Datei
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 net.minecraft.core.IRegistry;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ChunkHider19 extends ChunkHider18 {
|
||||||
|
@Override
|
||||||
|
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
|
||||||
|
return !hiddenBlockEntities.contains(IRegistry.ab.b(entityType.get(tile)).a());
|
||||||
|
}
|
||||||
|
}
|
67
SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java
Normale Datei
67
SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java
Normale Datei
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import net.minecraft.core.IRegistry;
|
||||||
|
import net.minecraft.core.SectionPosition;
|
||||||
|
import net.minecraft.world.level.block.entity.TileEntityTypes;
|
||||||
|
import net.minecraft.world.level.block.state.IBlockData;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
public class ProtocolWrapper19 implements ProtocolWrapper {
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<SectionPosition> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPosition.class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<IBlockData[]> multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, IBlockData[].class, 0);
|
||||||
|
private static final BiFunction<Object, UnaryOperator<Object>, Object> iBlockDataArrayCloner = ProtocolUtils.arrayCloneGenerator(TechHider.iBlockData);
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
return (p, packet) -> {
|
||||||
|
Object chunkCoords = multiBlockChangeChunk.get(packet);
|
||||||
|
if(bypass.bypass(p, TechHider.blockPositionX.get(chunkCoords), TechHider.blockPositionZ.get(chunkCoords)))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
packet = TechHider.multiBlockChangeCloner.apply(packet);
|
||||||
|
multiBlockChangeBlocks.set(packet, iBlockDataArrayCloner.apply(multiBlockChangeBlocks.get(packet), block -> ProtocolWrapper.impl.iBlockDataHidden(obfuscate, block) ? obfuscationTarget : block));
|
||||||
|
return packet;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<TileEntityTypes> tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, TileEntityTypes.class, 0);
|
||||||
|
@Override
|
||||||
|
public boolean unfilteredTileEntityDataAction(Object packet) {
|
||||||
|
return tileEntityType.get(packet) != TileEntityTypes.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean iBlockDataHidden(Set<Material> obfuscate, Object iBlockData) {
|
||||||
|
return obfuscate.contains(Material.getMaterial(IRegistry.V.b(((IBlockData) iBlockData).b()).a().toUpperCase()));
|
||||||
|
}
|
||||||
|
}
|
38
SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
Normale Datei
38
SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
Normale Datei
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BlockIds8 implements BlockIds {
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public int materialToId(Material material) {
|
||||||
|
return material.getId() << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Integer> materialToAllIds(Material material) {
|
||||||
|
return Collections.singleton(materialToId(material));
|
||||||
|
}
|
||||||
|
}
|
40
SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java
Normale Datei
40
SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java
Normale Datei
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public class ChunkHider8 implements ChunkHider {
|
||||||
|
|
||||||
|
protected static final Class<?> mapChunkPacket = Reflection.getClass("{nms}.PacketPlayOutMapChunk");
|
||||||
|
@Override
|
||||||
|
public Class<?> mapChunkPacket() {
|
||||||
|
return mapChunkPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set<Integer> obfuscate, Set<String> hiddenBlockEntities) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
76
SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java
Normale Datei
76
SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java
Normale Datei
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
public class ProtocolWrapper8 implements ProtocolWrapper {
|
||||||
|
private static final Class<?> chunkCoordinateIntPair = Reflection.getClass("{nms}.ChunkCoordIntPair");
|
||||||
|
private static final Reflection.FieldAccessor<?> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, chunkCoordinateIntPair, 0);
|
||||||
|
private static final Reflection.FieldAccessor<Integer> chunkCoordinateX = Reflection.getField(chunkCoordinateIntPair, int.class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<Integer> chunkCoordinateZ = Reflection.getField(chunkCoordinateIntPair, int.class, 1);
|
||||||
|
private static final Class<?> multiBlockChangeInfo = Reflection.getClass("{nms}.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo");
|
||||||
|
private static final Reflection.ConstructorInvoker multiBlockChangeInfoConstructor = Reflection.getConstructor(multiBlockChangeInfo, TechHider.multiBlockChangePacket, short.class, TechHider.iBlockData);
|
||||||
|
private static final BiFunction<Object, UnaryOperator<Object>, Object> multiBlockChangeInfoArrayCloner = ProtocolUtils.arrayCloneGenerator(multiBlockChangeInfo);
|
||||||
|
private static final Reflection.FieldAccessor<?> multiBlockChangeInfoBlock = Reflection.getField(multiBlockChangeInfo, TechHider.iBlockData, 0);
|
||||||
|
private static final Reflection.FieldAccessor<?> multiBlockChangeInfoPos = Reflection.getField(multiBlockChangeInfo, short.class, 0);
|
||||||
|
private static final Class<?> multiBlockChangeInfoArray = Reflection.getClass("[L{nms}.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo;");
|
||||||
|
private static final Reflection.FieldAccessor<?> multiBlockChangeInfos = Reflection.getField(TechHider.multiBlockChangePacket, multiBlockChangeInfoArray, 0);
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
return (p, packet) -> {
|
||||||
|
Object chunkCoords = multiBlockChangeChunk.get(packet);
|
||||||
|
if(bypass.bypass(p, chunkCoordinateX.get(chunkCoords), chunkCoordinateZ.get(chunkCoords)))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
Object modpacket = TechHider.multiBlockChangeCloner.apply(packet);
|
||||||
|
multiBlockChangeInfos.set(modpacket, multiBlockChangeInfoArrayCloner.apply(multiBlockChangeInfos.get(modpacket), mbci -> {
|
||||||
|
if(ProtocolWrapper.impl.iBlockDataHidden(obfuscate, multiBlockChangeInfoBlock.get(mbci)))
|
||||||
|
return multiBlockChangeInfoConstructor.invoke(modpacket, multiBlockChangeInfoPos.get(mbci), obfuscationTarget);
|
||||||
|
return mbci;
|
||||||
|
}));
|
||||||
|
return modpacket;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<Integer> tileEntityDataAction = Reflection.getField(TechHider.tileEntityDataPacket, int.class, 0);
|
||||||
|
@Override
|
||||||
|
public boolean unfilteredTileEntityDataAction(Object packet) {
|
||||||
|
return tileEntityDataAction.get(packet) != 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.MethodInvoker getBlockByBlockData = Reflection.getTypedMethod(TechHider.iBlockData, null, TechHider.block);
|
||||||
|
private static final Reflection.MethodInvoker getMaterialByBlock = Reflection.getTypedMethod(TechHider.craftMagicNumbers, "getMaterial", Material.class, TechHider.block);
|
||||||
|
@Override
|
||||||
|
public boolean iBlockDataHidden(Set<Material> obfuscate, Object iBlockData) {
|
||||||
|
return obfuscate.contains((Material) getMaterialByBlock.invoke(null, getBlockByBlockData.invoke(iBlockData)));
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,7 @@ sourceSets {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":SpigotCore_Main")
|
implementation project(":SpigotCore_Main")
|
||||||
|
compileOnly project(":SpigotCore_8")
|
||||||
|
|
||||||
compileOnly files("${project.rootDir}/lib/Spigot-1.9.jar")
|
compileOnly files("${project.rootDir}/lib/Spigot-1.9.jar")
|
||||||
}
|
}
|
||||||
|
108
SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java
Normale Datei
108
SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java
Normale Datei
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ChunkHider9 extends ChunkHider8 {
|
||||||
|
|
||||||
|
private static final UnaryOperator<Object> mapChunkCloner = ProtocolUtils.shallowCloneGenerator(mapChunkPacket);
|
||||||
|
|
||||||
|
private static final Reflection.FieldAccessor<Integer> mapChunkX = Reflection.getField(mapChunkPacket, int.class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<Integer> mapChunkZ = Reflection.getField(mapChunkPacket, int.class, 1);
|
||||||
|
private static final Reflection.FieldAccessor<Integer> mapChunkBitMask = Reflection.getField(mapChunkPacket, int.class, 2);
|
||||||
|
private static final Reflection.FieldAccessor<List> mapChunkBlockEntities = Reflection.getField(mapChunkPacket, List.class, 0);
|
||||||
|
private static final Reflection.FieldAccessor<byte[]> mapChunkData = Reflection.getField(mapChunkPacket, byte[].class, 0);
|
||||||
|
|
||||||
|
private static final Class<?> nbtTagCompound = Reflection.getClass("{nms.nbt}.NBTTagCompound");
|
||||||
|
private static final Reflection.MethodInvoker nbtTagGetString = Reflection.getTypedMethod(nbtTagCompound, null, String.class, String.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set<Integer> obfuscate, Set<String> hiddenBlockEntities) {
|
||||||
|
return (p, packet) -> {
|
||||||
|
if(bypass.bypass(p, mapChunkX.get(packet), mapChunkZ.get(packet)))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
packet = mapChunkCloner.apply(packet);
|
||||||
|
mapChunkBlockEntities.set(packet, ((List<?>)mapChunkBlockEntities.get(packet)).stream().filter(
|
||||||
|
nbttag -> !hiddenBlockEntities.contains((String) nbtTagGetString.invoke(nbttag, "id"))
|
||||||
|
).collect(Collectors.toList()));
|
||||||
|
|
||||||
|
byte[] data = dataHider(obfuscationTarget, obfuscate, mapChunkData.get(packet), mapChunkBitMask.get(packet));
|
||||||
|
mapChunkData.set(packet, data);
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] dataHider(int obfuscationTarget, Set<Integer> obfuscate, byte[] data, Integer primaryBitMask) {
|
||||||
|
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while(i < data.length){
|
||||||
|
byte bitsPerBlock = data[i++];
|
||||||
|
buffer.writeByte(bitsPerBlock);
|
||||||
|
|
||||||
|
if(bitsPerBlock != 13){
|
||||||
|
int paletteLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int paletteLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, paletteLengthLength);
|
||||||
|
i += paletteLengthLength;
|
||||||
|
|
||||||
|
for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++){
|
||||||
|
int entry = ProtocolUtils.readVarInt(data, i);
|
||||||
|
i += ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
|
||||||
|
if(obfuscate.contains(entry)){
|
||||||
|
entry = obfuscationTarget;
|
||||||
|
}
|
||||||
|
buffer.writeBytes(ProtocolUtils.writeVarInt(entry));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
buffer.writeByte(data[++i]); //Empty palette
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "Full chunk occured");
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataArrayLength = ProtocolUtils.readVarInt(data, i);
|
||||||
|
int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i);
|
||||||
|
buffer.writeBytes(data, i, dataArrayLength*8 + dataArrayLengthLength);
|
||||||
|
i += dataArrayLengthLength;
|
||||||
|
i += dataArrayLength * 8;
|
||||||
|
|
||||||
|
buffer.writeBytes(data, i, 4096);
|
||||||
|
i += 4096; //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048
|
||||||
|
}
|
||||||
|
|
||||||
|
data = new byte[buffer.readableBytes()];
|
||||||
|
buffer.readBytes(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
33
SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
Normale Datei
33
SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
Normale Datei
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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.core.Core;
|
||||||
|
import de.steamwar.core.VersionDependent;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface BlockIds {
|
||||||
|
BlockIds impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||||
|
|
||||||
|
int materialToId(Material material);
|
||||||
|
Set<Integer> materialToAllIds(Material material);
|
||||||
|
}
|
34
SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java
Normale Datei
34
SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java
Normale Datei
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2022 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.core.Core;
|
||||||
|
import de.steamwar.core.VersionDependent;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public interface ChunkHider {
|
||||||
|
ChunkHider impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||||
|
|
||||||
|
Class<?> mapChunkPacket();
|
||||||
|
BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set<Integer> obfuscate, Set<String> hiddenBlockEntities);
|
||||||
|
}
|
164
SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java
Normale Datei
164
SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java
Normale Datei
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2022 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
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() {}
|
||||||
|
|
||||||
|
public static void broadcastPacket(Object packet) {
|
||||||
|
Bukkit.getOnlinePlayers().stream().map(TinyProtocol.instance::getChannel).filter(TinyProtocol.instance::hasInjected).forEach(channel -> TinyProtocol.instance.sendPacket(channel, packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java
Normale Datei
41
SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java
Normale Datei
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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.core.Core;
|
||||||
|
import de.steamwar.core.VersionDependent;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public interface ProtocolWrapper {
|
||||||
|
ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||||
|
|
||||||
|
|
||||||
|
boolean unfilteredTileEntityDataAction(Object packet);
|
||||||
|
|
||||||
|
BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass);
|
||||||
|
|
||||||
|
BiFunction<Player, Object, Object> multiBlockChangeGenerator(Object obfuscationTarget, Set<Material> obfuscate, TechHider.BypassEvaluator bypass);
|
||||||
|
|
||||||
|
boolean iBlockDataHidden(Set<Material> obfuscate, Object iBlockData);
|
||||||
|
}
|
128
SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
Normale Datei
128
SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
Normale Datei
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
This file is a part of the SteamWar software.
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class TechHider {
|
||||||
|
|
||||||
|
public static final Class<?> blockPosition = Reflection.getClass("{nms.core}.BlockPosition");
|
||||||
|
private static final Class<?> baseBlockPosition = Reflection.getClass("{nms.core}.BaseBlockPosition");
|
||||||
|
public static final Reflection.FieldAccessor<Integer> blockPositionX = Reflection.getField(baseBlockPosition, int.class, 0);
|
||||||
|
public static final Reflection.FieldAccessor<Integer> blockPositionZ = Reflection.getField(baseBlockPosition, int.class, 2);
|
||||||
|
|
||||||
|
public static final Class<?> iBlockData = Reflection.getClass("{nms.world.level.block.state}.IBlockData");
|
||||||
|
public static final Class<?> block = Reflection.getClass("{nms.world.level.block}.Block");
|
||||||
|
private static final Reflection.MethodInvoker getBlockDataByBlock = Reflection.getTypedMethod(block, null, iBlockData);
|
||||||
|
|
||||||
|
public static final Class<?> craftMagicNumbers = Reflection.getClass("{obc}.util.CraftMagicNumbers");
|
||||||
|
private static final Reflection.MethodInvoker getBlockByMaterial = Reflection.getTypedMethod(craftMagicNumbers, "getBlock", block, Material.class);
|
||||||
|
|
||||||
|
private final Map<Class<?>, BiFunction<Player, Object, Object>> techhiders = new HashMap<>();
|
||||||
|
private final BypassEvaluator bypass;
|
||||||
|
private final Object obfuscationTarget;
|
||||||
|
private final Set<Material> obfuscate;
|
||||||
|
|
||||||
|
public TechHider(BypassEvaluator bypass, Material obfuscationTarget, Set<Material> obfuscate, Set<String> hiddenBlockEntities) {
|
||||||
|
this.bypass = bypass;
|
||||||
|
this.obfuscate = obfuscate;
|
||||||
|
this.obfuscationTarget = getBlockDataByBlock.invoke(getBlockByMaterial.invoke(null, obfuscationTarget));
|
||||||
|
|
||||||
|
techhiders.put(blockActionPacket, this::blockActionHider);
|
||||||
|
techhiders.put(blockChangePacket, this::blockChangeHider);
|
||||||
|
techhiders.put(tileEntityDataPacket, this::tileEntityDataHider);
|
||||||
|
techhiders.put(multiBlockChangePacket,ProtocolWrapper.impl.multiBlockChangeGenerator(obfuscationTarget, obfuscate, bypass));
|
||||||
|
techhiders.put(ChunkHider.impl.mapChunkPacket(), ChunkHider.impl.chunkHiderGenerator(bypass, BlockIds.impl.materialToId(obfuscationTarget), obfuscate.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet()), hiddenBlockEntities));
|
||||||
|
|
||||||
|
if(Core.getVersion() > 12 && Core.getVersion() < 19) {
|
||||||
|
Class<?> blockBreakClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockBreak");
|
||||||
|
techhiders.put(blockBreakClass, ProtocolWrapper.impl.blockBreakHiderGenerator(blockBreakClass, obfuscationTarget, obfuscate, bypass));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Core.getVersion() > 8){
|
||||||
|
techhiders.put(Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseItem"), (p, packet) -> p.getGameMode() == GameMode.SPECTATOR ? null : packet);
|
||||||
|
}
|
||||||
|
techhiders.put(Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseEntity"), (p, packet) -> p.getGameMode() == GameMode.SPECTATOR ? null : packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable() {
|
||||||
|
techhiders.forEach(TinyProtocol.instance::addFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable() {
|
||||||
|
techhiders.forEach(TinyProtocol.instance::removeFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Class<?> multiBlockChangePacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutMultiBlockChange");
|
||||||
|
public static final UnaryOperator<Object> multiBlockChangeCloner = ProtocolUtils.shallowCloneGenerator(TechHider.multiBlockChangePacket);
|
||||||
|
|
||||||
|
private static final Class<?> blockChangePacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockChange");
|
||||||
|
private static final Function<Object, Object> blockChangeCloner = ProtocolUtils.shallowCloneGenerator(blockChangePacket);
|
||||||
|
private static final Reflection.FieldAccessor<?> blockChangePosition = Reflection.getField(blockChangePacket, blockPosition, 0);
|
||||||
|
private static final Reflection.FieldAccessor<?> blockChangeBlockData = Reflection.getField(blockChangePacket, iBlockData, 0);
|
||||||
|
private Object blockChangeHider(Player p, Object packet) {
|
||||||
|
Object pos = blockChangePosition.get(packet);
|
||||||
|
if(bypass.bypass(p, ProtocolUtils.posToChunk(blockPositionX.get(pos)), ProtocolUtils.posToChunk(blockPositionZ.get(pos))))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if(ProtocolWrapper.impl.iBlockDataHidden(obfuscate, blockChangeBlockData.get(packet))) {
|
||||||
|
packet = blockChangeCloner.apply(packet);
|
||||||
|
blockChangeBlockData.set(packet, obfuscationTarget);
|
||||||
|
}
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Class<?> blockActionPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockAction");
|
||||||
|
private static final Reflection.FieldAccessor<?> blockActionPosition = Reflection.getField(blockActionPacket, blockPosition, 0);
|
||||||
|
private Object blockActionHider(Player p, Object packet) {
|
||||||
|
Object pos = blockActionPosition.get(packet);
|
||||||
|
if(bypass.bypass(p, ProtocolUtils.posToChunk(blockPositionX.get(pos)), ProtocolUtils.posToChunk(blockPositionZ.get(pos))))
|
||||||
|
return packet;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Class<?> tileEntityDataPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutTileEntityData");
|
||||||
|
private static final Reflection.FieldAccessor<?> tileEntityDataPosition = Reflection.getField(tileEntityDataPacket, blockPosition, 0);
|
||||||
|
private Object tileEntityDataHider(Player p, Object packet) {
|
||||||
|
Object pos = tileEntityDataPosition.get(packet);
|
||||||
|
if(bypass.bypass(p, ProtocolUtils.posToChunk(blockPositionX.get(pos)), ProtocolUtils.posToChunk(blockPositionZ.get(pos))))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if(ProtocolWrapper.impl.unfilteredTileEntityDataAction(packet))
|
||||||
|
return packet;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface BypassEvaluator {
|
||||||
|
boolean bypass(Player p, int chunkX, int chunkZ);
|
||||||
|
}
|
||||||
|
}
|
In neuem Issue referenzieren
Einen Benutzer sperren