diff --git a/pom.xml b/pom.xml index 9ace1338..0ee28eb1 100644 --- a/pom.xml +++ b/pom.xml @@ -187,6 +187,15 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + --enable-preview + + diff --git a/src/main/java/dev/hilligans/ourcraft/Block/BlockState/NewBlockState.java b/src/main/java/dev/hilligans/ourcraft/Block/BlockState/NewBlockState.java index 4aeed7e1..faece03f 100644 --- a/src/main/java/dev/hilligans/ourcraft/Block/BlockState/NewBlockState.java +++ b/src/main/java/dev/hilligans/ourcraft/Block/BlockState/NewBlockState.java @@ -80,4 +80,13 @@ public IBlockState setBlockStateID(int val) { this.blockStateReferenceID = val; return this; } + + @Override + public String toString() { + return "NewBlockState{" + + "blockStateReferenceID=" + blockStateReferenceID + + ", blockData=" + blockData + + ", block=" + block + + '}'; + } } diff --git a/src/main/java/dev/hilligans/ourcraft/ClientMain.java b/src/main/java/dev/hilligans/ourcraft/ClientMain.java index dd8cf35e..2f67c20b 100644 --- a/src/main/java/dev/hilligans/ourcraft/ClientMain.java +++ b/src/main/java/dev/hilligans/ourcraft/ClientMain.java @@ -1,13 +1,21 @@ package dev.hilligans.ourcraft; +import dev.hilligans.ourcraft.Block.Blocks; import dev.hilligans.ourcraft.Client.Client; import dev.hilligans.ourcraft.Client.Rendering.Graphics.API.IGraphicsEngine; import dev.hilligans.ourcraft.Util.ArgumentContainer; import dev.hilligans.ourcraft.Util.Side; +import dev.hilligans.ourcraft.World.NewWorldSystem.GlobalPaletteAtomicSubChunk; +import org.lwjgl.system.MemoryUtil; +import sun.misc.Unsafe; import java.io.IOException; +import java.lang.invoke.VarHandle; +import java.lang.reflect.Field; import java.util.concurrent.locks.LockSupport; +import static java.lang.StringTemplate.STR; + public class ClientMain { public static Client client; @@ -49,6 +57,38 @@ public static void main(String[] args) throws IOException { client.startClient(); } + private static sun.misc.Unsafe getUnsafeInstance() { + java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields(); + + /* + Different runtimes use different names for the Unsafe singleton, + so we cannot use .getDeclaredField and we scan instead. For example: + + Oracle: theUnsafe + PERC : m_unsafe_instance + Android: THE_ONE + */ + for (java.lang.reflect.Field field : fields) { + if (!field.getType().equals(sun.misc.Unsafe.class)) { + continue; + } + + int modifiers = field.getModifiers(); + if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers))) { + continue; + } + + try { + field.setAccessible(true); + return (sun.misc.Unsafe)field.get(null); + } catch (Exception ignored) { + } + break; + } + + throw new UnsupportedOperationException("LWJGL requires sun.misc.Unsafe to be available."); + } + public static int getWindowX() { return client == null ? 0 : client.windowX; } diff --git a/src/main/java/dev/hilligans/ourcraft/Server/Concurrent/IAtomicSubChunk.java b/src/main/java/dev/hilligans/ourcraft/Server/Concurrent/IAtomicSubChunk.java new file mode 100644 index 00000000..13aac0ab --- /dev/null +++ b/src/main/java/dev/hilligans/ourcraft/Server/Concurrent/IAtomicSubChunk.java @@ -0,0 +1,22 @@ +package dev.hilligans.ourcraft.Server.Concurrent; + +import dev.hilligans.ourcraft.Block.BlockState.IBlockState; +import dev.hilligans.ourcraft.World.NewWorldSystem.ISubChunk; + +public interface IAtomicSubChunk extends ISubChunk { + + IBlockState setBlockStateAtomic(int x, int y, int z, IBlockState blockState); + + + /** + * Used to replace an old blockstate with a new one + * useful if you want to do say a plant growing, so you can change the blockstate without having to grab the write lock + * @param x x pos in subchunk + * @param y y pos in subchunk + * @param z z pos in subchunk + * @param expected the blockstate to replace if it still exists + * @param to the new blockstate + * @return true if the expected blockstate match and the block was set, false otherwise + */ + boolean swapBlockStateAtomic(int x, int y, int z, IBlockState expected, IBlockState to); +} diff --git a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/CubicChunk.java b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/CubicChunk.java index 95da8f1f..f009a6cf 100644 --- a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/CubicChunk.java +++ b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/CubicChunk.java @@ -64,7 +64,7 @@ public IBlockState getBlockState1(long x, long y, long z) { if(subChunks[index] == null) { return Blocks.AIR.getDefaultState1(); } - return subChunks[index].getBlockState(x & 15, y & 15, z & 15); + return subChunks[index].getBlockState((int) (x & 15), (int) (y & 15), (int) (z & 15)); } @Override @@ -80,7 +80,7 @@ public void setBlockState(long x, long y, long z, IBlockState blockState) { subChunk = new GlobalPaletteImpl(16,16); subChunks[index] = subChunk; } - subChunk.setBlockState(x & 15, y & 15, z & 15, blockState); + subChunk.setBlockState((int) (x & 15), (int) (y & 15), (int) (z & 15), blockState); } @Override diff --git a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteAtomicSubChunk.java b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteAtomicSubChunk.java new file mode 100644 index 00000000..91a2f8c1 --- /dev/null +++ b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteAtomicSubChunk.java @@ -0,0 +1,89 @@ +package dev.hilligans.ourcraft.World.NewWorldSystem; + +import dev.hilligans.ourcraft.Block.BlockState.IBlockState; +import dev.hilligans.ourcraft.Server.Concurrent.IAtomicSubChunk; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; + +public class GlobalPaletteAtomicSubChunk implements IAtomicSubChunk { + + static final VarHandle ARRAY_HANDLE = MethodHandles.arrayElementVarHandle(int[].class); + public ArrayList blockStates; + public int[] blocks = new int[16 * 16 * 16 / 4]; + + public GlobalPaletteAtomicSubChunk(ArrayList blockStates) { + this.blockStates = blockStates; + if(blockStates.size() > Short.MAX_VALUE * 2) { + throw new RuntimeException("Unable to use this subchunk impl"); + } + } + + + @Override + public int getWidth() { + return 16; + } + + @Override + public int getHeight() { + return 16; + } + + @Override + public IBlockState getBlockState(int x, int y, int z) { + return blockStates.get((blocks[getIndex(x, y, z)] >> 16 * (z & 0b11)) & 0xFFFF); + } + + @Override + public IBlockState setBlockState(int x, int y, int z, IBlockState blockState) { + int shift = 16 * (z & 0b11); + int id = blockState.getBlockStateID() << shift; + int and = 0xFFFF << shift; + int index = getIndex(x, y, z); + int v = blocks[index]; + blocks[index] = v & and | id; + return blockStates.get((v >> shift) & 0xFFFF); + } + + @Override + public IBlockState setBlockStateAtomic(int x, int y, int z, IBlockState blockState) { + int shift = 16 * (z & 0b11); + int id = blockState.getBlockStateID() << shift; + int and = 0xFFFF << shift; + int index = getIndex(x, y, z); + int v; + do { + v = (int) ARRAY_HANDLE.getVolatile(blocks, index); + } while (!ARRAY_HANDLE.weakCompareAndSet(blocks, index, v, v & and | id)); + + return blockStates.get((v >> shift) & 0xFFFF); + } + + @Override + public boolean swapBlockStateAtomic(int x, int y, int z, IBlockState expected, IBlockState to) { + int shift = 16 * (z & 0b11); + int newID = to.getBlockStateID() << shift; + int oldID = expected.getBlockStateID() << shift; + int and = 0xFFFF << shift; + int index = getIndex(x, y, z); + int v; + do { + v = (int) ARRAY_HANDLE.getVolatile(blocks, index); + if((v & and) != oldID) { + return false; + } + } while (!ARRAY_HANDLE.weakCompareAndSet(blocks, index, v, v & and | newID)); + return true; + } + + public static int getIndex(int x, int y, int z) { + return ((x * 16) + y) * 4 + (z >> 2); + } + + @Override + public boolean isEmpty() { + return false; + } +} diff --git a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteImpl.java b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteImpl.java index e584a317..be5c379e 100644 --- a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteImpl.java +++ b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/GlobalPaletteImpl.java @@ -28,12 +28,12 @@ public int getHeight() { } @Override - public IBlockState getBlockState(long x, long y, long z) { + public IBlockState getBlockState(int x, int y, int z) { if(blockStates == null) { return Blocks.AIR.getDefaultState1(); } try { - short b = blockStates[(int) ((x * width + y) * height + z)]; + short b = blockStates[((x * width + y) * height + z)]; return b == 0 ? Blocks.AIR.getDefaultState1() : Ourcraft.GAME_INSTANCE.BLOCK_STATES.get(b); } catch (Exception e) { // e.printStackTrace(); @@ -42,7 +42,7 @@ public IBlockState getBlockState(long x, long y, long z) { } @Override - public IBlockState setBlockState(long x, long y, long z, IBlockState blockState) { + public IBlockState setBlockState(int x, int y, int z, IBlockState blockState) { if(blockStates == null) { if(blockState.getBlock() != Blocks.AIR) { blockStates = new short[width * height * width]; diff --git a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/ISubChunk.java b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/ISubChunk.java index 574bce25..6cd7e02f 100644 --- a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/ISubChunk.java +++ b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/ISubChunk.java @@ -9,9 +9,9 @@ public interface ISubChunk { int getHeight(); - IBlockState getBlockState(long x, long y, long z); + IBlockState getBlockState(int x, int y, int z); - IBlockState setBlockState(long x, long y, long z, IBlockState blockState); + IBlockState setBlockState(int x, int y, int z, IBlockState blockState); boolean isEmpty(); diff --git a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/PalettedSubChunk.java b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/PalettedSubChunk.java index 5296cc98..e09a0aef 100644 --- a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/PalettedSubChunk.java +++ b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/PalettedSubChunk.java @@ -20,12 +20,12 @@ public int getHeight() { } @Override - public IBlockState getBlockState(long x, long y, long z) { + public IBlockState getBlockState(int x, int y, int z) { return null; } @Override - public IBlockState setBlockState(long x, long y, long z, IBlockState blockState) { + public IBlockState setBlockState(int x, int y, int z, IBlockState blockState) { return null; } diff --git a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/SimpleSubChunkImpl.java b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/SimpleSubChunkImpl.java index d63faf0f..b2c1cc1b 100644 --- a/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/SimpleSubChunkImpl.java +++ b/src/main/java/dev/hilligans/ourcraft/World/NewWorldSystem/SimpleSubChunkImpl.java @@ -26,7 +26,7 @@ public int getHeight() { } @Override - public IBlockState getBlockState(long x, long y, long z) { + public IBlockState getBlockState(int x, int y, int z) { if(blockStates == null) { return Blocks.AIR.getDefaultState1(); } @@ -40,7 +40,7 @@ public IBlockState getBlockState(long x, long y, long z) { } @Override - public IBlockState setBlockState(long x, long y, long z, IBlockState blockState) { + public IBlockState setBlockState(int x, int y, int z, IBlockState blockState) { if(blockStates == null) { if(blockState.getBlock() != Blocks.AIR) { blockStates = new IBlockState[width * height * width];