Skip to content

Commit

Permalink
Added atomic subchunk operations.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hilligans committed Oct 10, 2023
1 parent 8b0f072 commit 88159c0
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 11 deletions.
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 +
'}';
}
}
40 changes: 40 additions & 0 deletions src/main/java/dev/hilligans/ourcraft/ClientMain.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<IBlockState> blockStates;
public int[] blocks = new int[16 * 16 * 16 / 4];

public GlobalPaletteAtomicSubChunk(ArrayList<IBlockState> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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];
Expand Down

0 comments on commit 88159c0

Please sign in to comment.