Compare commits

...

2 Commits

Author SHA1 Message Date
austin
8dcff7efe0 bug fixes, enforcing best practices
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
2024-06-22 16:32:59 -04:00
austin
7a2bdf7745 transvoxel algorithm meshgen 2024-06-22 16:10:30 -04:00
30 changed files with 3028 additions and 493 deletions

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file #maven.buildNumber.plugin properties file
#Fri Jun 14 13:45:11 EDT 2024 #Wed Jun 19 19:19:09 EDT 2024
buildNumber=137 buildNumber=138

View File

@ -10,6 +10,7 @@
- @subpage archimprovementtargets - @subpage archimprovementtargets
- @subpage savesindex - @subpage savesindex
- @subpage hitboxesindex - @subpage hitboxesindex
- @subpage drawcell
# What is this section # What is this section

View File

@ -0,0 +1,6 @@
@page drawcell Draw Cells
[TOC]
- @subpage transvoxelalgorithm
![](/docs/src/images/architecture/drawcell/ClientMacroArch.png)

View File

@ -0,0 +1,49 @@
@page transvoxelalgorithm Transvoxel Chunk Generation
# High Level
The goal of the transvoxel algorithm is to bridge the divide between a chunk of a higher resolution and a chunk of a lower resolution
![](/docs/src/images/architecture/drawcell/completevoxel.png)
For the voxels on the border between a low resolution chunk and a high resolution chunk, we split the voxels in half
![](/docs/src/images/architecture/drawcell/bisectedvoxel.png)
On the low-resolution half, we perform marching cubes
On the high resolution half, we generate a mesh that adapts the high resolution chunk to the low resolution voxel
![](/docs/src/images/architecture/drawcell/adaptedvoxel.png)
# Major files
[TransvoxelModelGeneration.java](@ref #electrosphere.renderer.meshgen.TransvoxelModelGeneration) - The main class that turns voxel data into mesh data
[TerrainChunk.java](@ref #electrosphere.entity.types.terrain.TerrainChunk) - The class that the DrawCellManager calls to generate chunk meshes
[ClientTerrainManager.java](@ref #electrosphere.client.terrain.manager.ClientTerrainManager) - Handles queueing the mesh data to the gpu
[TerrainChunkGenQueueItem.java](@ref #electrosphere.client.terrain.manager.TerrainChunkGenQueueItem) - A terrain mesh that has been queued to be added to the gpu
# Implementation Notes
The description of the algorithm always refers to the transition cells in terms of y pointing upwards and x pointing to the right.
This can be confusing to think about how it would apply to other orientations (ie what if we're working along the y axis or something and x is "up").
All these transforms are done implicitly in the `generateTerrainChunkData` function. When iterating across each axis, I've manually calculated what point should be where.
The inner polygonize functions always treat it as y-up, but that works because this transform has already been done before the data is passed in.
# Notes about table format
- `transitionCellClass` is indexed into by the case index value generated from the high resolution face data
- `transitionCellData` is indexed into by the class value from the `transitionCellClass`
- `transitionVertexData` is ALSO indexed into by the CASE INDEX VALUE, NOT THE CLASS VALUE. You can figure this out because the `transitionVertexData` has 512 entries

View File

@ -0,0 +1,3 @@
@page narrativearcdesign Narrative Arc Design
Use the idea of conspiracy to create mystery eventually leading to a big series of confrontations and narrative payoff

View File

@ -4,6 +4,7 @@
[TOC] [TOC]
- @subpage whatmakesaquestgood - @subpage whatmakesaquestgood
- @subpage narrativearcdesign
TODO: describe TODO: describe

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -1,6 +1,11 @@
@page bigthings Big Things I want to build @page bigthings Big Things I want to build
# and may or may not have the sanity to build # and may or may not have the sanity to build
DONE:
TODO(?):
- CFD - CFD
- Internal Boundaries - Internal Boundaries
- Multigrid optimization - Multigrid optimization
@ -8,6 +13,8 @@
- Transvoxel Algorithm - Transvoxel Algorithm
- Building cube voxels w/ LOD
- Deferred Shading Pipeline - Deferred Shading Pipeline
- Audio Ray Tracing - Audio Ray Tracing
@ -17,3 +24,7 @@
- Massive scale creature groups - Massive scale creature groups
(ie 10k armies) (ie 10k armies)
- Use HTML to define ui windows
- Some css support
- Language file for translation

View File

@ -371,9 +371,25 @@ Highlevel netcode gen updates
- Furthermore, keep tracking of the existing ids for trees and fields and only generate ids for new trees and fields - Furthermore, keep tracking of the existing ids for trees and fields and only generate ids for new trees and fields
Fix client gravity tree name Fix client gravity tree name
(06/19/2024)
Transvoxel implementation
- Begin work on transvoxel algo
(06/21/2024)
Transvoxel implementation
- First working implementation of mesh generation for transvoxel chunks (architecture of adding it to drawcellmanager still todo)
(06/22/2024)
Transvoxel implementation
- Scaling LODed chunks by lod level
Fix items falling below the ground
# TODO # TODO
Demo requirements: Demo requirements:
= Assets = = Assets =
Block animation in first person Block animation in first person
@ -385,7 +401,6 @@ Audio FX for everything
= Coding = = Coding =
Sour spot, sweet spot for damage hitboxes and hurtboxes Sour spot, sweet spot for damage hitboxes and hurtboxes
Fix items falling below the ground
Sub menu on title screen that allows changing control mappings Sub menu on title screen that allows changing control mappings
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around) Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Introduce block hitbox (blockbox) type - Introduce block hitbox (blockbox) type
@ -400,6 +415,26 @@ Ability for private realms to have time start/stop based on the player's feedbac
Goof off today requirements:
Transvoxel implementation
- Fix draw cell manager requesting far-out chunks
- Properly update to higher LOD meshes as you get closer
Client Terrain Entity Management (specifically creation/teardown for client)
- Also queries for far out chunks to load far away terrain
Server Terrain Management (specifically for collision)
- Handles communicating far out LOD chunks to client as well
Terrain Interface Positional Access Interface
- Ability to get terrain at point for interactions with game world eg placing grass/water collision
BIG BIG BIG BIG IMMEDIATE TO DO: BIG BIG BIG BIG IMMEDIATE TO DO:
always enforce opengl interface across all opengl calls jesus christ the bone uniform bug was impossible always enforce opengl interface across all opengl calls jesus christ the bone uniform bug was impossible
@ -456,22 +491,6 @@ Shader library system
- Abiltiy to include the shader library in individual files (ie implement #include) - Abiltiy to include the shader library in individual files (ie implement #include)
Break control handlers into separate files with new logic to transition between control handler states Break control handlers into separate files with new logic to transition between control handler states
Transvoxel Algorithm
Client Terrain Entity Management (specifically creation/teardown for client)
- Also queries for far out chunks to load far away terrain
Server Terrain Management (specifically for collision)
- Handles communicating far out LOD chunks to client as well
Terrain Interface Positional Access Interface
- Ability to get terrain at point for interactions with game world eg placing grass/water collision
Actually implement transvoxel algo
Marching Cubes Texture Overhaul
- Detect opengl max image size
- Construct texture atlas of max size
- (target 256x256 resolution initially, should give ~1000 types for 8192x8192)
- Prebake all textures into atlas
- Rewrite marching cubes shader to leverage this atlas
Another pass at grass Another pass at grass
- Multiple foliage models in same cell - Multiple foliage models in same cell
@ -580,9 +599,6 @@ Generic collision engine to support different instances of engine (eg hitboxes v
- Major refactoring to happen here - Major refactoring to happen here
Procedural Cliff Texture Procedural Cliff Texture
- Uses noise or fractals or something to generate infinite textures in shader - Uses noise or fractals or something to generate infinite textures in shader
Terrain Chunks:
- Scale textures to be 1 texture per unit of terrain
- Texture atlasing (512x512)
Loot Generator Loot Generator
- System that can generate items that would be appropriate reward given some variables - System that can generate items that would be appropriate reward given some variables
- ie you tell it 'this is this character's stats, this is the relative level of loot I want to provide' - ie you tell it 'this is this character's stats, this is the relative level of loot I want to provide'

View File

@ -0,0 +1,17 @@
@page testing Testing
Eventual goal is to have unit tests for parts of the engine that it makes sense for. Some ideas:
- Loading assets
- UI functionality
- Basic behavior trees
- Script Engine
- AI
- Networking
Current CI is Jenkins, which has a plugin
https://plugins.jenkins.io/xvfb/
that allows for graphical sessions while building
I need to figure out hooking this up to my container in order to do most of the above testing

View File

@ -90,6 +90,11 @@
"type" : "BYTE_ARRAY" "type" : "BYTE_ARRAY"
}, },
{
"name" : "chunkResolution",
"type" : "FIXED_INT"
},
{ {
"name" : "terrainWeight", "name" : "terrainWeight",
"type" : "FIXED_FLOAT" "type" : "FIXED_FLOAT"
@ -186,6 +191,27 @@
"chunkData" "chunkData"
] ]
}, },
{
"messageName" : "RequestReducedChunkData",
"description" : "Requests reduced resolution chunk data from the server",
"data" : [
"worldX",
"worldY",
"worldZ",
"chunkResolution"
]
},
{
"messageName" : "SendReducedChunkData",
"description" : "Sends chunk data to the client",
"data" : [
"worldX",
"worldY",
"worldZ",
"chunkResolution",
"chunkData"
]
},
{ {
"messageName" : "RequestFluidData", "messageName" : "RequestFluidData",
"description" : "Requests a fluid data from the server", "description" : "Requests a fluid data from the server",

View File

@ -11,39 +11,47 @@ import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.terrain.TerrainChunk; import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.shader.ShaderProgram; import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.renderer.texture.Texture; import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.datacell.Realm;
/** /**
* * A single drawcell - contains an entity that has a physics mesh and potentially graphics
* @author satellite
*/ */
public class DrawCell { public class DrawCell {
/**
* Enum for the different faces of a draw cell -- used when filling in data for higher LOD faces
*/
public enum DrawCellFace {
X_POSITIVE,
X_NEGATIVE,
Y_POSITIVE,
Y_NEGATIVE,
Z_POSITIVE,
Z_NEGATIVE,
}
//the position of the draw cell in world coordinates //the position of the draw cell in world coordinates
Vector3i worldPos; Vector3i worldPos;
//the main entity for the cell
Entity modelEntity; Entity modelEntity;
//the physics mesh
DBody physicsObject; DBody physicsObject;
//Allocated once instead of continuously, used to generate the visual/physics models //Allocated once instead of continuously, used to generate the visual/physics models
float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE]; float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
int[][][] types = new int[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE]; int[][][] types = new int[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
//the maximum detail LOD level
public static final int FULL_DETAIL_LOD = 0;
static Texture groundTextureOne = new Texture("/Textures/Ground/Dirt1.png"); /**
static Texture groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png"); * Private constructor
static Texture groundTextureThree = new Texture("/Textures/Ground/Dirt1.png"); */
static Texture groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
static {
// groundTextureOne = new Texture("/Textures/Ground/GrassTileable.png");
// groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
// groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
// groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
}
DrawCell(){ DrawCell(){
} }
@ -63,18 +71,23 @@ public class DrawCell {
/** /**
* Generates a drawable entity based on this chunk * Generates a drawable entity based on this chunk
*/ */
public void generateDrawableEntity(VoxelTextureAtlas atlas){ public void generateDrawableEntity(VoxelTextureAtlas atlas, int lod, DrawCellFace higherLODFace){
if(modelEntity != null){ if(modelEntity != null){
Globals.clientScene.deregisterEntity(modelEntity); Globals.clientScene.deregisterEntity(modelEntity);
} }
this.fillInData();
TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, types, lod);
if(lod > FULL_DETAIL_LOD){
fillInData(); }
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(chunkData, lod, atlas);
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(weights, types, 0, atlas);
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos()); ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
} }
/**
* Gets the real-space position of the draw cell
* @return the real-space position
*/
protected Vector3d getRealPos(){ protected Vector3d getRealPos(){
return new Vector3d( return new Vector3d(
worldPos.x * ChunkData.CHUNK_SIZE, worldPos.x * ChunkData.CHUNK_SIZE,
@ -224,5 +237,49 @@ public class DrawCell {
types[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = 0; types[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = 0;
} }
} }
/**
* Fills in the internal arrays of data for generate terrain models
*/
private void fillInData(TransvoxelChunkData chunkData, int lod, DrawCellFace face){
float[][] faceData = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
int[][] atlasData = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
switch(face){
case X_POSITIVE: {
} break;
case X_NEGATIVE: {
} break;
case Y_POSITIVE: {
} break;
case Y_NEGATIVE: {
} break;
case Z_POSITIVE: {
} break;
case Z_NEGATIVE: {
} break;
}
//
//fill in data
//
//main chunk
//face X
// if(worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
// currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y, worldPos.z);
// for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
// for(int j = 0; j < ChunkData.CHUNK_SIZE; j++){
// weights[ChunkData.CHUNK_SIZE][i][j] = currentChunk.getWeight(0, i, j);
// types[ChunkData.CHUNK_SIZE][i][j] = currentChunk.getType(0, i, j);
// }
// }
// } else {
// for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
// for(int j = 0; j < ChunkData.CHUNK_SIZE; j++){
// weights[ChunkData.CHUNK_SIZE][i][j] = -1;
// types[ChunkData.CHUNK_SIZE][i][j] = 0;
// }
// }
// }
}
} }

View File

@ -9,15 +9,40 @@ import org.joml.Vector3d;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.client.terrain.cache.ChunkData; import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.terrain.cells.DrawCell.DrawCellFace;
import electrosphere.client.terrain.manager.ClientTerrainManager; import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.renderer.shader.ShaderProgram; import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/** /**
* * Manages the graphical entities for the terrain chunks
* @author satellite *
*
*
Notes for integrating with transvoxel algo:
Different problems to tackle
For all chunks within minimum radius, check if they can be updated and update accordingly <--- we do this currently
For all chunks between minimum radius and first LOD radius, check if we can make a LOD chunk
If we can, make a lod chunk or see if it can be updated
This check will be:
For every position, check if all four positions required for LOD chunk are within lod radius
if yes, make lod chunk
If we cannot, create a fullres chunk
This check will be:
For every position, check if all four positions required for LOD chunk are within lod radius
if yes, make lod chunk
if they are outside the far bound, create lod chunk
if they are within the near bound, create a fullres chunk
*/ */
public class DrawCellManager { public class DrawCellManager {
@ -27,45 +52,46 @@ public class DrawCellManager {
int cellY; int cellY;
int cellZ; int cellZ;
//the dimensions of the world that this cell manager can handles
int cellWidth;
//the width of a minicell in this manager
int miniCellWidth;
//all currently displaying mini cells //all currently displaying mini cells
Set<DrawCell> cells; Set<DrawCell> cells = new HashSet<DrawCell>();
Map<String,DrawCell> keyCellMap = new HashMap<String,DrawCell>(); Map<String,DrawCell> keyCellMap = new HashMap<String,DrawCell>();
Set<String> hasNotRequested;
Set<String> hasRequested; //status of all position keys
Set<String> drawable; Set<String> hasNotRequested = new HashSet<String>();
Set<String> undrawable; Set<String> requested = new HashSet<String>();
Set<String> updateable; Set<String> drawable = new HashSet<String>();
Set<String> undrawable = new HashSet<String>();
Set<String> updateable = new HashSet<String>();
//LOD level of all position keys
Map<String,Integer> positionLODLevel = new HashMap<String,Integer>();
//voxel atlas //voxel atlas
VoxelTextureAtlas atlas; VoxelTextureAtlas atlas;
//shader program for drawable cells
ShaderProgram program; ShaderProgram program;
// int drawRadius = 5; //the real-space radius for which we will construct draw cells inside of
int drawStepdownInterval = 3; //ie, we check if the draw cell's entity would be inside this radius. If it would, create the draw cell, otherwise don't
int drawStepdownValue = 25; double drawFullModelRadius = 50;
double drawRadius = 50; //the radius we'll draw LODed chunks for
double drawLODRadius = drawFullModelRadius + ServerTerrainChunk.CHUNK_DIMENSION * (2*2 + 4*4 + 8*8 + 16*16);
//the number of possible LOD levels
//1,2,4,8,16
static final int NUMBER_OF_LOD_LEVELS = 5;
//the table of lod leve -> radius at which we will look for chunks within this log
double[] lodLevelRadiusTable = new double[5];
//the radius for which physics meshes are created when draw cells are created
int physicsRadius = 3; int physicsRadius = 3;
int worldBoundDiscreteMin = 0;
int worldBoundDiscreteMax = 0;
//client terrain manager
// ClientTerrainManager clientTerrainManager;
//ready to start updating? //ready to start updating?
boolean update = false; boolean update = false;
@ -82,22 +108,22 @@ public class DrawCellManager {
* @param discreteY The initial discrete position Y coordinate * @param discreteY The initial discrete position Y coordinate
*/ */
public DrawCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){ public DrawCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
cells = new HashSet<DrawCell>();
hasNotRequested = new HashSet<String>();
drawable = new HashSet<String>();
undrawable = new HashSet<String>();
updateable = new HashSet<String>();
hasRequested = new HashSet<String>();
cellX = discreteX; cellX = discreteX;
cellY = discreteY; cellY = discreteY;
cellZ = discreteZ; cellZ = discreteZ;
program = Globals.terrainShaderProgram; program = Globals.terrainShaderProgram;
//the first lod level is set by user
lodLevelRadiusTable[0] = drawFullModelRadius;
//generate LOD radius table
for(int i = 1; i < NUMBER_OF_LOD_LEVELS; i++){
double sizeOfSingleModel = Math.pow(2,i) * ServerTerrainChunk.CHUNK_DIMENSION;
//size of the radius for this lod level should be three times the size of a model + the previous radius
//this guarantees we get at least one adapter chunk, one proper chunk, and also that the radius accounts for the previous lod level chunks
lodLevelRadiusTable[i] = lodLevelRadiusTable[i-1] + sizeOfSingleModel * 3;
}
// drawRadius = Globals.userSettings.getGraphicsPerformanceLODChunkRadius();
drawStepdownInterval = Globals.userSettings.getGameplayPhysicsCellRadius();
physicsRadius = Globals.userSettings.getGameplayPhysicsCellRadius(); physicsRadius = Globals.userSettings.getGameplayPhysicsCellRadius();
invalidateAllCells(); invalidateAllCells();
@ -105,29 +131,41 @@ public class DrawCellManager {
update = true; update = true;
} }
/**
* Private constructor
*/
DrawCellManager(){ DrawCellManager(){
} }
public void setCell(Vector3i cellPos){ /**
* Sets the player's current position in cell-space
* @param cellPos The cell's position
*/
public void setPlayerCell(Vector3i cellPos){
cellX = cellPos.x; cellX = cellPos.x;
cellY = cellPos.y; cellY = cellPos.y;
cellZ = cellPos.z; cellZ = cellPos.z;
} }
/**
* Update function that is called if a cell has not been requested
*/
void updateUnrequestedCell(){ void updateUnrequestedCell(){
if(hasNotRequested.size() > 0){ if(hasNotRequested.size() > 0){
String targetKey = hasNotRequested.iterator().next(); String targetKey = hasNotRequested.iterator().next();
hasNotRequested.remove(targetKey); hasNotRequested.remove(targetKey);
Vector3i worldPos = getVectorFromKey(targetKey); Vector3i worldPos = getVectorFromKey(targetKey);
// Vector3i vector = getVectorFromKey(targetKey);
// int currentCellX = cellX - drawRadius + vector.x; //
// int currentCellY = cellY - drawRadius + vector.y; //Because of the way marching cubes works, we need to request the adjacent chunks so we know how to properly blend between one chunk and the next
// int currentCellZ = cellZ - drawRadius + vector.z; //The following loop-hell does this
//
for(int i = 0; i < 2; i++){ for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){ for(int j = 0; j < 2; j++){
for(int k = 0; k < 2; k++){ for(int k = 0; k < 2; k++){
Vector3i posToCheck = new Vector3i(worldPos).add(i,j,k); Vector3i posToCheck = new Vector3i(worldPos).add(i,j,k);
String requestKey = getCellKey(posToCheck.x,posToCheck.y,posToCheck.z);
if( if(
posToCheck.x >= 0 && posToCheck.x >= 0 &&
posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() && posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() &&
@ -137,20 +175,20 @@ public class DrawCellManager {
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() && posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z) !Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z)
){ ){
// if(!hasRequested.contains(targetKey)){ if(!requested.contains(requestKey)){
//client should request chunk data from server for each chunk necessary to create the model //client should request chunk data from server for each chunk necessary to create the model
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage( Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage(
posToCheck.x, posToCheck.x,
posToCheck.y, posToCheck.y,
posToCheck.z posToCheck.z
)); ));
// } }
} }
undrawable.add(targetKey);
hasRequested.add(targetKey);
} }
} }
} }
undrawable.add(targetKey);
requested.add(targetKey);
} }
} }
@ -158,10 +196,12 @@ public class DrawCellManager {
* Makes one of the undrawable cells drawable * Makes one of the undrawable cells drawable
*/ */
void makeCellDrawable(){ void makeCellDrawable(){
if(undrawable.size() > 0){ if(undrawable.size() > 0){
String targetKey = undrawable.iterator().next(); String targetKey = undrawable.iterator().next();
Vector3i worldPos = getVectorFromKey(targetKey); Vector3i worldPos = getVectorFromKey(targetKey);
//
//Checks if all chunk data necessary to generate a mesh is present
boolean containsNecessaryChunks = true; boolean containsNecessaryChunks = true;
for(int i = 0; i < 2; i++){ for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){ for(int j = 0; j < 2; j++){
@ -175,25 +215,28 @@ public class DrawCellManager {
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() && posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
!containsChunkDataAtWorldPoint(posToCheck.x,posToCheck.y,posToCheck.z) !containsChunkDataAtWorldPoint(posToCheck.x,posToCheck.y,posToCheck.z)
){ ){
containsChunkDataAtWorldPoint(posToCheck.x,posToCheck.y,posToCheck.z);
containsNecessaryChunks = false; containsNecessaryChunks = false;
} }
} }
} }
} }
//if contains all chunks necessary to generate visuals //
//if contains data for all chunks necessary to generate visuals
if(containsNecessaryChunks){ if(containsNecessaryChunks){
//build float array
//update the status of the terrain key
undrawable.remove(targetKey);
drawable.add(targetKey);
//build the cell
DrawCell cell = DrawCell.generateTerrainCell( DrawCell cell = DrawCell.generateTerrainCell(
worldPos worldPos
); );
cells.add(cell); cells.add(cell);
keyCellMap.put(targetKey,cell); keyCellMap.put(targetKey,cell);
// undrawable.add(targetKey); DrawCellFace higherLODFace = null;
undrawable.remove(targetKey); keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
drawable.add(targetKey);
//make drawable entity
keyCellMap.get(targetKey).generateDrawableEntity(atlas);
//evaluate for foliage //evaluate for foliage
Globals.clientFoliageManager.evaluateChunk(worldPos); Globals.clientFoliageManager.evaluateChunk(worldPos);
} }
@ -216,37 +259,49 @@ public class DrawCellManager {
worldPos.z >= 0 && worldPos.z >= 0 &&
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize() worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
){ ){
// if(Math.abs(drawRadius + 1 - targetX) < physicsRadius && Math.abs(drawRadius + 1 - targetY) < physicsRadius){
// needsPhysics[targetX][targetY] = true;
// }
// int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius)); //Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius);
// int stride = Math.min(commonWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue));
// while(commonWorldData.getDynamicInterpolationRatio() % stride != 0){
// stride = stride + 1;
// }
keyCellMap.get(targetKey).destroy(); keyCellMap.get(targetKey).destroy();
keyCellMap.get(targetKey).generateDrawableEntity(atlas); DrawCellFace higherLODFace = null;
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
} }
drawable.add(targetKey); drawable.add(targetKey);
} }
} }
/**
* Checks if the manager contains a cell position that hasn't had its chunk data requested from the server yet
* @return true if there is an unrequested cell, false otherwise
*/
public boolean containsUnrequestedCell(){ public boolean containsUnrequestedCell(){
return hasNotRequested.size() > 0; return hasNotRequested.size() > 0;
} }
/**
* Checks if the manager contains a cell who hasn't been made drawable yet
* @return true if there is an undrawable cell, false otherwise
*/
public boolean containsUndrawableCell(){ public boolean containsUndrawableCell(){
return undrawable.size() > 0; return undrawable.size() > 0;
} }
/**
* Checks if the manager contains a cell who needs to be updated
* @return true if there is an updateable cell, false otherwise
*/
public boolean containsUpdateableCell(){ public boolean containsUpdateableCell(){
return updateable.size() > 0; return updateable.size() > 0;
} }
/**
* Transforms a real coordinate into a cell-space coordinate
* @param input the real coordinate
* @return the cell coordinate
*/
public int transformRealSpaceToCellSpace(double input){ public int transformRealSpaceToCellSpace(double input){
return (int)(input / Globals.clientWorldData.getDynamicInterpolationRatio()); return (int)(input / Globals.clientWorldData.getDynamicInterpolationRatio());
} }
@ -278,7 +333,7 @@ public class DrawCellManager {
Set<DrawCell> cellsToRemove = new HashSet<DrawCell>(); Set<DrawCell> cellsToRemove = new HashSet<DrawCell>();
for(DrawCell cell : cells){ for(DrawCell cell : cells){
Vector3d realPos = cell.getRealPos(); Vector3d realPos = cell.getRealPos();
if(Globals.playerEntity != null && EntityUtils.getPosition(Globals.playerEntity).distance(realPos) > drawRadius){ if(Globals.playerEntity != null && EntityUtils.getPosition(Globals.playerEntity).distance(realPos) > drawFullModelRadius){
cellsToRemove.add(cell); cellsToRemove.add(cell);
} }
} }
@ -290,7 +345,7 @@ public class DrawCellManager {
undrawable.remove(key); undrawable.remove(key);
updateable.remove(key); updateable.remove(key);
keyCellMap.remove(key); keyCellMap.remove(key);
hasRequested.remove(key); requested.remove(key);
cell.destroy(); cell.destroy();
} }
} }
@ -301,9 +356,9 @@ public class DrawCellManager {
private void queueNewCells(){ private void queueNewCells(){
if(Globals.playerEntity != null && Globals.clientWorldData != null){ if(Globals.playerEntity != null && Globals.clientWorldData != null){
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity); Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
for(int x = -(int)drawRadius; x < drawRadius; x = x + ChunkData.CHUNK_SIZE){ for(int x = -(int)drawFullModelRadius; x < drawFullModelRadius; x = x + ChunkData.CHUNK_SIZE){
for(int y = -(int)drawRadius; y < drawRadius; y = y + ChunkData.CHUNK_SIZE){ for(int y = -(int)drawFullModelRadius; y < drawFullModelRadius; y = y + ChunkData.CHUNK_SIZE){
for(int z = -(int)drawRadius; z < drawRadius; z = z + ChunkData.CHUNK_SIZE){ for(int z = -(int)drawFullModelRadius; z < drawFullModelRadius; z = z + ChunkData.CHUNK_SIZE){
Vector3d newPos = new Vector3d(playerPos.x + x, playerPos.y + y, playerPos.z + z); Vector3d newPos = new Vector3d(playerPos.x + x, playerPos.y + y, playerPos.z + z);
Vector3i worldPos = new Vector3i( Vector3i worldPos = new Vector3i(
Globals.clientWorldData.convertRealToChunkSpace(newPos.x), Globals.clientWorldData.convertRealToChunkSpace(newPos.x),
@ -316,7 +371,7 @@ public class DrawCellManager {
Globals.clientWorldData.convertChunkToRealSpace(worldPos.z) Globals.clientWorldData.convertChunkToRealSpace(worldPos.z)
); );
if( if(
playerPos.distance(chunkRealSpace) < drawRadius && playerPos.distance(chunkRealSpace) < drawFullModelRadius &&
worldPos.x >= 0 && worldPos.x >= 0 &&
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() && worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.y >= 0 && worldPos.y >= 0 &&
@ -330,7 +385,7 @@ public class DrawCellManager {
Globals.clientWorldData.convertRealToChunkSpace(chunkRealSpace.z) Globals.clientWorldData.convertRealToChunkSpace(chunkRealSpace.z)
); );
if(!keyCellMap.containsKey(key) && !hasNotRequested.contains(key) && !undrawable.contains(key) && !drawable.contains(key) && if(!keyCellMap.containsKey(key) && !hasNotRequested.contains(key) && !undrawable.contains(key) && !drawable.contains(key) &&
!hasRequested.contains(key)){ !requested.contains(key)){
hasNotRequested.add(key); hasNotRequested.add(key);
} }
} }
@ -355,27 +410,20 @@ public class DrawCellManager {
} }
/** /**
* Splits a cell key into its constituent coordinates in array format. * Controls whether the client generates drawable chunks or just physics chunks (ie if running a headless client)
* @param cellKey The cell key to split * @param generate true to generate graphics, false otherwise
* @return The coordinates in array format
*/ */
// private int[] splitKeyToCoordinates(String cellKey){
// int[] rVal = new int[3];
// String[] components = cellKey.split("_");
// for(int i = 0; i < 3; i++){
// rVal[i] = Integer.parseInt(components[i]);
// }
// return rVal;
// }
public boolean coordsInPhysicsSpace(int worldX, int worldY){
return worldX <= cellX + physicsRadius && worldX >= cellX - physicsRadius && worldY <= cellY + physicsRadius && worldY >= cellY - physicsRadius;
}
public void setGenerateDrawables(boolean generate){ public void setGenerateDrawables(boolean generate){
this.generateDrawables = generate; this.generateDrawables = generate;
} }
/**
* Checks if the terrain cache has a chunk at a given world point
* @param worldX the x coordinate
* @param worldY the y coordinate
* @param worldZ the z coordinate
* @return true if the chunk data exists, false otherwise
*/
boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){ boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
if(Globals.clientTerrainManager != null){ if(Globals.clientTerrainManager != null){
return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ); return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
@ -428,11 +476,11 @@ public class DrawCellManager {
/** /**
* Gets the draw radius * Gets the radius within which full-detail models are drawn
* @return the draw radius * @return the radius
*/ */
public double getDrawRadius(){ public double getDrawFullModelRadius(){
return drawRadius; return drawFullModelRadius;
} }
/** /**
@ -444,6 +492,5 @@ public class DrawCellManager {
// public
} }

View File

@ -74,7 +74,7 @@ public class VoxelTextureAtlas {
* @return the index in the atlas of the texture of the provided voxel type * @return the index in the atlas of the texture of the provided voxel type
*/ */
public int getVoxelTypeOffset(int voxelTypeId){ public int getVoxelTypeOffset(int voxelTypeId){
return typeCoordMap.get(voxelTypeId); return typeCoordMap.containsKey(voxelTypeId) ? typeCoordMap.get(voxelTypeId) : -1;
} }
} }

View File

@ -1,9 +1,7 @@
package electrosphere.client.terrain.editing; package electrosphere.client.terrain.editing;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.parser.net.message.TerrainMessage;

View File

@ -6,7 +6,6 @@ import java.nio.IntBuffer;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@ -36,7 +35,7 @@ public class ClientTerrainManager {
public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO; public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
//caches chunks from server //caches chunks from server
static final int CACHE_SIZE = 50; static final int CACHE_SIZE = 500;
//used for caching the macro values //used for caching the macro values
ClientTerrainCache terrainCache; ClientTerrainCache terrainCache;
@ -55,6 +54,9 @@ public class ClientTerrainManager {
} }
/**
* Handles messages that have been received from the server
*/
public void handleMessages(){ public void handleMessages(){
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>(); List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
for(TerrainMessage message : messageQueue){ for(TerrainMessage message : messageQueue){
@ -99,14 +101,32 @@ public class ClientTerrainManager {
} }
} }
/**
* Attaches a terrain message to the queue of messages that this manager needs to process
* @param message The message
*/
public void attachTerrainMessage(TerrainMessage message){ public void attachTerrainMessage(TerrainMessage message){
messageQueue.add(message); messageQueue.add(message);
} }
/**
* Checks if the terrain cache contains chunk data at a given world position
* @param worldX the x position
* @param worldY the y position
* @param worldZ the z position
* @return true if the data exists, false otherwise
*/
public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){ public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
return terrainCache.containsChunkDataAtWorldPoint(worldX, worldY, worldZ); return terrainCache.containsChunkDataAtWorldPoint(worldX, worldY, worldZ);
} }
/**
* Checks that the cache contains chunk data at a real-space coordinate
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @return true if the cache contains the chunk data at the coordinate, false otherwise
*/
public boolean containsChunkDataAtRealPoint(double x, double y, double z){ public boolean containsChunkDataAtRealPoint(double x, double y, double z){
assert clientWorldData != null; assert clientWorldData != null;
return terrainCache.containsChunkDataAtWorldPoint( return terrainCache.containsChunkDataAtWorldPoint(

View File

@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.joml.Vector3i;
import electrosphere.audio.AudioUtils; import electrosphere.audio.AudioUtils;
import electrosphere.audio.VirtualAudioSource; import electrosphere.audio.VirtualAudioSource;
@ -15,7 +16,9 @@ import electrosphere.client.fluid.cells.FluidCellManager;
import electrosphere.client.foliagemanager.ClientFoliageManager; import electrosphere.client.foliagemanager.ClientFoliageManager;
import electrosphere.client.sim.ClientSimulation; import electrosphere.client.sim.ClientSimulation;
import electrosphere.client.targeting.crosshair.Crosshair; import electrosphere.client.targeting.crosshair.Crosshair;
import electrosphere.client.terrain.cells.DrawCell;
import electrosphere.client.terrain.cells.DrawCellManager; import electrosphere.client.terrain.cells.DrawCellManager;
import electrosphere.client.terrain.cells.DrawCell.DrawCellFace;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
import electrosphere.controls.ControlHandler; import electrosphere.controls.ControlHandler;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
@ -28,6 +31,7 @@ import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.movement.ApplyRotationTree; import electrosphere.entity.state.movement.ApplyRotationTree;
import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.entity.types.tree.ProceduralTree; import electrosphere.entity.types.tree.ProceduralTree;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.menu.MenuGenerators; import electrosphere.menu.MenuGenerators;
@ -36,8 +40,10 @@ import electrosphere.menu.WindowUtils;
import electrosphere.menu.mainmenu.MenuGeneratorsMultiplayer; import electrosphere.menu.mainmenu.MenuGeneratorsMultiplayer;
import electrosphere.net.NetUtils; import electrosphere.net.NetUtils;
import electrosphere.net.client.ClientNetworking; import electrosphere.net.client.ClientNetworking;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.renderer.ui.elements.Window; import electrosphere.renderer.ui.elements.Window;
import electrosphere.server.datacell.EntityDataCellMapper; import electrosphere.server.datacell.EntityDataCellMapper;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.util.MathUtils; import electrosphere.util.MathUtils;
public class ClientLoading { public class ClientLoading {
@ -180,7 +186,6 @@ public class ClientLoading {
} else { } else {
Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(1,0,1), MathUtils.getOriginVectorf()); Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(1,0,1), MathUtils.getOriginVectorf());
} }
/* /*

View File

@ -2,6 +2,7 @@ package electrosphere.entity.types.terrain;
import org.joml.Vector3d; import org.joml.Vector3d;
import electrosphere.client.terrain.cells.DrawCell;
import electrosphere.client.terrain.cells.VoxelTextureAtlas; import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.client.terrain.manager.ClientTerrainManager; import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsEntityUtils;
@ -11,6 +12,8 @@ import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.ServerEntityUtils;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration; import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
/** /**
@ -21,19 +24,23 @@ public class TerrainChunk {
/** /**
* Creates a client terrain chunk based on weights and values provided * Creates a client terrain chunk based on weights and values provided
* @param weights The terrain weights * @param chunkData the chunk data to generate with
* @param values The values (block types)
* @param levelOfDetail Increasing value that increments level of detail. 0 would be full resolution, 1 would be half resolution and so on. Only generates physics if levelOfDetail is 0 * @param levelOfDetail Increasing value that increments level of detail. 0 would be full resolution, 1 would be half resolution and so on. Only generates physics if levelOfDetail is 0
* @return The terrain chunk entity * @return The terrain chunk entity
*/ */
public static Entity clientCreateTerrainChunkEntity(float[][][] weights, int[][][] values, int levelOfDetail, VoxelTextureAtlas atlas){ public static Entity clientCreateTerrainChunkEntity(TransvoxelChunkData chunkData, int levelOfDetail, VoxelTextureAtlas atlas){
TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values); TerrainChunkData data;
if(levelOfDetail == DrawCell.FULL_DETAIL_LOD){
data = TerrainChunkModelGeneration.generateTerrainChunkData(chunkData.terrainGrid, chunkData.textureGrid, levelOfDetail);
} else {
data = TransvoxelModelGeneration.generateTerrainChunkData(chunkData);
}
String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas); String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas);
Entity rVal = EntityCreationUtils.createClientSpatialEntity(); Entity rVal = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath); EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
if(data.vertices.size() > 0 && levelOfDetail < 1){ if(data.vertices.size() > 0 && levelOfDetail == DrawCell.FULL_DETAIL_LOD){
PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data); PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
} }
@ -53,7 +60,7 @@ public class TerrainChunk {
*/ */
public static Entity serverCreateTerrainChunkEntity(Realm realm, Vector3d position, float[][][] weights, int[][][] values){ public static Entity serverCreateTerrainChunkEntity(Realm realm, Vector3d position, float[][][] weights, int[][][] values){
TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values); TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values, DrawCell.FULL_DETAIL_LOD);
Entity rVal = EntityCreationUtils.createServerEntity(realm, position); Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
if(data.vertices.size() > 0){ if(data.vertices.size() > 0){

View File

@ -52,6 +52,9 @@ public class MenuGeneratorsLevelEditor {
//is the voxel selection window open //is the voxel selection window open
static boolean voxelWindowOpen = false; static boolean voxelWindowOpen = false;
//vertical offset from cursor position to spawn things at
static final Vector3d cursorVerticalOffset = new Vector3d(0,0.05,0);
/** /**
* Creates the level editor side panel top view * Creates the level editor side panel top view
@ -172,7 +175,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
Realm realm = Globals.realmManager.getRealms().iterator().next(); Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
CreatureUtils.serverSpawnBasicCreature(realm, cursorPos, data.getCreatureId(), null); CreatureUtils.serverSpawnBasicCreature(realm, cursorPos, data.getCreatureId(), null);
return false; return false;
}})); }}));
@ -202,7 +205,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
Realm realm = Globals.realmManager.getRealms().iterator().next(); Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
FoliageUtils.serverSpawnTreeFoliage(realm, cursorPos, data.getName(), new Random().nextLong()); FoliageUtils.serverSpawnTreeFoliage(realm, cursorPos, data.getName(), new Random().nextLong());
return false; return false;
}})); }}));
@ -232,7 +235,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
Realm realm = Globals.realmManager.getRealms().iterator().next(); Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
ItemUtils.serverSpawnBasicItem(realm, cursorPos, item.getItemId()); ItemUtils.serverSpawnBasicItem(realm, cursorPos, item.getItemId());
return false; return false;
}})); }}));
@ -263,7 +266,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
Realm realm = Globals.realmManager.getRealms().iterator().next(); Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0); Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
ObjectUtils.serverSpawnBasicObject(realm, cursorPos, object.getObjectId()); ObjectUtils.serverSpawnBasicObject(realm, cursorPos, object.getObjectId());
return false; return false;
}})); }}));

View File

@ -176,6 +176,16 @@ SYNCHRONIZATION_MESSAGE,
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer); rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestReducedChunkDataMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSendReducedChunkDataMessage(byteBuffer);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer); rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer);

View File

@ -16,6 +16,8 @@ public class TerrainMessage extends NetworkMessage {
SPAWNPOSITION, SPAWNPOSITION,
REQUESTCHUNKDATA, REQUESTCHUNKDATA,
SENDCHUNKDATA, SENDCHUNKDATA,
REQUESTREDUCEDCHUNKDATA,
SENDREDUCEDCHUNKDATA,
REQUESTFLUIDDATA, REQUESTFLUIDDATA,
SENDFLUIDDATA, SENDFLUIDDATA,
UPDATEFLUIDDATA, UPDATEFLUIDDATA,
@ -40,6 +42,7 @@ public class TerrainMessage extends NetworkMessage {
double realLocationY; double realLocationY;
double realLocationZ; double realLocationZ;
byte[] chunkData; byte[] chunkData;
int chunkResolution;
float terrainWeight; float terrainWeight;
int terrainValue; int terrainValue;
@ -196,6 +199,14 @@ public class TerrainMessage extends NetworkMessage {
this.chunkData = chunkData; this.chunkData = chunkData;
} }
public int getchunkResolution() {
return chunkResolution;
}
public void setchunkResolution(int chunkResolution) {
this.chunkResolution = chunkResolution;
}
public float getterrainWeight() { public float getterrainWeight() {
return terrainWeight; return terrainWeight;
} }
@ -262,6 +273,14 @@ public class TerrainMessage extends NetworkMessage {
} }
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
return TerrainMessage.canParsesendChunkDataMessage(byteBuffer); return TerrainMessage.canParsesendChunkDataMessage(byteBuffer);
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA_SIZE){
return true;
} else {
return false;
}
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA:
return TerrainMessage.canParseSendReducedChunkDataMessage(byteBuffer);
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE){ if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE){
return true; return true;
@ -478,6 +497,79 @@ public class TerrainMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static TerrainMessage parseRequestReducedChunkDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setchunkResolution(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
public static TerrainMessage constructRequestReducedChunkDataMessage(int worldX,int worldY,int worldZ,int chunkResolution){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setchunkResolution(chunkResolution);
rVal.serialize();
return rVal;
}
public static boolean canParseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
if(currentStreamLength < 6){
return false;
}
if(currentStreamLength < 10){
return false;
}
if(currentStreamLength < 14){
return false;
}
if(currentStreamLength < 18){
return false;
}
int chunkDataSize = 0;
if(currentStreamLength < 22){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(18 + 0));
temporaryByteQueue.add(byteBuffer.peek(18 + 1));
temporaryByteQueue.add(byteBuffer.peek(18 + 2));
temporaryByteQueue.add(byteBuffer.peek(18 + 3));
chunkDataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 22 + chunkDataSize){
return false;
}
return true;
}
public static TerrainMessage parseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setchunkResolution(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setchunkData(ByteStreamUtils.popByteArrayFromByteQueue(byteBuffer));
return rVal;
}
public static TerrainMessage constructSendReducedChunkDataMessage(int worldX,int worldY,int worldZ,int chunkResolution,byte[] chunkData){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setchunkResolution(chunkResolution);
rVal.setchunkData(chunkData);
rVal.serialize();
return rVal;
}
public static TerrainMessage parseRequestFluidDataMessage(CircularByteBuffer byteBuffer){ public static TerrainMessage parseRequestFluidDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA); TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
stripPacketHeader(byteBuffer); stripPacketHeader(byteBuffer);
@ -807,6 +899,59 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[18+i] = chunkData[i]; rawBytes[18+i] = chunkData[i];
} }
break; break;
case REQUESTREDUCEDCHUNKDATA:
rawBytes = new byte[2+4+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA;
intValues = ByteStreamUtils.serializeIntToBytes(worldX);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldY);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldZ);
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(chunkResolution);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
break;
case SENDREDUCEDCHUNKDATA:
rawBytes = new byte[2+4+4+4+4+4+chunkData.length];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA;
intValues = ByteStreamUtils.serializeIntToBytes(worldX);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldY);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldZ);
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(chunkResolution);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(chunkData.length);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
for(int i = 0; i < chunkData.length; i++){
rawBytes[22+i] = chunkData[i];
}
break;
case REQUESTFLUIDDATA: case REQUESTFLUIDDATA:
rawBytes = new byte[2+4+4+4]; rawBytes = new byte[2+4+4+4];
//message header //message header

View File

@ -69,9 +69,11 @@ Message categories
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 5; public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 5;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 6; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 6;
public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 7; public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 7;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 8; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA = 8;
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 9; public static final byte TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA = 9;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 10; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 10;
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 11;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 12;
/* /*
Terrain packet sizes Terrain packet sizes
*/ */
@ -82,6 +84,7 @@ Message categories
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE = 38; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE = 38;
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26; public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA_SIZE = 18;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14;
/* /*
Server subcategories Server subcategories

View File

@ -1,23 +1,18 @@
package electrosphere.renderer.meshgen; package electrosphere.renderer.meshgen;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import static org.lwjgl.opengl.GL30.glBindVertexArray; import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import electrosphere.client.terrain.cells.VoxelTextureAtlas; import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
@ -25,14 +20,13 @@ import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.renderer.model.Material; import electrosphere.renderer.model.Material;
import electrosphere.renderer.model.Mesh; import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model; import electrosphere.renderer.model.Model;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
public class TerrainChunkModelGeneration { public class TerrainChunkModelGeneration {
//http://paulbourke.net/geometry/polygonise/ //http://paulbourke.net/geometry/polygonise/
static int edgeTable[]={ public static int edgeTable[]={
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
@ -68,7 +62,7 @@ public class TerrainChunkModelGeneration {
}; };
//256 by 16 //256 by 16
static int triTable[][] = { public static int triTable[][] = {
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
@ -625,7 +619,7 @@ public class TerrainChunkModelGeneration {
return new Vector3f(x,y,z); return new Vector3f(x,y,z);
} }
public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid){ public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid, int lod){
// 5 6 // 5 6
// +-------------+ +-----5-------+ ^ Y // +-------------+ +-----5-------+ ^ Y

View File

@ -24,13 +24,13 @@ public class RenderScreenPipeline implements RenderPipeline {
//the leftover texture gets used to draw the screen framebuffer quad //the leftover texture gets used to draw the screen framebuffer quad
//which doesnt work //which doesnt work
openGLState.glActiveTexture(GL40.GL_TEXTURE0); openGLState.glActiveTexture(GL40.GL_TEXTURE0);
GL40.glBindTexture(GL40.GL_TEXTURE_2D, 0); openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0);
openGLState.glActiveTexture(GL40.GL_TEXTURE1); openGLState.glActiveTexture(GL40.GL_TEXTURE1);
GL40.glBindTexture(GL40.GL_TEXTURE_2D, 0); openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0);
openGLState.glActiveTexture(GL40.GL_TEXTURE2); openGLState.glActiveTexture(GL40.GL_TEXTURE2);
GL40.glBindTexture(GL40.GL_TEXTURE_2D, 0); openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0);
openGLState.glActiveTexture(GL40.GL_TEXTURE3); openGLState.glActiveTexture(GL40.GL_TEXTURE3);
GL40.glBindTexture(GL40.GL_TEXTURE_2D, 0); openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0);
openGLState.glActiveTexture(GL40.GL_TEXTURE0); openGLState.glActiveTexture(GL40.GL_TEXTURE0);
openGLState.glDepthTest(false); openGLState.glDepthTest(false);

View File

@ -40,7 +40,7 @@ public class VolumeBufferPipeline implements RenderPipeline {
RenderingEngine.volumeDepthBackfaceFramebuffer.bind(); RenderingEngine.volumeDepthBackfaceFramebuffer.bind();
GL40.glClear(GL40.GL_DEPTH_BUFFER_BIT); GL40.glClear(GL40.GL_DEPTH_BUFFER_BIT);
GL40.glActiveTexture(GL40.GL_TEXTURE0); openGLState.glActiveTexture(GL40.GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, woodTexture); // glBindTexture(GL_TEXTURE_2D, woodTexture);
// renderScene(simpleDepthShader); // renderScene(simpleDepthShader);

View File

@ -7,14 +7,12 @@ import org.joml.Vector3i;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.item.ItemUtils;
import electrosphere.server.content.serialization.ContentSerialization; import electrosphere.server.content.serialization.ContentSerialization;
import electrosphere.server.content.serialization.EntitySerialization; import electrosphere.server.content.serialization.EntitySerialization;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.pathfinding.NavMeshUtils;
import electrosphere.server.saves.SaveUtils; import electrosphere.server.saves.SaveUtils;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
@ -54,7 +52,8 @@ public class ServerContentManager {
hydrateRawContent(realm,cell,contentRaw); hydrateRawContent(realm,cell,contentRaw);
} else { } else {
//else create from scratch //else create from scratch
EnvironmentGenerator.generateForest(realm, cell, worldPos, 0); //UNCOMMENT THIS WHEN YOU WANT CONTENT GENERATED FOR WORLDS AGAIN
// EnvironmentGenerator.generateForest(realm, cell, worldPos, 0);
} }
} else { } else {
//just because content wasn't generated doesn't mean there isn't data saved under that key //just because content wasn't generated doesn't mean there isn't data saved under that key