various work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-29 16:14:06 -04:00
parent 12e95dc2b8
commit a977168ad9
11 changed files with 142 additions and 38 deletions

View File

@ -1589,6 +1589,9 @@ Cleaning up parts of Main class
Spawn test structure in macro data on creation Spawn test structure in macro data on creation
Macro data structures block regular foliage generation Macro data structures block regular foliage generation
ServerBlockManager places macro data structures when generating chunks that contain them ServerBlockManager places macro data structures when generating chunks that contain them
Fix life trees creating state items when trees undefined in data
Unhashing ivec hashed keys in chunk caches
Unit tests for unhash func

View File

@ -6,6 +6,7 @@ import java.util.Set;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
import electrosphere.util.math.HashUtils;
/** /**
* A container of data about a chunk of terrain * A container of data about a chunk of terrain
@ -42,9 +43,11 @@ public class ChunkData {
*/ */
float[][][] voxelWeight; float[][][] voxelWeight;
//the list of positions modified since the last call to resetModifiedPositions /**
//Used in DrawCell to keep track of which positions to invalidate * the list of positions modified since the last call to resetModifiedPositions
Set<String> modifiedSinceLastGeneration = new HashSet<String>(); * Used in DrawCell to keep track of which positions to invalidate
*/
Set<Long> modifiedSinceLastGeneration = new HashSet<Long>();
/** /**
* The word x coordinate * The word x coordinate
@ -107,7 +110,7 @@ public class ChunkData {
for(int y = 0; y < CHUNK_DATA_SIZE; y++){ for(int y = 0; y < CHUNK_DATA_SIZE; y++){
for(int z = 0; z < CHUNK_DATA_SIZE; z++){ for(int z = 0; z < CHUNK_DATA_SIZE; z++){
if(voxelType[x][y][z] != this.voxelType[x][y][z]){ if(voxelType[x][y][z] != this.voxelType[x][y][z]){
String key = getVoxelPositionKey(new Vector3i(x,y,z)); Long key = getVoxelPositionKey(new Vector3i(x,y,z));
if(!modifiedSinceLastGeneration.contains(key)){ if(!modifiedSinceLastGeneration.contains(key)){
modifiedSinceLastGeneration.add(key); modifiedSinceLastGeneration.add(key);
} }
@ -139,7 +142,7 @@ public class ChunkData {
for(int y = 0; y < CHUNK_DATA_SIZE; y++){ for(int y = 0; y < CHUNK_DATA_SIZE; y++){
for(int z = 0; z < CHUNK_DATA_SIZE; z++){ for(int z = 0; z < CHUNK_DATA_SIZE; z++){
if(voxelWeight[x][y][z] != this.voxelWeight[x][y][z]){ if(voxelWeight[x][y][z] != this.voxelWeight[x][y][z]){
String key = getVoxelPositionKey(new Vector3i(x,y,z)); Long key = getVoxelPositionKey(new Vector3i(x,y,z));
if(!modifiedSinceLastGeneration.contains(key)){ if(!modifiedSinceLastGeneration.contains(key)){
modifiedSinceLastGeneration.add(key); modifiedSinceLastGeneration.add(key);
} }
@ -164,7 +167,7 @@ public class ChunkData {
voxelWeight[localX][localY][localZ] = weight; voxelWeight[localX][localY][localZ] = weight;
voxelType[localX][localY][localZ] = type; voxelType[localX][localY][localZ] = type;
//store as modified in cache //store as modified in cache
String key = this.getVoxelPositionKey(new Vector3i(localX,localY,localZ)); Long key = this.getVoxelPositionKey(new Vector3i(localX,localY,localZ));
if(!modifiedSinceLastGeneration.contains(key)){ if(!modifiedSinceLastGeneration.contains(key)){
modifiedSinceLastGeneration.add(key); modifiedSinceLastGeneration.add(key);
} }
@ -226,9 +229,11 @@ public class ChunkData {
*/ */
public Set<Vector3i> getModifiedPositions(){ public Set<Vector3i> getModifiedPositions(){
Set<Vector3i> rVal = new HashSet<Vector3i>(); Set<Vector3i> rVal = new HashSet<Vector3i>();
for(String key : modifiedSinceLastGeneration){ for(Long key : modifiedSinceLastGeneration){
String[] split = key.split("_"); int x = HashUtils.unhashIVec(key, HashUtils.UNHASH_COMPONENT_X);
rVal.add(new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2]))); int y = HashUtils.unhashIVec(key, HashUtils.UNHASH_COMPONENT_Y);
int z = HashUtils.unhashIVec(key, HashUtils.UNHASH_COMPONENT_Z);
rVal.add(new Vector3i(x,y,z));
} }
return rVal; return rVal;
} }
@ -238,8 +243,8 @@ public class ChunkData {
* @param position The voxel position * @param position The voxel position
* @return The key * @return The key
*/ */
private String getVoxelPositionKey(Vector3i position){ private Long getVoxelPositionKey(Vector3i position){
return position.x + "_" + position.y + "_" + position.z; return HashUtils.hashIVec(worldX, worldY, worldZ);
} }
/** /**

View File

@ -113,13 +113,19 @@ public class ClientLifeTree implements BehaviorTree {
public ClientLifeTree(Entity parent, Object ... params){ public ClientLifeTree(Entity parent, Object ... params){
this.parent = parent; this.parent = parent;
this.healthSystem = (HealthSystem)params[0]; this.healthSystem = (HealthSystem)params[0];
stateTransitionUtil = StateTransitionUtil.create(parent, false, new StateTransitionUtilItem[]{ StateTransitionUtilItem[] stateData = null;
StateTransitionUtilItem.create( if(this.healthSystem.getDyingState() != null){
LifeStateEnum.DYING, stateData = new StateTransitionUtilItem[]{
healthSystem.getDyingState(), StateTransitionUtilItem.create(
() -> {} LifeStateEnum.DYING,
) this.healthSystem.getDyingState(),
}); () -> {}
)
};
} else {
stateData = new StateTransitionUtilItem[0];
}
this.stateTransitionUtil = StateTransitionUtil.create(parent, false, stateData);
} }
/** /**

View File

@ -313,15 +313,21 @@ public class ServerLifeTree implements BehaviorTree {
this.lifeCurrent = this.lifeMax; this.lifeCurrent = this.lifeMax;
this.iFrameMaxCount = this.healthSystem.getOnDamageIFrames(); this.iFrameMaxCount = this.healthSystem.getOnDamageIFrames();
this.iFrameCurrent = 0; this.iFrameCurrent = 0;
this.stateTransitionUtil = StateTransitionUtil.create(parent, true, new StateTransitionUtilItem[]{ StateTransitionUtilItem[] stateData = null;
StateTransitionUtilItem.create( if(this.healthSystem.getDyingState() != null){
LifeStateEnum.DYING, stateData = new StateTransitionUtilItem[]{
this.healthSystem.getDyingState(), StateTransitionUtilItem.create(
() -> { LifeStateEnum.DYING,
this.setState(LifeStateEnum.DEAD); this.healthSystem.getDyingState(),
} () -> {
) this.setState(LifeStateEnum.DEAD);
}); }
)
};
} else {
stateData = new StateTransitionUtilItem[0];
}
this.stateTransitionUtil = StateTransitionUtil.create(parent, true, stateData);
} }
/** /**

View File

@ -74,7 +74,7 @@ public class MacroData {
* @param seed The seed for the world * @param seed The seed for the world
* @return The world * @return The world
*/ */
public static MacroData generateWorld(long seed){ public static MacroData generateWorld(long seed, ServerWorldData serverWorldData){
Random random = new Random(seed); Random random = new Random(seed);
MacroData rVal = new MacroData(); MacroData rVal = new MacroData();
@ -110,10 +110,10 @@ public class MacroData {
rVal.characters.add(testChar); rVal.characters.add(testChar);
//add a test character //add a test character
Structure struct = Structure.createStructure( Vector3d structPos = ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 0, 32770));
Globals.gameConfigCurrent.getStructureData().getType("test1"), double elevationAtStruct = serverWorldData.getServerTerrainManager().getElevation(32774, 32770, 0, 0);
new Vector3d(ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 1, 32770)).sub(0,10,0)) structPos.y = elevationAtStruct;
); Structure struct = Structure.createStructure(Globals.gameConfigCurrent.getStructureData().getType("test1"),structPos);
rVal.structures.add(struct); rVal.structures.add(struct);
//spawn initial characters in each race //spawn initial characters in each race

View File

@ -17,7 +17,9 @@ public class MacroDataLoader {
* @return The macro data * @return The macro data
*/ */
public static MacroData loadFromSave(String saveName){ public static MacroData loadFromSave(String saveName){
MacroData rVal = FileUtils.loadObjectFromSavePath(saveName, "macro.json", MacroData.class); MacroData rVal = FileUtils.loadObjectFromSavePath(saveName, "macro.json", MacroData.class);
//preload and assign structure fabs //preload and assign structure fabs
for(Structure structure : rVal.getStructures()){ for(Structure structure : rVal.getStructures()){
File fabFile = FileUtils.getAssetFile(structure.getFabPath()); File fabFile = FileUtils.getAssetFile(structure.getFabPath());
@ -30,6 +32,7 @@ public class MacroDataLoader {
} }
structure.setFab(fab); structure.setFab(fab);
} }
return rVal; return rVal;
} }

View File

@ -42,7 +42,7 @@ public class PlainsGen implements HeightmapGenerator {
* @return The height * @return The height
*/ */
public float getHeight(long SEED, double x, double y){ public float getHeight(long SEED, double x, double y){
return sampleAllNoise(SEED, x, y) + HEIGHT_OFFSET; return PlainsGen.sampleAllNoise(SEED, x, y) + HEIGHT_OFFSET;
} }

View File

@ -6,10 +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.Semaphore; import java.util.concurrent.Semaphore;
import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap; import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap;
import electrosphere.util.math.HashUtils;
/** /**
* Caches chunk data on the server * Caches chunk data on the server
@ -177,7 +177,7 @@ public class ServerChunkCache {
* @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

@ -124,8 +124,11 @@ public class SaveUtils {
ServerFluidManager serverFluidManager = new ServerFluidManager(serverWorldData, serverTerrainManager, 0, new DefaultFluidGenerator()); ServerFluidManager serverFluidManager = new ServerFluidManager(serverWorldData, serverTerrainManager, 0, new DefaultFluidGenerator());
serverFluidManager.save(saveName); serverFluidManager.save(saveName);
//attach terrain to world data prior to pushing into macro data
serverWorldData.setManagers(serverTerrainManager, serverFluidManager, null);
//macro data //macro data
MacroData macroData = MacroData.generateWorld(sceneFile.getSeed()); MacroData macroData = MacroData.generateWorld(sceneFile.getSeed(), serverWorldData);
macroData.save(saveName); macroData.save(saveName);
} else { } else {
//just save to disk //just save to disk

View File

@ -5,8 +5,35 @@ package electrosphere.util.math;
*/ */
public class HashUtils { public class HashUtils {
private static final int SHIFT_Y = 16; // 16 bits per value /**
private static final int SHIFT_Z = 32; // 2 * 16 bits * Bits to shift the y value by
*/
private static final int SHIFT_Y = 16;
/**
* Bits to shift the z value by
*/
private static final int SHIFT_Z = 32;
/**
* Mask used when unhashing components
*/
private static final long UNHASH_MASK = 0xFFFFL;
/**
* Unhashes the x component
*/
public static final int UNHASH_COMPONENT_X = 0;
/**
* Unhashes the y component
*/
public static final int UNHASH_COMPONENT_Y = 1;
/**
* Unhashes the z component
*/
public static final int UNHASH_COMPONENT_Z = 2;
/** /**
* Hashes an integer vector. Must be within the range [0,65536] * Hashes an integer vector. Must be within the range [0,65536]
@ -22,4 +49,27 @@ public class HashUtils {
return ((long) x) | ((long) y << SHIFT_Y) | ((long) z << SHIFT_Z); return ((long) x) | ((long) y << SHIFT_Y) | ((long) z << SHIFT_Z);
} }
/**
* Unhashes an ivec-hashed value
* @param hash The hash
* @param component The component (x, y, or z) to pull from the hash (x=0, y=1, z=2)
* @return The value
*/
public static int unhashIVec(long hash, int component){
switch(component){
case 0: {
return (int)(hash & UNHASH_MASK);
}
case 1: {
return (int)(hash >> SHIFT_Y & UNHASH_MASK);
}
case 2: {
return (int)(hash >> SHIFT_Z & UNHASH_MASK);
}
default: {
throw new Error("Provided undefined component! " + component);
}
}
}
} }

View File

@ -0,0 +1,28 @@
package electrosphere.util.math;
import static org.junit.jupiter.api.Assertions.assertEquals;
import electrosphere.test.annotations.UnitTest;
/**
* Tests for hash utils
*/
public class HashUtilsTests {
@UnitTest
public void test_unhashIVec(){
int x = 1;
int y = 2;
int z = 3;
long hash = HashUtils.hashIVec(x, y, z);
int x_r = HashUtils.unhashIVec(hash, HashUtils.UNHASH_COMPONENT_X);
int y_r = HashUtils.unhashIVec(hash, HashUtils.UNHASH_COMPONENT_Y);
int z_r = HashUtils.unhashIVec(hash, HashUtils.UNHASH_COMPONENT_Z);
assertEquals(x, x_r);
assertEquals(y, y_r);
assertEquals(z, z_r);
}
}