fix single player loading
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
c8ba4c5e5c
commit
ddaab9a2db
1
.gitignore
vendored
1
.gitignore
vendored
@ -36,6 +36,7 @@
|
||||
/saves/random_sp_world
|
||||
/saves/defaultLevel*
|
||||
/saves/generation_testing
|
||||
/saves/World name*
|
||||
|
||||
#screenshots
|
||||
/assets/Screenshots
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
@ -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
|
||||
)
|
||||
);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@ -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));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user