fix single player loading
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-12-03 16:14:07 -05:00
parent c8ba4c5e5c
commit ddaab9a2db
25 changed files with 522 additions and 462 deletions

1
.gitignore vendored
View File

@ -36,6 +36,7 @@
/saves/random_sp_world
/saves/defaultLevel*
/saves/generation_testing
/saves/World name*
#screenshots
/assets/Screenshots

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Tue Dec 03 12:29:34 EST 2024
buildNumber=516
#Tue Dec 03 15:14:56 EST 2024
buildNumber=519

View File

@ -1229,6 +1229,7 @@ Native code building correctly in jenkins pipeline
Refactoring native code
Fix gravity tree not deactivating when body is disabled
Refactoring world menu generators into dedicated class
Fix single player loading

View File

@ -74,7 +74,7 @@ public class BlockDrawCell {
/**
* The cached minimum distance
*/
double cachedMinDistance = -1;
long cachedMinDistance = -1;
/**
* Target to notify on generation completion
@ -302,11 +302,16 @@ public class BlockDrawCell {
* @param distCache the lod value under which distance caches are invalidated
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<BlockDrawCell> node, int distCache){
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<BlockDrawCell> node, int distCache){
if(cachedMinDistance != INVALID_DIST_CACHE && distCache < lod){
return cachedMinDistance;
} else {
this.cachedMinDistance = GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
double dist = GeomUtils.approxMinDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
if(Double.isFinite(dist)){
this.cachedMinDistance = (long)dist;
} else {
this.cachedMinDistance = GeomUtils.REALLY_BIG_NUMBER;
}
return cachedMinDistance;
}
}

View File

@ -35,27 +35,27 @@ public class ClientBlockCellManager {
/**
* The distance to draw at full resolution
*/
public static final double FULL_RES_DIST = 8 * 8;
public static final double FULL_RES_DIST = 8;
/**
* The distance for half resolution
*/
public static final double HALF_RES_DIST = 16 * 16;
public static final double HALF_RES_DIST = 16;
/**
* The distance for quarter resolution
*/
public static final double QUARTER_RES_DIST = 20 * 20;
public static final double QUARTER_RES_DIST = 20;
/**
* The distance for eighth resolution
*/
public static final double EIGHTH_RES_DIST = 32 * 32;
public static final double EIGHTH_RES_DIST = 32;
/**
* The distance for sixteenth resolution
*/
public static final double SIXTEENTH_RES_DIST = 64 * 64;
public static final double SIXTEENTH_RES_DIST = 64;
/**
* The octree holding all the chunks to evaluate
@ -175,7 +175,9 @@ public class ClientBlockCellManager {
return false;
}
if(node.isLeaf()){
if(this.shouldSplit(playerPos, node, distCache)){
if(this.isMeta(playerPos, node, distCache)){
this.flagAsMeta(node);
} else if(this.shouldSplit(playerPos, node, distCache)){
Globals.profiler.beginCpuSample("ClientDrawCellManager.split");
//perform op
WorldOctTreeNode<BlockDrawCell> container = chunkTree.split(node);
@ -281,12 +283,8 @@ public class ClientBlockCellManager {
* @param node the node
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<BlockDrawCell> node, int distCache){
if(node.getData() == null){
return GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
} else {
return node.getData().getMinDistance(worldPos, node, distCache);
}
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<BlockDrawCell> node, int distCache){
return node.getData().getMinDistance(worldPos, node, distCache);
}
/**
@ -429,6 +427,29 @@ public class ClientBlockCellManager {
}
}
/**
* Checks if this is a meta node
* @param pos The position of the player
* @param node The node
* @param distCache The distance cache
* @return true if it is a meta node, false otherwise
*/
private boolean isMeta(Vector3i pos, WorldOctTreeNode<BlockDrawCell> node, int distCache){
return
node.getLevel() < this.chunkTree.getMaxLevel() - BlockChunkData.LOD_SIXTEENTH_RES &&
this.getMinDistance(pos, node, distCache) > SIXTEENTH_RES_DIST
;
}
/**
* Sets this node to be a meta node
* @param node The node
*/
private void flagAsMeta(WorldOctTreeNode<BlockDrawCell> node){
node.getData().setHasGenerated(true);
node.getData().setHomogenous(true);
}
/**
* Gets whether this should be joined or not
* @param pos the player position
@ -818,6 +839,15 @@ public class ClientBlockCellManager {
return false;
}
/**
* Gets the number of nodes in the tree
* @return The number of nodes
*/
public int getNodeCount(){
return this.chunkTree.getNodeCount();
}
}

View File

@ -33,8 +33,6 @@ public class ClientWorldData {
Vector3f worldMinPoint;
Vector3f worldMaxPoint;
float randomDampener;
int worldDiscreteSize;
@ -42,12 +40,10 @@ public class ClientWorldData {
public ClientWorldData(
Vector3f worldMinPoint,
Vector3f worldMaxPoint,
float randomDampener,
int worldDiscreteSize
) {
this.worldMinPoint = worldMinPoint;
this.worldMaxPoint = worldMaxPoint;
this.randomDampener = randomDampener;
this.worldDiscreteSize = worldDiscreteSize;
}
@ -62,10 +58,6 @@ public class ClientWorldData {
return worldMaxPoint;
}
public float getRandomDampener() {
return randomDampener;
}
public int getWorldDiscreteSize() {
return worldDiscreteSize;
}

View File

@ -35,27 +35,27 @@ public class ClientDrawCellManager {
/**
* The distance to draw at full resolution
*/
public static final double FULL_RES_DIST = 8 * 8;
public static final double FULL_RES_DIST = 8;
/**
* The distance for half resolution
*/
public static final double HALF_RES_DIST = 16 * 16;
public static final double HALF_RES_DIST = 16;
/**
* The distance for quarter resolution
*/
public static final double QUARTER_RES_DIST = 20 * 20;
public static final double QUARTER_RES_DIST = 20;
/**
* The distance for eighth resolution
*/
public static final double EIGHTH_RES_DIST = 32 * 32;
public static final double EIGHTH_RES_DIST = 32;
/**
* The distance for sixteenth resolution
*/
public static final double SIXTEENTH_RES_DIST = 128 * 128;
public static final double SIXTEENTH_RES_DIST = 128;
/**
* Lod value for a full res chunk
@ -205,7 +205,9 @@ public class ClientDrawCellManager {
return false;
}
if(node.isLeaf()){
if(this.shouldSplit(playerPos, node, distCache)){
if(this.isMeta(playerPos, node, distCache)){
this.flagAsMeta(node);
} else if(this.shouldSplit(playerPos, node, distCache)){
Globals.profiler.beginCpuSample("ClientDrawCellManager.split");
//perform op
WorldOctTreeNode<DrawCell> container = chunkTree.split(node);
@ -325,12 +327,8 @@ public class ClientDrawCellManager {
* @param node the node
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<DrawCell> node, int distCache){
if(node.getData() == null){
return GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
} else {
return node.getData().getMinDistance(worldPos, node, distCache);
}
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<DrawCell> node, int distCache){
return node.getData().getMinDistance(worldPos, node, distCache);
}
/**
@ -564,6 +562,29 @@ public class ClientDrawCellManager {
}
}
/**
* Checks if this is a meta node
* @param pos The position of the player
* @param node The node
* @param distCache The distance cache
* @return true if it is a meta node, false otherwise
*/
private boolean isMeta(Vector3i pos, WorldOctTreeNode<DrawCell> node, int distCache){
return
node.getLevel() < this.chunkTree.getMaxLevel() - SIXTEENTH_RES_LOD &&
this.getMinDistance(pos, node, distCache) > SIXTEENTH_RES_DIST
;
}
/**
* Sets this node to be a meta node
* @param node The node
*/
private void flagAsMeta(WorldOctTreeNode<DrawCell> node){
node.getData().setHasGenerated(true);
node.getData().setHomogenous(true);
}
/**
* Gets whether this should be joined or not
* @param pos the player position
@ -1001,6 +1022,14 @@ public class ClientDrawCellManager {
return halfResCount;
}
/**
* Gets the number of nodes in the tree
* @return The number of nodes
*/
public int getNodeCount(){
return this.chunkTree.getNodeCount();
}
/**
* Gets The number of generated chunks
* @return

View File

@ -91,7 +91,7 @@ public class DrawCell {
/**
* The cached minimum distance
*/
double cachedMinDistance = -1;
long cachedMinDistance = -1;
/**
* Target to notify on generation completion
@ -579,11 +579,16 @@ public class DrawCell {
* @param distCache the lod value under which distance caches are invalidated
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<DrawCell> node, int distCache){
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<DrawCell> node, int distCache){
if(cachedMinDistance != INVALID_DIST_CACHE && distCache < lod){
return cachedMinDistance;
} else {
this.cachedMinDistance = GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
double dist = GeomUtils.approxMinDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
if(Double.isFinite(dist)){
this.cachedMinDistance = (long)dist;
} else {
this.cachedMinDistance = GeomUtils.REALLY_BIG_NUMBER;
}
return cachedMinDistance;
}
}

View File

@ -190,7 +190,7 @@ public class FoliageCell {
/**
* The cached minimum distance
*/
double cachedMinDistance = -1;
long cachedMinDistance = -1;
/**
* Target to notify on generation completion
@ -670,11 +670,16 @@ public class FoliageCell {
* @param distCache the lod value under which distance caches are invalidated
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<FoliageCell> node, int distCache){
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<FoliageCell> node, int distCache){
if(cachedMinDistance != INVALID_DIST_CACHE && distCache < lod){
return cachedMinDistance;
} else {
this.cachedMinDistance = GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
double dist = GeomUtils.approxMinDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
if(Double.isFinite(dist)){
this.cachedMinDistance = (long)dist;
} else {
this.cachedMinDistance = GeomUtils.REALLY_BIG_NUMBER;
}
return cachedMinDistance;
}
}

View File

@ -35,27 +35,27 @@ public class FoliageCellManager {
/**
* The distance to foliage at full resolution
*/
public static final double FULL_RES_DIST = 16 * 16;
public static final double FULL_RES_DIST = 16;
/**
* The distance for half resolution
*/
public static final double HALF_RES_DIST = 20 * 20;
public static final double HALF_RES_DIST = 20;
/**
* The distance for quarter resolution
*/
public static final double QUARTER_RES_DIST = 16 * 16;
public static final double QUARTER_RES_DIST = 16;
/**
* The distance for eighth resolution
*/
public static final double EIGHTH_RES_DIST = 24 * 24;
public static final double EIGHTH_RES_DIST = 24;
/**
* The distance for sixteenth resolution
*/
public static final double SIXTEENTH_RES_DIST = 64 * 64;
public static final double SIXTEENTH_RES_DIST = 64;
/**
* Lod value for a full res chunk
@ -211,7 +211,9 @@ public class FoliageCellManager {
return false;
}
if(node.isLeaf()){
if(this.shouldSplit(absVoxelPos, node, distCache)){
if(this.isMeta(absVoxelPos, node, distCache)){
this.flagAsMeta(node);
} else if(this.shouldSplit(absVoxelPos, node, distCache)){
Globals.profiler.beginCpuSample("FoliageCellManager.split");
//perform op
WorldOctTreeNode<FoliageCell> container = chunkTree.split(node);
@ -338,12 +340,8 @@ public class FoliageCellManager {
* @param node the node
* @return the distance
*/
public double getMinDistance(Vector3i worldPos, WorldOctTreeNode<FoliageCell> node, int distCache){
if(node.getData() == null){
return GeomUtils.getMinSquaredDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound());
} else {
return node.getData().getMinDistance(worldPos, node, distCache);
}
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<FoliageCell> node, int distCache){
return node.getData().getMinDistance(worldPos, node, distCache);
}
/**
@ -486,6 +484,29 @@ public class FoliageCellManager {
}
}
/**
* Checks if this is a meta node
* @param pos The position of the player
* @param node The node
* @param distCache The distance cache
* @return true if it is a meta node, false otherwise
*/
private boolean isMeta(Vector3i pos, WorldOctTreeNode<FoliageCell> node, int distCache){
return
node.getLevel() < this.chunkTree.getMaxLevel() - SIXTEENTH_RES_LOD &&
this.getMinDistance(pos, node, distCache) > SIXTEENTH_RES_DIST
;
}
/**
* Sets this node to be a meta node
* @param node The node
*/
private void flagAsMeta(WorldOctTreeNode<FoliageCell> node){
node.getData().setHasGenerated(true);
node.getData().setHomogenous(true);
}
/**
* Gets whether this should be joined or not
* @param pos the player position
@ -865,6 +886,13 @@ public class FoliageCellManager {
return null;
}
/**
* Gets the number of nodes in the tree
* @return The number of nodes
*/
public int getNodeCount(){
return this.chunkTree.getNodeCount();
}
}

View File

@ -36,8 +36,17 @@ public class ImGuiChunkMonitor {
//ui framework text
ImGui.text("Chunk Monitor");
Globals.clientDrawCellManager.updateStatus();
ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getMaxResCount());
if(Globals.clientDrawCellManager != null){
Globals.clientDrawCellManager.updateStatus();
ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getMaxResCount());
ImGui.text("Terrain node count: " + Globals.clientDrawCellManager.getNodeCount());
}
if(Globals.clientBlockCellManager != null){
ImGui.text("Block node count: " + Globals.clientBlockCellManager.getNodeCount());
}
if(Globals.foliageCellManager != null){
ImGui.text("Foliage node count: " + Globals.foliageCellManager.getNodeCount());
}
}
});
chunkMonitorWindow.setOpen(false);

View File

@ -7,6 +7,7 @@ import electrosphere.server.terrain.generation.DefaultChunkGenerator;
import electrosphere.server.terrain.generation.TestGenerationChunkGenerator;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.server.terrain.models.TerrainModel;
import electrosphere.util.FileUtils;
import org.joml.Vector3d;
@ -21,7 +22,7 @@ public class ServerWorldData {
/**
* The size of the procedural world
*/
public static final int PROCEDURAL_WORLD_SIZE = 2000;
public static final int PROCEDURAL_WORLD_SIZE = TerrainModel.MAX_WORLD_SIZE_DISCRETE;
public static enum WorldType {
GAME_WORLD,

View File

@ -14,7 +14,6 @@ import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.template.ClientProtocolTemplate;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* The client protocol for handling terrain messages
@ -35,15 +34,14 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
//Vector3f worldMinPoint, Vector3f worldMaxPoint, int dynamicInterpolationRatio, float randomDampener, int worldDiscreteSize
new Vector3f(
message.getworldMinX(),
0,
message.getworldMinY()
message.getworldMinY(),
message.getworldMinZ()
),
new Vector3f(
message.getworldMaxX(),
(int)(message.getworldSizeDiscrete() * ServerTerrainChunk.CHUNK_DIMENSION),
message.getworldMaxY()
message.getworldMaxY(),
message.getworldMaxZ()
),
message.getrandomDampener(),
message.getworldSizeDiscrete()
);
Globals.clientSceneWrapper.getCollisionEngine().setCollisionWorldData(new CollisionWorldData(Globals.clientWorldData));

View File

@ -37,8 +37,10 @@ public class TerrainMessage extends NetworkMessage {
float randomDampener;
int worldMinX;
int worldMinY;
int worldMinZ;
int worldMaxX;
int worldMaxY;
int worldMaxZ;
float value;
int worldX;
int worldY;
@ -138,6 +140,20 @@ public class TerrainMessage extends NetworkMessage {
this.worldMinY = worldMinY;
}
/**
* Gets worldMinZ
*/
public int getworldMinZ() {
return worldMinZ;
}
/**
* Sets worldMinZ
*/
public void setworldMinZ(int worldMinZ) {
this.worldMinZ = worldMinZ;
}
/**
* Gets worldMaxX
*/
@ -166,6 +182,20 @@ public class TerrainMessage extends NetworkMessage {
this.worldMaxY = worldMaxY;
}
/**
* Gets worldMaxZ
*/
public int getworldMaxZ() {
return worldMaxZ;
}
/**
* Sets worldMaxZ
*/
public void setworldMaxZ(int worldMaxZ) {
this.worldMaxZ = worldMaxZ;
}
/**
* Gets value
*/
@ -491,27 +521,27 @@ public class TerrainMessage extends NetworkMessage {
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
stripPacketHeader(byteBuffer);
rVal.setworldSizeDiscrete(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setdynamicInterpolationRatio(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setrandomDampener(ByteStreamUtils.popFloatFromByteQueue(byteBuffer));
rVal.setworldMinX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldMinY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldMinZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldMaxX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldMaxY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldMaxZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
/**
* Constructs a message of type ResponseMetadata
*/
public static TerrainMessage constructResponseMetadataMessage(int worldSizeDiscrete,int dynamicInterpolationRatio,float randomDampener,int worldMinX,int worldMinY,int worldMaxX,int worldMaxY){
public static TerrainMessage constructResponseMetadataMessage(int worldSizeDiscrete,int worldMinX,int worldMinY,int worldMinZ,int worldMaxX,int worldMaxY,int worldMaxZ){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
rVal.setworldSizeDiscrete(worldSizeDiscrete);
rVal.setdynamicInterpolationRatio(dynamicInterpolationRatio);
rVal.setrandomDampener(randomDampener);
rVal.setworldMinX(worldMinX);
rVal.setworldMinY(worldMinY);
rVal.setworldMinZ(worldMinZ);
rVal.setworldMaxX(worldMaxX);
rVal.setworldMaxY(worldMaxY);
rVal.setworldMaxZ(worldMaxZ);
rVal.serialize();
return rVal;
}
@ -1064,26 +1094,27 @@ public class TerrainMessage extends NetworkMessage {
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(dynamicInterpolationRatio);
intValues = ByteStreamUtils.serializeIntToBytes(worldMinX);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeFloatToBytes(randomDampener);
intValues = ByteStreamUtils.serializeIntToBytes(worldMinY);
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
} intValues = ByteStreamUtils.serializeIntToBytes(worldMinX);
}
intValues = ByteStreamUtils.serializeIntToBytes(worldMinZ);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldMinY);
intValues = ByteStreamUtils.serializeIntToBytes(worldMaxX);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldMaxX);
intValues = ByteStreamUtils.serializeIntToBytes(worldMaxY);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldMaxY);
intValues = ByteStreamUtils.serializeIntToBytes(worldMaxZ);
for(int i = 0; i < 4; i++){
rawBytes[26+i] = intValues[i];
}

View File

@ -359,11 +359,11 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
connectionHandler.addMessagetoOutgoingQueue(
TerrainMessage.constructResponseMetadataMessage(
realm.getServerWorldData().getWorldSizeDiscrete(),
realm.getServerWorldData().getDynamicInterpolationRatio(),
0,
(int)realm.getServerWorldData().getWorldBoundMin().x,
(int)realm.getServerWorldData().getWorldBoundMin().y,
(int)realm.getServerWorldData().getWorldBoundMin().z,
(int)realm.getServerWorldData().getWorldBoundMax().x,
(int)realm.getServerWorldData().getWorldBoundMax().y,
(int)realm.getServerWorldData().getWorldBoundMax().z
)
);

View File

@ -78,18 +78,19 @@ public class OverworldChunkGenerator implements ChunkGenerator {
* @return The heightmap array
*/
private float[][] getHeightmap(int worldX, int worldZ){
String key = worldX + "_" + worldZ;
if(heightmapCache.containsKey(key)){
return heightmapCache.get(key);
} else {
float[][] macroValues = model.getRad5MacroValuesAtPosition(worldX, worldZ);
float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk(
macroValues,
model.getDynamicInterpolationRatio()
);
heightmapCache.put(key,heightmap);
return heightmap;
}
// String key = worldX + "_" + worldZ;
// if(heightmapCache.containsKey(key)){
// return heightmapCache.get(key);
// } else {
// float[][] macroValues = model.getRad5MacroValuesAtPosition(worldX, worldZ);
// float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk(
// macroValues,
// model.getDynamicInterpolationRatio()
// );
// heightmapCache.put(key,heightmap);
// return heightmap;
// }
return null;
}
}

View File

@ -162,13 +162,14 @@ public class TerrainGenerator {
erosionSimulation.simulate();
erosionHeightmap = erosionSimulation.getData();
rVal = new TerrainModel(
interpolationPhaseDimension,
modelInput,
OCEAN_THRESHOLD * verticalInterpolationRatio,
MOUNTAIN_THRESHOLD * verticalInterpolationRatio,
dynamicInterpRatio
);
// rVal = new TerrainModel(
// interpolationPhaseDimension,
// modelInput,
// OCEAN_THRESHOLD * verticalInterpolationRatio,
// MOUNTAIN_THRESHOLD * verticalInterpolationRatio,
// dynamicInterpRatio
// );
rVal = TerrainModel.create();
//create internal renderer

View File

@ -0,0 +1,32 @@
package electrosphere.server.terrain.generation.macro;
import electrosphere.server.terrain.models.TerrainModel;
/**
* The default approach to generating macro data
*/
public class DefaultMacroGenerator implements MacroGenerator {
/**
* The default surface biome
*/
static final short DEFAULT_SURFACE_BIOME = 1;
@Override
public void generate(TerrainModel model) {
int DIM = model.getDiscreteArrayDimension();
float[][] elevation = model.getElevation();
short[][] biome = model.getBiome();
for(int x = 0; x < DIM; x++){
for(int y = 0; y < DIM; y++){
elevation[x][y] = 1;
biome[x][y] = DEFAULT_SURFACE_BIOME;
}
}
model.setElevationArray(elevation);
model.setBiome(biome);
}
}

View File

@ -0,0 +1,16 @@
package electrosphere.server.terrain.generation.macro;
import electrosphere.server.terrain.models.TerrainModel;
/**
* Populates a terrain model's macro data
*/
public interface MacroGenerator {
/**
* Generates the macro data in a terrain model
* @param model The terrain model
*/
public void generate(TerrainModel model);
}

View File

@ -5,8 +5,8 @@ import electrosphere.engine.Globals;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.server.terrain.diskmap.ChunkDiskMap;
import electrosphere.server.terrain.generation.TestGenerationChunkGenerator;
import electrosphere.server.terrain.generation.continentphase.TerrainGenerator;
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
import electrosphere.server.terrain.generation.macro.DefaultMacroGenerator;
import electrosphere.server.terrain.models.TerrainModel;
import electrosphere.server.terrain.models.TerrainModification;
import electrosphere.util.FileUtils;
@ -14,6 +14,7 @@ import electrosphere.util.annotation.Exclude;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
@ -99,13 +100,10 @@ public class ServerTerrainManager {
* Generates a terrain model for the manager
*/
public void generate(){
TerrainGenerator terrainGen = new TerrainGenerator();
terrainGen.setInterpolationRatio(parent.getWorldSizeDiscrete()/200);
terrainGen.setVerticalInterpolationRatio(parent.getWorldSizeDiscrete());
terrainGen.setRandomSeed(seed);
model = terrainGen.generateModel();
this.chunkGenerator.setModel(model);
model.setInterpolationRandomDampener(SERVER_TERRAIN_MANAGER_DAMPENER);
this.model = TerrainModel.create();
DefaultMacroGenerator generator = new DefaultMacroGenerator();
generator.generate(this.model);
this.chunkGenerator.setModel(this.model);
this.chunkDiskMap = ChunkDiskMap.init();
}
@ -115,16 +113,38 @@ public class ServerTerrainManager {
*/
public void save(String saveName){
if(model != null){
ByteBuffer buffer = ByteBuffer.allocate(model.getElevation().length * model.getElevation()[0].length * 4);
FloatBuffer floatView = buffer.asFloatBuffer();
for(int x = 0; x < model.getElevation().length; x++){
floatView.put(model.getElevation()[x]);
if(model.getDiscreteArrayDimension() < 1){
throw new Error("Invalid terrain macro data size!");
}
//save the model itself
FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model);
//save the elevation array
ByteBuffer floatBuff = ByteBuffer.allocate(model.getDiscreteArrayDimension() * model.getDiscreteArrayDimension() * 4);
FloatBuffer floatView = floatBuff.asFloatBuffer();
for(int x = 0; x < model.getDiscreteArrayDimension(); x++){
for(int y = 0; y < model.getDiscreteArrayDimension(); y++){
floatView.put(model.getElevation()[x][y]);
}
}
if(floatView.position() > 0){
floatView.flip();
}
FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model);
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array());
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", floatBuff.array());
//save the biome array
ByteBuffer shortBuff = ByteBuffer.allocate(model.getDiscreteArrayDimension() * model.getDiscreteArrayDimension() * 2);
ShortBuffer shortView = shortBuff.asShortBuffer();
for(int x = 0; x < model.getDiscreteArrayDimension(); x++){
for(int y = 0; y < model.getDiscreteArrayDimension(); y++){
shortView.put(model.getBiome()[x][y]);
}
}
if(shortView.position() > 0){
shortView.flip();
}
FileUtils.saveBinaryToSavePath(saveName, "./biome.dat", shortBuff.array());
}
//for each chunk, save via disk map
for(ServerTerrainChunk chunk : this.chunkCache.getContents()){
@ -143,18 +163,41 @@ public class ServerTerrainManager {
public void load(String saveName){
//load terrain model
if(FileUtils.getSaveFile(saveName, "./terrain.json").exists()){
//read the model itself
model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class);
chunkGenerator.setModel(model);
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat");
ByteBuffer buffer = ByteBuffer.wrap(data);
FloatBuffer floatView = buffer.asFloatBuffer();
float[][] elevation = new float[parent.getWorldSizeDiscrete()][parent.getWorldSizeDiscrete()];
for(int x = 0; x < parent.getWorldSizeDiscrete(); x++){
for(int y = 0; y < parent.getWorldSizeDiscrete(); y++){
elevation[x][y] = floatView.get();
if(model.getDiscreteArrayDimension() < 1){
throw new Error("Invalid terrain macro data size!");
}
//read the elevation data
float[][] elevation = new float[model.getDiscreteArrayDimension()][model.getDiscreteArrayDimension()];
if(FileUtils.checkSavePathExists(saveName, "./terrain.dat")){
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat");
ByteBuffer buffer = ByteBuffer.wrap(data);
FloatBuffer floatView = buffer.asFloatBuffer();
for(int x = 0; x < model.getDiscreteArrayDimension(); x++){
for(int y = 0; y < model.getDiscreteArrayDimension(); y++){
elevation[x][y] = floatView.get();
}
}
}
model.setElevationArray(elevation);
//read the biome data
short[][] biome = new short[model.getDiscreteArrayDimension()][model.getDiscreteArrayDimension()];
if(FileUtils.checkSavePathExists(saveName, "./biome.dat")){
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./biome.dat");
ByteBuffer buffer = ByteBuffer.wrap(data);
ShortBuffer shortView = buffer.asShortBuffer();
for(int x = 0; x < model.getDiscreteArrayDimension(); x++){
for(int y = 0; y < model.getDiscreteArrayDimension(); y++){
biome[x][y] = shortView.get();
}
}
}
model.setBiome(biome);
}
//load chunk disk map
chunkDiskMap = ChunkDiskMap.init(saveName);
@ -176,10 +219,6 @@ public class ServerTerrainManager {
this.chunkCache.clear();
}
public float[][] getTerrainAtChunk(int x, int y){
return model.getElevationForChunk(x, y);
}
public float getDiscreteValue(int x, int y){
if(model != null){
return model.getElevation()[x][y];
@ -187,26 +226,6 @@ public class ServerTerrainManager {
return 0;
}
}
public int getDynamicInterpolationRatio(){
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
if(model != null){
return model.getDynamicInterpolationRatio();
} else {
//THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
return 0;
}
}
public float getRandomDampener(){
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
if(model != null){
return model.getRandomDampener();
} else {
//THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
return 0.0f;
}
}
/**
* Gets the terrain model backing this terrain manager

View File

@ -14,29 +14,24 @@ public class TerrainModel {
/**
* Maximum size of the macro data
*/
public static final int MAX_MACRO_DATA_SIZE = 2000;
public static final int MAX_MACRO_DATA_SIZE = 2048;
/**
* The scale of the macro data
*/
public static final int DEFAULT_MACRO_DATA_SCALE = 32;
/**
* The dynamic interpolation ratio
* The maximum discrete world size
*/
int dynamicInterpolationRatio;
/**
* The interpolation dampener
*/
float interpolationRandomDampener = 0.4f;
public static final int MAX_WORLD_SIZE_DISCRETE = MAX_MACRO_DATA_SIZE * DEFAULT_MACRO_DATA_SCALE;
/**
* The discrete array dimension of the model
*/
int discreteArrayDimension;
int discreteArrayDimension = MAX_MACRO_DATA_SIZE;
/**
* The macro level elevation data
@ -78,28 +73,16 @@ public class TerrainModel {
*/
TerrainModel() {
}
/**
* Constructor
* @param dimension The dimension of the model
* @param elevation The macro elevation data
* @param realOceanThreshold The real coordinate ocean threshold
* @param realMountainThreshold The real coordinate mountain threshold
* @param dynamicInterpolationRatio The dynamic interpolation ratio
* Creates the default terrain model
* @return The default terrain model
*/
public TerrainModel(
int dimension,
float[][] elevation,
float realOceanThreshold,
float realMountainThreshold,
int dynamicInterpolationRatio
){
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
this.discreteArrayDimension = dimension;
this.elevation = elevation;
this.realMountainThreshold = realMountainThreshold;
this.realOceanThreshold = realOceanThreshold;
public static TerrainModel create(){
TerrainModel rVal = new TerrainModel();
rVal.elevation = new float[rVal.discreteArrayDimension][rVal.discreteArrayDimension];
rVal.biome = new short[rVal.discreteArrayDimension][rVal.discreteArrayDimension];
return rVal;
}
/**
@ -108,10 +91,9 @@ public class TerrainModel {
* @param dynamicInterpolationRatio The dynamic interpolation ratio
* @return The terrain model
*/
public static TerrainModel constructTerrainModel(int dimension, int dynamicInterpolationRatio){
public static TerrainModel constructTerrainModel(int dimension){
TerrainModel rVal = new TerrainModel();
rVal.discreteArrayDimension = dimension;
rVal.dynamicInterpolationRatio = dynamicInterpolationRatio;
return rVal;
}
@ -122,7 +104,6 @@ public class TerrainModel {
public static TerrainModel generateTestModel(){
TerrainModel rVal = new TerrainModel();
rVal.discreteArrayDimension = TestGenerationChunkGenerator.GENERATOR_REALM_SIZE;
rVal.dynamicInterpolationRatio = 1;
int macroDataImageScale = TestGenerationChunkGenerator.GENERATOR_REALM_SIZE / DEFAULT_MACRO_DATA_SCALE + 1;
rVal.biome = new short[macroDataImageScale][macroDataImageScale];
for(int x = 0; x < macroDataImageScale; x++){
@ -149,290 +130,13 @@ public class TerrainModel {
public short[][] getBiome(){
return biome;
}
/**
* Gets the interpolation random dampener
* @param f The interpolation random dampener
* Sets the biome array
* @param biome The biome array
*/
public void setInterpolationRandomDampener(float f){
interpolationRandomDampener = f;
}
/**
* Dynamically interpolates a chunk of a specific size from the pre-existing elevation map
* @param x The x position on the elevation map to get a chunk from
* @param y The y position on the elevation map to get a chunk from
* @return Dynamically interpolated float array of elevations of chunk
*/
public float[][] getElevationForChunk(int x, int y){
//this is what we intend to return from the function
float[][] rVal = new float[dynamicInterpolationRatio][dynamicInterpolationRatio];
/*
So we're looking at chunk x,y
if this is our grid:
4 0.1 0.2 0.3 0.4
^
| 3 0.1 0.2 0.3 0.4
|
| 2 0.1 0.2 0.3 0.4
x 1 0.1 0.2 0.3 0.4
0 1 2 3
y ---- >
say we're looking at x=2,y=1
"macroValues" should contain the values for bounds x = [1,3] and y = [0,2]
the goal is to have the "center" of the output chunk have the value the
elevation grid at x=2,y=1
*/
//set macroValues
float[][] macroValues = getMacroValuesAtPosition(x,y);
int halfLength = dynamicInterpolationRatio/2;
/*
Four quadrants we're generating
_____________________
|1 |2 |
| | |
| | |
| | |
|__________|__________|
|3 |4 |
| | |
| | |
|__________|__________|
First set of loops is quadrant 1
then quadrant 2
then quadrant 3
then quadrant 4
*/
int outXOffset = 0;
int outYOffset = 0;
for(int i = 0; i < halfLength; i++){
for(int j = 0; j < halfLength; j++){
rVal[i+outXOffset][j+outYOffset] =
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][0] +
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[0][1] +
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][1]
;
}
}
outXOffset = halfLength;
for(int i = 0; i < halfLength; i++){
for(int j = 0; j < halfLength; j++){
rVal[i+outXOffset][j+outYOffset] =
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][0] +
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][1] +
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[2][1]
;
}
}
outXOffset = 0;
outYOffset = halfLength;
for(int i = 0; i < halfLength; i++){
for(int j = 0; j < halfLength; j++){
rVal[i+outXOffset][j+outYOffset] =
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][1] +
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[0][2] +
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][2]
;
}
}
outXOffset = halfLength;
for(int i = 0; i < halfLength; i++){
for(int j = 0; j < halfLength; j++){
rVal[i+outXOffset][j+outYOffset] =
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][1] +
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][2] +
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[2][2]
;
}
}
return rVal;
}
/*
So we're looking at chunk x,y
if this is our grid:
4 0.1 0.2 0.3 0.4
^
| 3 0.1 0.2 0.3 0.4
|
| 2 0.1 0.2 0.3 0.4
x 1 0.1 0.2 0.3 0.4
0 1 2 3
y ---- >
say we're looking at x=2,y=1
"macroValues" should contain the values for x = [1,3] and y = [0,2]
the goal is to have the "center" of the output chunk have the value the
elevation grid at x=2,y=1
*/
/**
* Gets the macro values at a position
* @param x The world x position
* @param y The world y position
* @return The macro values
*/
public float[][] getMacroValuesAtPosition(int x, int y){
float[][] rVal = new float[3][3];
rVal[1][1] = elevation[x][y];
if(x - 1 >= 0){
rVal[0][1] = elevation[x-1][y];
if(y - 1 >= 0){
rVal[0][0] = elevation[x-1][y-1];
} else {
rVal[0][0] = 0;
}
if(y + 1 < discreteArrayDimension){
rVal[0][2] = elevation[x-1][y+1];
} else {
rVal[0][2] = 0;
}
} else {
rVal[0][0] = 0;
rVal[0][1] = 0;
rVal[0][2] = 0;
}
if(x + 1 < discreteArrayDimension){
rVal[2][1] = elevation[x+1][y];
if(y - 1 >= 0){
rVal[2][0] = elevation[x+1][y-1];
} else {
rVal[2][0] = 0;
}
if(y + 1 < discreteArrayDimension){
rVal[2][2] = elevation[x+1][y+1];
} else {
rVal[2][2] = 0;
}
} else {
rVal[2][0] = 0;
rVal[2][1] = 0;
rVal[2][2] = 0;
}
if(y - 1 >= 0){
rVal[1][0] = elevation[x][y-1];
} else {
rVal[1][0] = 0;
}
if(y + 1 < discreteArrayDimension){
rVal[1][2] = elevation[x][y+1];
} else {
rVal[1][2] = 0;
}
return rVal;
}
/**
* Gets the 5-radius macro values at a position
* @param x The x position
* @param y The y position
* @return The macro values
*/
public float[][] getRad5MacroValuesAtPosition(int x, int y){
float[][] rVal = new float[5][5];
for(int i = -2; i < 3; i++){
for(int j = -2; j < 3; j++){
if(x + i >= 0 && x + i < discreteArrayDimension && y + j >= 0 && y + j < discreteArrayDimension){
rVal[i+2][j+2] = elevation[x+i][y+j];
} else {
rVal[i+2][j+2] = 0;
}
}
}
return rVal;
}
/*
So we're looking at chunk x,y
if this is our grid:
4 0.1 0.2 0.3 0.4
^
| 3 0.1 0.2 0.3 0.4
|
| 2 0.1 0.2 0.3 0.4
x 1 0.1 0.2 0.3 0.4
0 1 2 3
y ---- >
say we're looking at x=2,y=1
"macroValues" should contain the values for x = [1,3] and y = [0,2]
the goal is to have the "center" of the output chunk have the value the
elevation grid at x=2,y=1
*/
/**
* Gets the random dampener for the model
* @return The random dampener
*/
public float getRandomDampener(){
return interpolationRandomDampener;
}
/**
* Gets the dynamic interpolation ratio
* @return The ratio
*/
public int getDynamicInterpolationRatio(){
return dynamicInterpolationRatio;
public void setBiome(short[][] biome){
this.biome = biome;
}
/**
@ -532,6 +236,13 @@ public class TerrainModel {
public double getMacroWidthInRealTerms(){
return this.macroDataScale * ServerTerrainChunk.CHUNK_DIMENSION;
}
/**
* Gets the size of the discrete arrays
* @return The size of the discrete arrays
*/
public int getDiscreteArrayDimension(){
return discreteArrayDimension;
}
}

View File

@ -270,6 +270,14 @@ public class WorldOctTree <T> {
}
}
/**
* The number of nodes in the tree
* @return The number of nodes
*/
public int getNodeCount(){
return nodes.size();
}
/**
* A node in a chunk tree

View File

@ -8,6 +8,16 @@ import org.joml.Vector3i;
*/
public class GeomUtils {
/**
* A really big number
*/
public static final int REALLY_BIG_NUMBER = 1000000;
/**
* Cutoff after which we just take the distance between the current axis
*/
public static final int SIMPLIFICATION_CUTOFF = 100000;
/**
* Gets the minimum distance from a point to an axis aligned cube
* @param pos the position to check against
@ -103,6 +113,125 @@ public class GeomUtils {
}
}
/**
* Gets the minimum squared distance from a point to an axis aligned cube
* @param pos the position to check against
* @param cubeMin The min position of the cube
* @param cubeMax The max position of the cube
* @return the distance
*/
public static double approxMinDistanceAABB(Vector3i pos, Vector3i cubeMin, Vector3i cubeMax){
int minX = cubeMin.x;
int minY = cubeMin.y;
int minZ = cubeMin.z;
int maxX = cubeMax.x;
int maxY = cubeMax.y;
int maxZ = cubeMax.z;
if(pos.x > minX && pos.x < maxX){
if(pos.y > minY && pos.y < maxY){
if(pos.z > minZ && pos.z < maxZ){
return 0;
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(pos.x,pos.y,minZ);
} else {
return pos.distance(pos.x,pos.y,maxZ);
}
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - maxY);
}
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(pos.x,minY,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(pos.x,minY,minZ);
} else {
return pos.distance(pos.x,minY,maxZ);
}
} else {
if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - minY);
}
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(pos.x,maxY,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(pos.x,maxY,minZ);
} else {
return pos.distance(pos.x,maxY,maxZ);
}
}
} else if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){
if(Math.abs(pos.x - maxX) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.x - maxX);
}
if(pos.y > minY && pos.y < maxY){
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(minX,pos.y,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(minX,pos.y,minZ);
} else {
return pos.distance(minX,pos.y,maxZ);
}
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - maxY);
}
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(minX,minY,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(minX,minY,minZ);
} else {
return pos.distance(minX,minY,maxZ);
}
} else {
if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - minY);
}
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(minX,maxY,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(minX,maxY,minZ);
} else {
return pos.distance(minX,maxY,maxZ);
}
}
} else {
if(Math.abs(pos.x - minX) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.x - maxX);
}
if(pos.y > minY && pos.y < maxY){
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(maxX,pos.y,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(maxX,pos.y,minZ);
} else {
return pos.distance(maxX,pos.y,maxZ);
}
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - maxY);
}
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(maxX,minY,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(maxX,minY,minZ);
} else {
return pos.distance(maxX,minY,maxZ);
}
} else {
if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - minY);
}
if(pos.z > minZ && pos.z < maxZ){
return pos.distance(maxX,maxY,pos.z);
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(maxX,maxY,minZ);
} else {
return pos.distance(maxX,maxY,maxZ);
}
}
}
}
/**
* Gets the minimum squared distance from a point to an axis aligned cube
* @param pos the position to check against
@ -205,7 +334,7 @@ public class GeomUtils {
* @param cubeMax The max position of the cube
* @return the distance
*/
public static double getMinSquaredDistanceAABB(Vector3i pos, Vector3i cubeMin, Vector3i cubeMax){
public static long getMinSquaredDistanceAABB(Vector3i pos, Vector3i cubeMin, Vector3i cubeMax){
int minX = cubeMin.x;
int minY = cubeMin.y;
int minZ = cubeMin.z;

View File

@ -25,6 +25,10 @@
"name" : "worldMinY",
"type" : "FIXED_INT"
},
{
"name" : "worldMinZ",
"type" : "FIXED_INT"
},
{
"name" : "worldMaxX",
"type" : "FIXED_INT"
@ -33,6 +37,10 @@
"name" : "worldMaxY",
"type" : "FIXED_INT"
},
{
"name" : "worldMaxZ",
"type" : "FIXED_INT"
},
{
@ -120,12 +128,12 @@
"description" : "Tell the client the terrain metadata",
"data" : [
"worldSizeDiscrete",
"dynamicInterpolationRatio",
"randomDampener",
"worldMinX",
"worldMinY",
"worldMinZ",
"worldMaxX",
"worldMaxY"
"worldMaxY",
"worldMaxZ"
]
},
{

View File

@ -35,7 +35,7 @@ public class ClientDrawCellManagerTests {
public void testJoinCase(){
int worldDiscreteSize = 64;
Globals.clientWorldData = new ClientWorldData(new Vector3f(0), new Vector3f(worldDiscreteSize * ServerTerrainChunk.CHUNK_DIMENSION), 0, worldDiscreteSize);
Globals.clientWorldData = new ClientWorldData(new Vector3f(0), new Vector3f(worldDiscreteSize * ServerTerrainChunk.CHUNK_DIMENSION), worldDiscreteSize);
ClientDrawCellManager manager = new ClientDrawCellManager(null, 64);
Vector3i playerPos = new Vector3i(0,0,0);
WorldOctTreeNode<DrawCell> node = WorldOctTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));