better chunk position hashing algo
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-03-30 17:10:53 -04:00
parent 9c6333108d
commit 67212d6003
9 changed files with 42 additions and 14 deletions

View File

@ -1394,6 +1394,7 @@ Vector pooling
Simplify WorldOctTree to reduce lag with large node counts Simplify WorldOctTree to reduce lag with large node counts
Increase memory allowance, mostly fixed latency while walking around Increase memory allowance, mostly fixed latency while walking around
AssetManager streaming budget AssetManager streaming budget
Better chunk position hashing algo

View File

@ -6,9 +6,10 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import electrosphere.util.math.HashUtils;
/** /**
* Caches chunk data on the server * Caches chunk data on the server
*/ */
@ -158,7 +159,7 @@ public class BlockChunkCache {
* @return The key * @return The key
*/ */
public long getKey(int worldX, int worldY, int worldZ){ public long getKey(int worldX, int worldY, int worldZ){
return Objects.hash(worldX, worldY, worldZ); return HashUtils.hashIVec(worldX, worldY, worldZ);
} }
/** /**

View File

@ -7,7 +7,6 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -22,6 +21,7 @@ import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData; import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.util.math.HashUtils;
/** /**
@ -296,6 +296,6 @@ public class ClientBlockManager {
* @return The key * @return The key
*/ */
private Long getRequestKey(int worldX, int worldY, int worldZ, int stride){ private Long getRequestKey(int worldX, int worldY, int worldZ, int stride){
return (long)Objects.hash(worldY, worldZ, worldZ); return (long)HashUtils.hashIVec(worldY, worldZ, worldZ);
} }
} }

View File

@ -5,11 +5,12 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.util.math.HashUtils;
/** /**
@ -151,7 +152,7 @@ public class ClientTerrainCache {
* @return The cache key * @return The cache key
*/ */
public long getKey(int worldX, int worldY, int worldZ){ public long getKey(int worldX, int worldY, int worldZ){
return Objects.hash(worldX, worldY, worldZ); return HashUtils.hashIVec(worldX, worldY, worldZ);
} }
/** /**

View File

@ -9,7 +9,6 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
@ -33,6 +32,7 @@ import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.model.Model; import electrosphere.renderer.model.Model;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.util.math.HashUtils;
/** /**
* Manages terrain storage and access on the client * Manages terrain storage and access on the client
@ -389,7 +389,7 @@ public class ClientTerrainManager {
* @return The key * @return The key
*/ */
private Long getRequestKey(int worldX, int worldY, int worldZ, int stride){ private Long getRequestKey(int worldX, int worldY, int worldZ, int stride){
return (long)Objects.hash(worldY, worldZ, worldZ); return (long)HashUtils.hashIVec(worldY, worldZ, worldZ);
} }
} }

View File

@ -6,7 +6,6 @@ import java.nio.ByteBuffer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterOutputStream; import java.util.zip.InflaterOutputStream;
@ -16,6 +15,7 @@ import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
import electrosphere.util.annotation.Exclude; import electrosphere.util.annotation.Exclude;
import electrosphere.util.math.HashUtils;
/** /**
* An interface for accessing the disk map of chunk information * An interface for accessing the disk map of chunk information
@ -48,7 +48,7 @@ public class ServerBlockChunkDiskMap {
* @return The key * @return The key
*/ */
private static long getBlockChunkKey(int worldX, int worldY, int worldZ){ private static long getBlockChunkKey(int worldX, int worldY, int worldZ){
return Objects.hash(worldX, worldY, worldZ); return HashUtils.hashIVec(worldX, worldY, worldZ);
} }
/** /**

View File

@ -1,7 +1,6 @@
package electrosphere.server.content; package electrosphere.server.content;
import java.util.Collection; import java.util.Collection;
import java.util.Objects;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -12,6 +11,7 @@ import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.saves.SaveUtils; import electrosphere.server.saves.SaveUtils;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
import electrosphere.util.math.HashUtils;
public class ServerContentManager { public class ServerContentManager {
@ -50,7 +50,7 @@ public class ServerContentManager {
contentRaw.hydrateRawContent(realm,cell); contentRaw.hydrateRawContent(realm,cell);
} else { } else {
//else create from scratch //else create from scratch
ServerContentGenerator.generateContent(realm, cell, worldPos, Objects.hash(worldPos.x, worldPos.y, worldPos.z)); ServerContentGenerator.generateContent(realm, cell, worldPos, HashUtils.hashIVec(worldPos.x, worldPos.y, worldPos.z));
} }
} else { } else {
//just because content wasn't generated doesn't mean there isn't data saved under that key //just because content wasn't generated doesn't mean there isn't data saved under that key

View File

@ -7,7 +7,6 @@ import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -42,6 +41,7 @@ import electrosphere.server.fluid.manager.ServerFluidChunk;
import electrosphere.server.fluid.manager.ServerFluidManager; import electrosphere.server.fluid.manager.ServerFluidManager;
import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.server.terrain.models.TerrainModel; import electrosphere.server.terrain.models.TerrainModel;
import electrosphere.util.math.HashUtils;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
/** /**
@ -729,7 +729,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
* @return The server data cell if it exists, otherwise null * @return The server data cell if it exists, otherwise null
*/ */
private Long getServerDataCellKey(Vector3i worldPos){ private Long getServerDataCellKey(Vector3i worldPos){
return (long)Objects.hash(worldPos.x, worldPos.y, worldPos.z); return (long)HashUtils.hashIVec(worldPos.x, worldPos.y, worldPos.z);
} }
/** /**

View File

@ -0,0 +1,25 @@
package electrosphere.util.math;
/**
* Utilities for hashing things
*/
public class HashUtils {
private static final int SHIFT_Y = 16; // 16 bits per value
private static final int SHIFT_Z = 32; // 2 * 16 bits
/**
* Hashes an integer vector. Must be within the range [0,65536]
* @param x The x component
* @param y The y component
* @param z The z component
* @return The hashed value
*/
public static long hashIVec(int x, int y, int z){
if (x < 0 || x > 65536 || y < 0 || y > 65536 || z < 0 || z > 65536) {
throw new IllegalArgumentException("Values must be in range [0, 65536]");
}
return ((long) x) | ((long) y << SHIFT_Y) | ((long) z << SHIFT_Z);
}
}