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
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
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