This commit is contained in:
parent
12e95dc2b8
commit
a977168ad9
@ -1589,6 +1589,9 @@ Cleaning up parts of Main class
|
||||
Spawn test structure in macro data on creation
|
||||
Macro data structures block regular foliage generation
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import java.util.Set;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
|
||||
import electrosphere.util.math.HashUtils;
|
||||
|
||||
/**
|
||||
* A container of data about a chunk of terrain
|
||||
@ -42,9 +43,11 @@ public class ChunkData {
|
||||
*/
|
||||
float[][][] voxelWeight;
|
||||
|
||||
//the list of positions modified since the last call to resetModifiedPositions
|
||||
//Used in DrawCell to keep track of which positions to invalidate
|
||||
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
||||
/**
|
||||
* the list of positions modified since the last call to resetModifiedPositions
|
||||
* Used in DrawCell to keep track of which positions to invalidate
|
||||
*/
|
||||
Set<Long> modifiedSinceLastGeneration = new HashSet<Long>();
|
||||
|
||||
/**
|
||||
* The word x coordinate
|
||||
@ -107,7 +110,7 @@ public class ChunkData {
|
||||
for(int y = 0; y < CHUNK_DATA_SIZE; y++){
|
||||
for(int z = 0; z < CHUNK_DATA_SIZE; 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)){
|
||||
modifiedSinceLastGeneration.add(key);
|
||||
}
|
||||
@ -139,7 +142,7 @@ public class ChunkData {
|
||||
for(int y = 0; y < CHUNK_DATA_SIZE; y++){
|
||||
for(int z = 0; z < CHUNK_DATA_SIZE; 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)){
|
||||
modifiedSinceLastGeneration.add(key);
|
||||
}
|
||||
@ -164,7 +167,7 @@ public class ChunkData {
|
||||
voxelWeight[localX][localY][localZ] = weight;
|
||||
voxelType[localX][localY][localZ] = type;
|
||||
//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)){
|
||||
modifiedSinceLastGeneration.add(key);
|
||||
}
|
||||
@ -226,9 +229,11 @@ public class ChunkData {
|
||||
*/
|
||||
public Set<Vector3i> getModifiedPositions(){
|
||||
Set<Vector3i> rVal = new HashSet<Vector3i>();
|
||||
for(String key : modifiedSinceLastGeneration){
|
||||
String[] split = key.split("_");
|
||||
rVal.add(new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2])));
|
||||
for(Long key : modifiedSinceLastGeneration){
|
||||
int x = HashUtils.unhashIVec(key, HashUtils.UNHASH_COMPONENT_X);
|
||||
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;
|
||||
}
|
||||
@ -238,8 +243,8 @@ public class ChunkData {
|
||||
* @param position The voxel position
|
||||
* @return The key
|
||||
*/
|
||||
private String getVoxelPositionKey(Vector3i position){
|
||||
return position.x + "_" + position.y + "_" + position.z;
|
||||
private Long getVoxelPositionKey(Vector3i position){
|
||||
return HashUtils.hashIVec(worldX, worldY, worldZ);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -113,13 +113,19 @@ public class ClientLifeTree implements BehaviorTree {
|
||||
public ClientLifeTree(Entity parent, Object ... params){
|
||||
this.parent = parent;
|
||||
this.healthSystem = (HealthSystem)params[0];
|
||||
stateTransitionUtil = StateTransitionUtil.create(parent, false, new StateTransitionUtilItem[]{
|
||||
StateTransitionUtilItem.create(
|
||||
LifeStateEnum.DYING,
|
||||
healthSystem.getDyingState(),
|
||||
() -> {}
|
||||
)
|
||||
});
|
||||
StateTransitionUtilItem[] stateData = null;
|
||||
if(this.healthSystem.getDyingState() != null){
|
||||
stateData = new StateTransitionUtilItem[]{
|
||||
StateTransitionUtilItem.create(
|
||||
LifeStateEnum.DYING,
|
||||
this.healthSystem.getDyingState(),
|
||||
() -> {}
|
||||
)
|
||||
};
|
||||
} else {
|
||||
stateData = new StateTransitionUtilItem[0];
|
||||
}
|
||||
this.stateTransitionUtil = StateTransitionUtil.create(parent, false, stateData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -313,15 +313,21 @@ public class ServerLifeTree implements BehaviorTree {
|
||||
this.lifeCurrent = this.lifeMax;
|
||||
this.iFrameMaxCount = this.healthSystem.getOnDamageIFrames();
|
||||
this.iFrameCurrent = 0;
|
||||
this.stateTransitionUtil = StateTransitionUtil.create(parent, true, new StateTransitionUtilItem[]{
|
||||
StateTransitionUtilItem.create(
|
||||
LifeStateEnum.DYING,
|
||||
this.healthSystem.getDyingState(),
|
||||
() -> {
|
||||
this.setState(LifeStateEnum.DEAD);
|
||||
}
|
||||
)
|
||||
});
|
||||
StateTransitionUtilItem[] stateData = null;
|
||||
if(this.healthSystem.getDyingState() != null){
|
||||
stateData = new StateTransitionUtilItem[]{
|
||||
StateTransitionUtilItem.create(
|
||||
LifeStateEnum.DYING,
|
||||
this.healthSystem.getDyingState(),
|
||||
() -> {
|
||||
this.setState(LifeStateEnum.DEAD);
|
||||
}
|
||||
)
|
||||
};
|
||||
} else {
|
||||
stateData = new StateTransitionUtilItem[0];
|
||||
}
|
||||
this.stateTransitionUtil = StateTransitionUtil.create(parent, true, stateData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -74,7 +74,7 @@ public class MacroData {
|
||||
* @param seed The seed for the world
|
||||
* @return The world
|
||||
*/
|
||||
public static MacroData generateWorld(long seed){
|
||||
public static MacroData generateWorld(long seed, ServerWorldData serverWorldData){
|
||||
Random random = new Random(seed);
|
||||
MacroData rVal = new MacroData();
|
||||
|
||||
@ -110,10 +110,10 @@ public class MacroData {
|
||||
rVal.characters.add(testChar);
|
||||
|
||||
//add a test character
|
||||
Structure struct = Structure.createStructure(
|
||||
Globals.gameConfigCurrent.getStructureData().getType("test1"),
|
||||
new Vector3d(ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 1, 32770)).sub(0,10,0))
|
||||
);
|
||||
Vector3d structPos = ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 0, 32770));
|
||||
double elevationAtStruct = serverWorldData.getServerTerrainManager().getElevation(32774, 32770, 0, 0);
|
||||
structPos.y = elevationAtStruct;
|
||||
Structure struct = Structure.createStructure(Globals.gameConfigCurrent.getStructureData().getType("test1"),structPos);
|
||||
rVal.structures.add(struct);
|
||||
|
||||
//spawn initial characters in each race
|
||||
|
||||
@ -17,7 +17,9 @@ public class MacroDataLoader {
|
||||
* @return The macro data
|
||||
*/
|
||||
public static MacroData loadFromSave(String saveName){
|
||||
|
||||
MacroData rVal = FileUtils.loadObjectFromSavePath(saveName, "macro.json", MacroData.class);
|
||||
|
||||
//preload and assign structure fabs
|
||||
for(Structure structure : rVal.getStructures()){
|
||||
File fabFile = FileUtils.getAssetFile(structure.getFabPath());
|
||||
@ -30,6 +32,7 @@ public class MacroDataLoader {
|
||||
}
|
||||
structure.setFab(fab);
|
||||
}
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ public class PlainsGen implements HeightmapGenerator {
|
||||
* @return The height
|
||||
*/
|
||||
public float getHeight(long SEED, double x, double y){
|
||||
return sampleAllNoise(SEED, x, y) + HEIGHT_OFFSET;
|
||||
return PlainsGen.sampleAllNoise(SEED, x, y) + HEIGHT_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -6,10 +6,10 @@ import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import electrosphere.server.physics.terrain.diskmap.ChunkDiskMap;
|
||||
import electrosphere.util.math.HashUtils;
|
||||
|
||||
/**
|
||||
* Caches chunk data on the server
|
||||
@ -177,7 +177,7 @@ public class ServerChunkCache {
|
||||
* @return The key
|
||||
*/
|
||||
public long getKey(int worldX, int worldY, int worldZ){
|
||||
return Objects.hash(worldX, worldY, worldZ);
|
||||
return HashUtils.hashIVec(worldX, worldY, worldZ);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -124,8 +124,11 @@ public class SaveUtils {
|
||||
ServerFluidManager serverFluidManager = new ServerFluidManager(serverWorldData, serverTerrainManager, 0, new DefaultFluidGenerator());
|
||||
serverFluidManager.save(saveName);
|
||||
|
||||
//attach terrain to world data prior to pushing into macro data
|
||||
serverWorldData.setManagers(serverTerrainManager, serverFluidManager, null);
|
||||
|
||||
//macro data
|
||||
MacroData macroData = MacroData.generateWorld(sceneFile.getSeed());
|
||||
MacroData macroData = MacroData.generateWorld(sceneFile.getSeed(), serverWorldData);
|
||||
macroData.save(saveName);
|
||||
} else {
|
||||
//just save to disk
|
||||
|
||||
@ -5,8 +5,35 @@ package electrosphere.util.math;
|
||||
*/
|
||||
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]
|
||||
@ -22,4 +49,27 @@ public class HashUtils {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
28
src/test/java/electrosphere/util/math/HashUtilsTests.java
Normal file
28
src/test/java/electrosphere/util/math/HashUtilsTests.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user