Skip to content

Commit

Permalink
feat: reduce memory footprint of proximity block data
Browse files Browse the repository at this point in the history
  • Loading branch information
Ingrim4 committed Feb 25, 2024
1 parent c0d308b commit 37cd25b
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ public static BlockPos fromLong(long value) {
return new BlockPos(x, y, z);
}

public int toSectionPos() {
return (this.x & 0xF) << 12 | (this.y & 0xFFF) << 0 | (this.z & 0xF) << 16;
}

public static BlockPos fromSectionPos(int x, int z, int sectionPos) {
x += (sectionPos >> 12) & 0xF;
int y = (sectionPos << 20 >> 20);
z += (sectionPos >> 16) & 0xF;
return new BlockPos(x, y, z);
}

@Override
public int compareTo(BlockPos other) {
if (this.y == other.y) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package net.imprex.orebfuscator.util;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class BlockPosTest {

@Test
public void testLongFormat() {
BlockPos positionA = new BlockPos(-52134, BlockPos.MAX_Y, 6243234);
BlockPos positionB = new BlockPos(0, BlockPos.MIN_Y, -4);
BlockPos positionC = new BlockPos(15, 0, -5663423);
BlockPos positionD = new BlockPos(21523, 16, -5663423);

long valueA = positionA.toLong();
long valueB = positionB.toLong();
long valueC = positionC.toLong();
long valueD = positionD.toLong();

assertEquals(positionA, BlockPos.fromLong(valueA));
assertEquals(positionB, BlockPos.fromLong(valueB));
assertEquals(positionC, BlockPos.fromLong(valueC));
assertEquals(positionD, BlockPos.fromLong(valueD));
}

@Test
public void testSectionPos() {
final int chunkX = -42 << 4;
final int chunkZ = 6521 << 4;

BlockPos positionA = new BlockPos(chunkX + 8, BlockPos.MAX_Y, chunkZ);
BlockPos positionB = new BlockPos(chunkX, BlockPos.MIN_Y, chunkZ + 15);
BlockPos positionC = new BlockPos(chunkX + 15, 0, chunkZ + 4);

int sectionPosA = positionA.toSectionPos();
int sectionPosB = positionB.toSectionPos();
int sectionPosC = positionC.toSectionPos();

assertEquals(positionA, BlockPos.fromSectionPos(chunkX, chunkZ, sectionPosA));
assertEquals(positionB, BlockPos.fromSectionPos(chunkX, chunkZ, sectionPosB));
assertEquals(positionC, BlockPos.fromSectionPos(chunkX, chunkZ, sectionPosC));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.imprex.orebfuscator.obfuscation;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.bukkit.World;
Expand Down Expand Up @@ -39,7 +41,7 @@ public void process(ObfuscationTask task) {
ProximityConfig proximityConfig = bundle.proximity();

Set<BlockPos> blockEntities = new HashSet<>();
Set<BlockPos> proximityBlocks = new HashSet<>();
List<BlockPos> proximityBlocks = new ArrayList<>();

int baseX = chunkStruct.chunkX << 4;
int baseZ = chunkStruct.chunkZ << 4;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.imprex.orebfuscator.obfuscation;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

Expand Down Expand Up @@ -64,7 +65,7 @@ public CompletableFuture<ObfuscationResult> submitForObfuscation() {
return this.future;
}

public ObfuscationResult createResult(byte[] data, Set<BlockPos> blockEntities, Set<BlockPos> proximityBlocks) {
public ObfuscationResult createResult(byte[] data, Set<BlockPos> blockEntities, List<BlockPos> proximityBlocks) {
return new ObfuscationResult(this.position, this.chunkHash, data, blockEntities, proximityBlocks);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.imprex.orebfuscator.obfuscation;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.imprex.orebfuscator.util.BlockPos;
Expand All @@ -14,14 +16,14 @@ public class ObfuscationResult {
private final byte[] data;

private final Set<BlockPos> blockEntities;
private final Set<BlockPos> proximityBlocks;
private final List<BlockPos> proximityBlocks;

public ObfuscationResult(ChunkPosition position, byte[] hash, byte[] data) {
this(position, hash, data, new HashSet<>(), new HashSet<>());
this(position, hash, data, new HashSet<>(), new ArrayList<>());
}

public ObfuscationResult(ChunkPosition position, byte[] hash, byte[] data,
Set<BlockPos> blockEntities, Set<BlockPos> proximityBlocks) {
Set<BlockPos> blockEntities, List<BlockPos> proximityBlocks) {
this.position = position;
this.hash = hash;
this.data = data;
Expand All @@ -45,7 +47,7 @@ public Set<BlockPos> getBlockEntities() {
return blockEntities;
}

public Set<BlockPos> getProximityBlocks() {
public List<BlockPos> getProximityBlocks() {
return proximityBlocks;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.imprex.orebfuscator.obfuscation;

import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

Expand Down Expand Up @@ -38,7 +39,7 @@ public ChunkStruct getChunkStruct() {
return this.request.getChunkStruct();
}

public void complete(byte[] data, Set<BlockPos> blockEntities, Set<BlockPos> proximityBlocks) {
public void complete(byte[] data, Set<BlockPos> blockEntities, List<BlockPos> proximityBlocks) {
this.request.complete(this.request.createResult(data, blockEntities, proximityBlocks));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package net.imprex.orebfuscator.player;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

Expand All @@ -23,7 +22,7 @@ public class OrebfuscatorPlayer {
private final AdvancedConfig config;

private final AtomicReference<World> world = new AtomicReference<>();
private final Map<Long, Set<BlockPos>> chunks = new ConcurrentHashMap<>();
private final Map<Long, OrebfuscatorPlayerChunk> chunks = new ConcurrentHashMap<>();

private volatile long latestUpdateTimestamp = System.currentTimeMillis();
private volatile Location location = new Location(null, 0, 0, 0);
Expand Down Expand Up @@ -112,20 +111,16 @@ void updateWorld() {
}
}

public void addChunk(int chunkX, int chunkZ, Set<BlockPos> blocks) {
long key = ChunkPosition.toLong(chunkX, chunkZ);
this.chunks.computeIfAbsent(key, k -> {
return Collections.newSetFromMap(new ConcurrentHashMap<>());
}).addAll(blocks);
public void addChunk(int chunkX, int chunkZ, List<BlockPos> blocks) {
this.chunks.put(ChunkPosition.toLong(chunkX, chunkZ),
new OrebfuscatorPlayerChunk(chunkX, chunkZ, blocks));
}

public Set<BlockPos> getChunk(int chunkX, int chunkZ) {
long key = ChunkPosition.toLong(chunkX, chunkZ);
return this.chunks.getOrDefault(key, Collections.emptySet());
public OrebfuscatorPlayerChunk getChunk(int chunkX, int chunkZ) {
return this.chunks.get(ChunkPosition.toLong(chunkX, chunkZ));
}

public void removeChunk(int chunkX, int chunkZ) {
long key = ChunkPosition.toLong(chunkX, chunkZ);
this.chunks.remove(key);
this.chunks.remove(ChunkPosition.toLong(chunkX, chunkZ));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package net.imprex.orebfuscator.player;

import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import net.imprex.orebfuscator.util.BlockPos;

public class OrebfuscatorPlayerChunk {

private final int chunkX;
private final int chunkZ;

private int proximitySize;
private final int[] proximityBlocks;

public OrebfuscatorPlayerChunk(int chunkX, int chunkZ, List<BlockPos> proximityBlocks) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;

this.proximitySize = proximityBlocks.size();
this.proximityBlocks = new int[proximityBlocks.size()];

for (int i = 0; i < proximityBlocks.size(); i++) {
this.proximityBlocks[i] = proximityBlocks.get(i).toSectionPos();
}
}

public boolean isEmpty() {
return proximitySize <= 0;
}

public Iterator<BlockPos> proximityIterator() {
return new ProximityItr();
}

private class ProximityItr implements Iterator<BlockPos> {

private final int x = chunkX << 4;
private final int z = chunkZ << 4;

private int cursor;
private int returnCursor = -1;

@Override
public boolean hasNext() {
return cursor < proximitySize;
}

@Override
public BlockPos next() {
if (cursor >= proximitySize)
throw new NoSuchElementException();

int sectionPos = proximityBlocks[returnCursor = cursor];
cursor++;

return BlockPos.fromSectionPos(x, z, sectionPos);
}

@Override
public void remove() {
if (returnCursor < 0)
throw new IllegalStateException();

// remove entry
final int index = returnCursor;
final int newSize;
if ((newSize = proximitySize - 1) > index)
System.arraycopy(proximityBlocks, index + 1, proximityBlocks, index, newSize - index);
proximityBlocks[proximitySize = newSize] = 0xFFFFFFFF;

// update cursor positions
cursor = returnCursor;
returnCursor = -1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.bukkit.GameMode;
import org.bukkit.Location;
Expand All @@ -18,6 +17,7 @@
import net.imprex.orebfuscator.config.OrebfuscatorConfig;
import net.imprex.orebfuscator.config.ProximityConfig;
import net.imprex.orebfuscator.player.OrebfuscatorPlayer;
import net.imprex.orebfuscator.player.OrebfuscatorPlayerChunk;
import net.imprex.orebfuscator.player.OrebfuscatorPlayerMap;
import net.imprex.orebfuscator.util.BlockPos;
import net.imprex.orebfuscator.util.FastGazeUtil;
Expand Down Expand Up @@ -103,12 +103,12 @@ private void process(Player player) {
for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) {
for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) {

Set<BlockPos> blocks = orebfuscatorPlayer.getChunk(chunkX, chunkZ);
if (blocks == null) {
OrebfuscatorPlayerChunk chunk = orebfuscatorPlayer.getChunk(chunkX, chunkZ);
if (chunk == null) {
continue;
}

for (Iterator<BlockPos> iterator = blocks.iterator(); iterator.hasNext(); ) {
for (Iterator<BlockPos> iterator = chunk.proximityIterator(); iterator.hasNext(); ) {
BlockPos blockPos = iterator.next();

// check if block is in range
Expand Down Expand Up @@ -141,7 +141,7 @@ private void process(Player player) {
updateBlocks.add(blockPos);
}

if (blocks.isEmpty()) {
if (chunk.isEmpty()) {
orebfuscatorPlayer.removeChunk(chunkX, chunkZ);
}
}
Expand Down

0 comments on commit 37cd25b

Please sign in to comment.