Paper/CraftBukkit-Patches/0017-Orebfuscator.patch
md_5 fa4078a2d6 "It Compiles" - Update Spigot to Minecraft 1.7.2 proper. See below for full release notes (MUST READ).
This is a lightly tested build. You are encouraged to keep backups at all times. Please attempt to report all issues to IRC. The following features are intentionally missing from this build and will be added as soon as humanly possible.
- BungeeCord IP forwarding
- Firing of AsyncLoginEvent in offline mode
- A few custom kick / other hardcoded messages

As always this build comes with no warranty.
Thanks for your support.
~md_5
2013-12-01 17:16:56 +11:00

383 lines
16 KiB
Diff

From f6ae5fd819d9eec7c5fac9f58d43065bf344d962 Mon Sep 17 00:00:00 2001
From: md_5 <md_5@live.com.au>
Date: Thu, 16 May 2013 18:51:05 +1000
Subject: [PATCH] Orebfuscator
diff --git a/src/main/java/net/minecraft/server/EntityFallingBlock.java b/src/main/java/net/minecraft/server/EntityFallingBlock.java
index 991a765..e15840b 100644
--- a/src/main/java/net/minecraft/server/EntityFallingBlock.java
+++ b/src/main/java/net/minecraft/server/EntityFallingBlock.java
@@ -86,6 +86,7 @@ public class EntityFallingBlock extends Entity {
}
this.world.setAir(i, j, k);
+ world.spigotConfig.antiXrayInstance.updateNearbyBlocks(world, i, j, k); // Spigot
}
if (this.onGround) {
@@ -101,6 +102,7 @@ public class EntityFallingBlock extends Entity {
}
this.world.setTypeAndData(i, j, k, this.id, this.data, 3);
// CraftBukkit end
+ world.spigotConfig.antiXrayInstance.updateNearbyBlocks(world, i, j, k); // Spigot
if (this.id instanceof BlockFalling) {
((BlockFalling) this.id).a(this.world, i, j, k, this.data);
diff --git a/src/main/java/net/minecraft/server/Explosion.java b/src/main/java/net/minecraft/server/Explosion.java
index 39e5b5b..d2587c1 100644
--- a/src/main/java/net/minecraft/server/Explosion.java
+++ b/src/main/java/net/minecraft/server/Explosion.java
@@ -239,6 +239,7 @@ public class Explosion {
j = chunkposition.y;
k = chunkposition.z;
block = this.world.getType(i, j, k);
+ world.spigotConfig.antiXrayInstance.updateNearbyBlocks(world, i, j, k); // Spigot
if (flag) {
double d0 = (double) ((float) i + this.world.random.nextFloat());
double d1 = (double) ((float) j + this.world.random.nextFloat());
diff --git a/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java b/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
index 856e825..7169ec8 100644
--- a/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
+++ b/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
@@ -28,6 +28,7 @@ public class PacketPlayOutMapChunk extends Packet {
this.d = chunkmap.c;
this.c = chunkmap.b;
+ chunk.world.spigotConfig.antiXrayInstance.obfuscateSync(chunk.locX, chunk.locZ, i, chunkmap.a, chunk.world); // Spigot
try {
this.buffer = chunkmap.a;
diff --git a/src/main/java/net/minecraft/server/PacketPlayOutMapChunkBulk.java b/src/main/java/net/minecraft/server/PacketPlayOutMapChunkBulk.java
index 3eac231..c3cfdc7 100644
--- a/src/main/java/net/minecraft/server/PacketPlayOutMapChunkBulk.java
+++ b/src/main/java/net/minecraft/server/PacketPlayOutMapChunkBulk.java
@@ -26,6 +26,7 @@ public class PacketPlayOutMapChunkBulk extends Packet {
}
};
// CraftBukkit end
+ private World world; // Spigot
public PacketPlayOutMapChunkBulk() {}
@@ -44,6 +45,9 @@ public class PacketPlayOutMapChunkBulk extends Packet {
Chunk chunk = (Chunk) list.get(k);
ChunkMap chunkmap = PacketPlayOutMapChunk.a(chunk, true, '\uffff');
+ // Spigot start
+ world = chunk.world;
+ /*
if (buildBuffer.length < j + chunkmap.a.length) {
byte[] abyte = new byte[j + chunkmap.a.length];
@@ -52,6 +56,8 @@ public class PacketPlayOutMapChunkBulk extends Packet {
}
System.arraycopy(chunkmap.a, 0, buildBuffer, j, chunkmap.a.length);
+ */
+ // Spigot end
j += chunkmap.a.length;
this.a[k] = chunk.locX;
this.b[k] = chunk.locZ;
@@ -79,6 +85,22 @@ public class PacketPlayOutMapChunkBulk extends Packet {
if (this.buffer != null) {
return;
}
+ // Spigot start
+ int finalBufferSize = 0;
+ // Obfuscate all sections
+ for (int i = 0; i < a.length; i++) {
+ world.spigotConfig.antiXrayInstance.obfuscate(c[i], d[i], a[i], inflatedBuffers[i], world);
+ finalBufferSize += inflatedBuffers[i].length;
+ }
+
+ // Now it's time to efficiently copy the chunk to the build buffer
+ buildBuffer = new byte[finalBufferSize];
+ int bufferLocation = 0;
+ for (int i = 0; i < a.length; i++) {
+ System.arraycopy(inflatedBuffers[i], 0, buildBuffer, bufferLocation, inflatedBuffers[i].length);
+ bufferLocation += inflatedBuffers[i].length;
+ }
+ // Spigot end
Deflater deflater = localDeflater.get();
deflater.reset();
diff --git a/src/main/java/net/minecraft/server/PlayerInteractManager.java b/src/main/java/net/minecraft/server/PlayerInteractManager.java
index 3028404..e24d4b5 100644
--- a/src/main/java/net/minecraft/server/PlayerInteractManager.java
+++ b/src/main/java/net/minecraft/server/PlayerInteractManager.java
@@ -173,6 +173,7 @@ public class PlayerInteractManager {
this.o = i1;
}
}
+ world.spigotConfig.antiXrayInstance.updateNearbyBlocks(world, i, j, k); // Spigot
}
}
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 4a9d48b..7f8d224 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -464,6 +464,7 @@ public abstract class World implements IBlockAccess {
this.e(i, j + 1, k, block);
this.e(i, j, k - 1, block);
this.e(i, j, k + 1, block);
+ spigotConfig.antiXrayInstance.updateNearbyBlocks(this, i, j, k); // Spigot
}
public void b(int i, int j, int k, Block block, int l) {
diff --git a/src/main/java/org/spigotmc/AntiXray.java b/src/main/java/org/spigotmc/AntiXray.java
new file mode 100644
index 0000000..6413ac0
--- /dev/null
+++ b/src/main/java/org/spigotmc/AntiXray.java
@@ -0,0 +1,204 @@
+package org.spigotmc;
+
+import gnu.trove.set.TByteSet;
+import gnu.trove.set.hash.TByteHashSet;
+import net.minecraft.server.Block;
+import net.minecraft.server.World;
+
+public class AntiXray
+{
+
+ private static final CustomTimingsHandler update = new CustomTimingsHandler( "xray - update" );
+ private static final CustomTimingsHandler obfuscate = new CustomTimingsHandler( "xray - obfuscate" );
+ /*========================================================================*/
+ // Used to keep track of which blocks to obfuscate
+ private final boolean[] obfuscateBlocks = new boolean[ Short.MAX_VALUE ];
+ // Used to select a random replacement ore
+ private byte[] replacementOres;
+
+ public AntiXray(SpigotWorldConfig config)
+ {
+ // Set all listed blocks as true to be obfuscated
+ for ( int id : config.blocks )
+ {
+ obfuscateBlocks[id] = true;
+ }
+
+ // For every block
+ TByteSet blocks = new TByteHashSet();
+ for ( int i = 0; i < obfuscateBlocks.length; i++ )
+ {
+ // If we are obfuscating it
+ if ( obfuscateBlocks[i] )
+ {
+ Block block = Block.e(i);
+ // Check it exists and is not a tile entity
+ if ( block != null && !block.isTileEntity() )
+ {
+ // Add it to the set of replacement blocks
+ blocks.add( (byte) i );
+ }
+ }
+ }
+ // Bake it to a flat array of replacements
+ replacementOres = blocks.toArray();
+ }
+
+ /**
+ * Starts the timings handler, then updates all blocks within the set radius
+ * of the given coordinate, revealing them if they are hidden ores.
+ */
+ public void updateNearbyBlocks(World world, int x, int y, int z)
+ {
+ if ( world.spigotConfig.antiXray )
+ {
+ update.startTiming();
+ updateNearbyBlocks( world, x, y, z, 2, false ); // 2 is the radius, we shouldn't change it as that would make it exponentially slower
+ update.stopTiming();
+ }
+ }
+
+ /**
+ * Starts the timings handler, and then removes all non exposed ores from
+ * the chunk buffer.
+ */
+ public void obfuscateSync(int chunkX, int chunkY, int bitmask, byte[] buffer, World world)
+ {
+ if ( world.spigotConfig.antiXray )
+ {
+ obfuscate.startTiming();
+ obfuscate( chunkX, chunkY, bitmask, buffer, world );
+ obfuscate.stopTiming();
+ }
+ }
+
+ /**
+ * Removes all non exposed ores from the chunk buffer.
+ */
+ public void obfuscate(int chunkX, int chunkY, int bitmask, byte[] buffer, World world)
+ {
+ // If the world is marked as obfuscated
+ if ( world.spigotConfig.antiXray )
+ {
+ // Initial radius to search around for air
+ int initialRadius = 1;
+ // Which block in the buffer we are looking at, anywhere from 0 to 16^4
+ int index = 0;
+ // The iterator marking which random ore we should use next
+ int randomOre = 0;
+
+ // Chunk corner X and Z blocks
+ int startX = chunkX << 4;
+ int startZ = chunkY << 4;
+
+ // Chunks can have up to 16 sections
+ for ( int i = 0; i < 16; i++ )
+ {
+ // If the bitmask indicates this chunk is sent...
+ if ( ( bitmask & 1 << i ) != 0 )
+ {
+ // Work through all blocks in the chunk, y,z,x
+ for ( int y = 0; y < 16; y++ )
+ {
+ for ( int z = 0; z < 16; z++ )
+ {
+ for ( int x = 0; x < 16; x++ )
+ {
+ // For some reason we can get too far ahead of ourselves (concurrent modification on bulk chunks?) so if we do, just abort and move on
+ if ( index >= buffer.length )
+ {
+ continue;
+ }
+ // Grab the block ID in the buffer.
+ // TODO: extended IDs are not yet supported
+ int blockId = buffer[index] & 0xFF;
+ // Check if the block should be obfuscated
+ if ( obfuscateBlocks[blockId] )
+ {
+ // TODO: Don't really understand this, but if radius is not 0 and the world isn't loaded, bail out
+ if ( initialRadius != 0 && !isLoaded( world, startX + x, ( i << 4 ) + y, startZ + z, initialRadius ) )
+ {
+ continue;
+ }
+ // On the otherhand, if radius is 0, or the nearby blocks are all non air, we can obfuscate
+ if ( initialRadius == 0 || !hasTransparentBlockAdjacent( world, startX + x, ( i << 4 ) + y, startZ + z, initialRadius ) )
+ {
+ switch ( world.spigotConfig.engineMode )
+ {
+ case 1:
+ // Replace with stone
+ buffer[index] = 1;
+ break;
+ case 2:
+ // Replace with random ore.
+ if ( randomOre >= replacementOres.length )
+ {
+ randomOre = 0;
+ }
+ buffer[index] = replacementOres[randomOre++];
+ break;
+ }
+ }
+ }
+
+ index++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void updateNearbyBlocks(World world, int x, int y, int z, int radius, boolean updateSelf)
+ {
+ // If the block in question is loaded
+ if ( world.isLoaded( x, y, z ) )
+ {
+ // Get block id
+ Block block = world.getType(x, y, z);
+
+ // See if it needs update
+ if ( updateSelf && obfuscateBlocks[Block.b(block)] )
+ {
+ // Send the update
+ world.notify( x, y, z );
+ }
+
+ // Check other blocks for updates
+ if ( radius > 0 )
+ {
+ updateNearbyBlocks( world, x + 1, y, z, radius - 1, true );
+ updateNearbyBlocks( world, x - 1, y, z, radius - 1, true );
+ updateNearbyBlocks( world, x, y + 1, z, radius - 1, true );
+ updateNearbyBlocks( world, x, y - 1, z, radius - 1, true );
+ updateNearbyBlocks( world, x, y, z + 1, radius - 1, true );
+ updateNearbyBlocks( world, x, y, z - 1, radius - 1, true );
+ }
+ }
+ }
+
+ private static boolean isLoaded(World world, int x, int y, int z, int radius)
+ {
+ return world.isLoaded( x, y, z )
+ || ( radius > 0
+ && ( isLoaded( world, x + 1, y, z, radius - 1 )
+ || isLoaded( world, x - 1, y, z, radius - 1 )
+ || isLoaded( world, x, y + 1, z, radius - 1 )
+ || isLoaded( world, x, y - 1, z, radius - 1 )
+ || isLoaded( world, x, y, z + 1, radius - 1 )
+ || isLoaded( world, x, y, z - 1, radius - 1 ) ) );
+ }
+
+ private static boolean hasTransparentBlockAdjacent(World world, int x, int y, int z, int radius)
+ {
+ return !world.getType(x, y, z).r() /* isSolidBlock */
+ || ( radius > 0
+ && ( hasTransparentBlockAdjacent( world, x + 1, y, z, radius - 1 )
+ || hasTransparentBlockAdjacent( world, x - 1, y, z, radius - 1 )
+ || hasTransparentBlockAdjacent( world, x, y + 1, z, radius - 1 )
+ || hasTransparentBlockAdjacent( world, x, y - 1, z, radius - 1 )
+ || hasTransparentBlockAdjacent( world, x, y, z + 1, radius - 1 )
+ || hasTransparentBlockAdjacent( world, x, y, z - 1, radius - 1 ) ) );
+ }
+}
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 3e66d79..bab9d8f 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -1,5 +1,6 @@
package org.spigotmc;
+import java.util.Arrays;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -128,4 +129,29 @@ public class SpigotWorldConfig
viewDistance = getInt( "view-distance", Bukkit.getViewDistance() );
log( "View Distance: " + viewDistance );
}
+
+ public boolean antiXray = true;
+ public int engineMode = 1;
+ public List<Integer> blocks = Arrays.asList( new Integer[]
+ {
+ 1, 5, 14, 15, 16, 21, 48, 49, 54, 56, 73, 74, 82, 129, 130
+ } );
+ public AntiXray antiXrayInstance;
+ private void antiXray()
+ {
+ antiXray = getBoolean( "anti-xray.enabled", antiXray );
+ log( "Anti X-Ray: " + antiXray );
+
+ engineMode = getInt( "anti-xray.engine-mode", engineMode );
+ log( "\tEngine Mode: " + engineMode );
+
+ if ( SpigotConfig.version < 3 )
+ {
+ set( "anti-xray.blocks", blocks );
+ }
+ blocks = getList( "anti-xray.blocks", blocks );
+ log( "\tBlocks: " + blocks );
+
+ antiXrayInstance = new AntiXray( this );
+ }
}
--
1.8.3.2