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
#Fri Jun 14 13:45:11 EDT 2024
buildNumber=137
#Wed Jun 19 19:19:09 EDT 2024
buildNumber=138

View File

@ -10,6 +10,7 @@
- @subpage archimprovementtargets
- @subpage savesindex
- @subpage hitboxesindex
- @subpage drawcell
# 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]
- @subpage whatmakesaquestgood
- @subpage narrativearcdesign
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
# and may or may not have the sanity to build
DONE:
TODO(?):
- CFD
- Internal Boundaries
- Multigrid optimization
@ -8,6 +13,8 @@
- Transvoxel Algorithm
- Building cube voxels w/ LOD
- Deferred Shading Pipeline
- Audio Ray Tracing
@ -17,3 +24,7 @@
- Massive scale creature groups
(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
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
Demo requirements:
= Assets =
Block animation in first person
@ -385,7 +401,6 @@ Audio FX for everything
= Coding =
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
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- 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:
always enforce opengl interface across all opengl calls jesus christ the bone uniform bug was impossible
@ -457,22 +492,6 @@ Shader library system
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
- 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
Procedural Cliff Texture
- 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
- 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'

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"
},
{
"name" : "chunkResolution",
"type" : "FIXED_INT"
},
{
"name" : "terrainWeight",
"type" : "FIXED_FLOAT"
@ -186,6 +191,27 @@
"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",
"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.EntityUtils;
import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.renderer.texture.Texture;
import electrosphere.server.datacell.Realm;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
*
* @author satellite
* A single drawcell - contains an entity that has a physics mesh and potentially graphics
*/
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
Vector3i worldPos;
//the main entity for the cell
Entity modelEntity;
//the physics mesh
DBody physicsObject;
//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];
int[][][] types = new int[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
static Texture groundTextureOne = new Texture("/Textures/Ground/Dirt1.png");
static Texture groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
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");
}
//the maximum detail LOD level
public static final int FULL_DETAIL_LOD = 0;
/**
* Private constructor
*/
DrawCell(){
}
@ -63,18 +71,23 @@ public class DrawCell {
/**
* 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){
Globals.clientScene.deregisterEntity(modelEntity);
}
this.fillInData();
TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, types, lod);
if(lod > FULL_DETAIL_LOD){
fillInData();
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(weights, types, 0, atlas);
}
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(chunkData, lod, atlas);
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
}
/**
* Gets the real-space position of the draw cell
* @return the real-space position
*/
protected Vector3d getRealPos(){
return new Vector3d(
worldPos.x * ChunkData.CHUNK_SIZE,
@ -225,4 +238,48 @@ public class DrawCell {
}
}
/**
* 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 electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.terrain.cells.DrawCell.DrawCellFace;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
import electrosphere.net.parser.net.message.TerrainMessage;
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 {
@ -27,45 +52,46 @@ public class DrawCellManager {
int cellY;
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
Set<DrawCell> cells;
Set<DrawCell> cells = new HashSet<DrawCell>();
Map<String,DrawCell> keyCellMap = new HashMap<String,DrawCell>();
Set<String> hasNotRequested;
Set<String> hasRequested;
Set<String> drawable;
Set<String> undrawable;
Set<String> updateable;
//status of all position keys
Set<String> hasNotRequested = new HashSet<String>();
Set<String> requested = new HashSet<String>();
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
VoxelTextureAtlas atlas;
//shader program for drawable cells
ShaderProgram program;
// int drawRadius = 5;
int drawStepdownInterval = 3;
int drawStepdownValue = 25;
//the real-space radius for which we will construct draw cells inside of
//ie, we check if the draw cell's entity would be inside this radius. If it would, create the draw cell, otherwise don't
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 worldBoundDiscreteMin = 0;
int worldBoundDiscreteMax = 0;
//client terrain manager
// ClientTerrainManager clientTerrainManager;
//ready to start updating?
boolean update = false;
@ -82,22 +108,22 @@ public class DrawCellManager {
* @param discreteY The initial discrete position Y coordinate
*/
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;
cellY = discreteY;
cellZ = discreteZ;
program = Globals.terrainShaderProgram;
// drawRadius = Globals.userSettings.getGraphicsPerformanceLODChunkRadius();
drawStepdownInterval = Globals.userSettings.getGameplayPhysicsCellRadius();
//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;
}
physicsRadius = Globals.userSettings.getGameplayPhysicsCellRadius();
invalidateAllCells();
@ -105,29 +131,41 @@ public class DrawCellManager {
update = true;
}
/**
* Private constructor
*/
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;
cellY = cellPos.y;
cellZ = cellPos.z;
}
/**
* Update function that is called if a cell has not been requested
*/
void updateUnrequestedCell(){
if(hasNotRequested.size() > 0){
String targetKey = hasNotRequested.iterator().next();
hasNotRequested.remove(targetKey);
Vector3i worldPos = getVectorFromKey(targetKey);
// Vector3i vector = getVectorFromKey(targetKey);
// int currentCellX = cellX - drawRadius + vector.x;
// int currentCellY = cellY - drawRadius + vector.y;
// int currentCellZ = cellZ - drawRadius + vector.z;
//
//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
//The following loop-hell does this
//
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
for(int k = 0; k < 2; k++){
Vector3i posToCheck = new Vector3i(worldPos).add(i,j,k);
String requestKey = getCellKey(posToCheck.x,posToCheck.y,posToCheck.z);
if(
posToCheck.x >= 0 &&
posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() &&
@ -137,20 +175,20 @@ public class DrawCellManager {
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
!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
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage(
posToCheck.x,
posToCheck.y,
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
*/
void makeCellDrawable(){
if(undrawable.size() > 0){
String targetKey = undrawable.iterator().next();
Vector3i worldPos = getVectorFromKey(targetKey);
//
//Checks if all chunk data necessary to generate a mesh is present
boolean containsNecessaryChunks = true;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
@ -175,25 +215,28 @@ public class DrawCellManager {
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
!containsChunkDataAtWorldPoint(posToCheck.x,posToCheck.y,posToCheck.z)
){
containsChunkDataAtWorldPoint(posToCheck.x,posToCheck.y,posToCheck.z);
containsNecessaryChunks = false;
}
}
}
}
//if contains all chunks necessary to generate visuals
//
//if contains data for all chunks necessary to generate visuals
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(
worldPos
);
cells.add(cell);
keyCellMap.put(targetKey,cell);
// undrawable.add(targetKey);
undrawable.remove(targetKey);
drawable.add(targetKey);
//make drawable entity
keyCellMap.get(targetKey).generateDrawableEntity(atlas);
DrawCellFace higherLODFace = null;
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
//evaluate for foliage
Globals.clientFoliageManager.evaluateChunk(worldPos);
}
@ -216,37 +259,49 @@ public class DrawCellManager {
worldPos.z >= 0 &&
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).generateDrawableEntity(atlas);
DrawCellFace higherLODFace = null;
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
}
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(){
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(){
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(){
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){
return (int)(input / Globals.clientWorldData.getDynamicInterpolationRatio());
}
@ -278,7 +333,7 @@ public class DrawCellManager {
Set<DrawCell> cellsToRemove = new HashSet<DrawCell>();
for(DrawCell cell : cells){
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);
}
}
@ -290,7 +345,7 @@ public class DrawCellManager {
undrawable.remove(key);
updateable.remove(key);
keyCellMap.remove(key);
hasRequested.remove(key);
requested.remove(key);
cell.destroy();
}
}
@ -301,9 +356,9 @@ public class DrawCellManager {
private void queueNewCells(){
if(Globals.playerEntity != null && Globals.clientWorldData != null){
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
for(int x = -(int)drawRadius; x < drawRadius; x = x + ChunkData.CHUNK_SIZE){
for(int y = -(int)drawRadius; y < drawRadius; y = y + ChunkData.CHUNK_SIZE){
for(int z = -(int)drawRadius; z < drawRadius; z = z + ChunkData.CHUNK_SIZE){
for(int x = -(int)drawFullModelRadius; x < drawFullModelRadius; x = x + ChunkData.CHUNK_SIZE){
for(int y = -(int)drawFullModelRadius; y < drawFullModelRadius; y = y + 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);
Vector3i worldPos = new Vector3i(
Globals.clientWorldData.convertRealToChunkSpace(newPos.x),
@ -316,7 +371,7 @@ public class DrawCellManager {
Globals.clientWorldData.convertChunkToRealSpace(worldPos.z)
);
if(
playerPos.distance(chunkRealSpace) < drawRadius &&
playerPos.distance(chunkRealSpace) < drawFullModelRadius &&
worldPos.x >= 0 &&
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.y >= 0 &&
@ -330,7 +385,7 @@ public class DrawCellManager {
Globals.clientWorldData.convertRealToChunkSpace(chunkRealSpace.z)
);
if(!keyCellMap.containsKey(key) && !hasNotRequested.contains(key) && !undrawable.contains(key) && !drawable.contains(key) &&
!hasRequested.contains(key)){
!requested.contains(key)){
hasNotRequested.add(key);
}
}
@ -355,27 +410,20 @@ public class DrawCellManager {
}
/**
* Splits a cell key into its constituent coordinates in array format.
* @param cellKey The cell key to split
* @return The coordinates in array format
* Controls whether the client generates drawable chunks or just physics chunks (ie if running a headless client)
* @param generate true to generate graphics, false otherwise
*/
// 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){
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){
if(Globals.clientTerrainManager != null){
return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
@ -428,11 +476,11 @@ public class DrawCellManager {
/**
* Gets the draw radius
* @return the draw radius
* Gets the radius within which full-detail models are drawn
* @return the radius
*/
public double getDrawRadius(){
return drawRadius;
public double getDrawFullModelRadius(){
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
*/
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;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals;
import electrosphere.net.parser.net.message.TerrainMessage;

View File

@ -6,7 +6,6 @@ import java.nio.IntBuffer;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
@ -36,7 +35,7 @@ public class ClientTerrainManager {
public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
//caches chunks from server
static final int CACHE_SIZE = 50;
static final int CACHE_SIZE = 500;
//used for caching the macro values
ClientTerrainCache terrainCache;
@ -55,6 +54,9 @@ public class ClientTerrainManager {
}
/**
* Handles messages that have been received from the server
*/
public void handleMessages(){
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
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){
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){
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){
assert clientWorldData != null;
return terrainCache.containsChunkDataAtWorldPoint(

View File

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

View File

@ -2,6 +2,7 @@ package electrosphere.entity.types.terrain;
import org.joml.Vector3d;
import electrosphere.client.terrain.cells.DrawCell;
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.PhysicsEntityUtils;
@ -11,6 +12,8 @@ import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.datacell.Realm;
/**
@ -21,19 +24,23 @@ public class TerrainChunk {
/**
* Creates a client terrain chunk based on weights and values provided
* @param weights The terrain weights
* @param values The values (block types)
* @param chunkData the chunk data to generate with
* @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
*/
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);
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
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);
}
@ -53,7 +60,7 @@ public class TerrainChunk {
*/
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);
if(data.vertices.size() > 0){

View File

@ -52,6 +52,9 @@ public class MenuGeneratorsLevelEditor {
//is the voxel selection window open
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
@ -172,7 +175,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
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);
return false;
}}));
@ -202,7 +205,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
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());
return false;
}}));
@ -232,7 +235,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
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());
return false;
}}));
@ -263,7 +266,7 @@ public class MenuGeneratorsLevelEditor {
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
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());
return false;
}}));

View File

@ -176,6 +176,16 @@ SYNCHRONIZATION_MESSAGE,
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer);
}
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:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer);

View File

@ -16,6 +16,8 @@ public class TerrainMessage extends NetworkMessage {
SPAWNPOSITION,
REQUESTCHUNKDATA,
SENDCHUNKDATA,
REQUESTREDUCEDCHUNKDATA,
SENDREDUCEDCHUNKDATA,
REQUESTFLUIDDATA,
SENDFLUIDDATA,
UPDATEFLUIDDATA,
@ -40,6 +42,7 @@ public class TerrainMessage extends NetworkMessage {
double realLocationY;
double realLocationZ;
byte[] chunkData;
int chunkResolution;
float terrainWeight;
int terrainValue;
@ -196,6 +199,14 @@ public class TerrainMessage extends NetworkMessage {
this.chunkData = chunkData;
}
public int getchunkResolution() {
return chunkResolution;
}
public void setchunkResolution(int chunkResolution) {
this.chunkResolution = chunkResolution;
}
public float getterrainWeight() {
return terrainWeight;
}
@ -262,6 +273,14 @@ public class TerrainMessage extends NetworkMessage {
}
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
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:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE){
return true;
@ -478,6 +497,79 @@ public class TerrainMessage extends NetworkMessage {
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){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
stripPacketHeader(byteBuffer);
@ -807,6 +899,59 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[18+i] = chunkData[i];
}
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:
rawBytes = new byte[2+4+4+4];
//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_REQUESTCHUNKDATA = 6;
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_SENDFLUIDDATA = 9;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 10;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA = 8;
public static final byte TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA = 9;
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
*/
@ -82,6 +84,7 @@ Message categories
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_REQUESTCHUNKDATA_SIZE = 14;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA_SIZE = 18;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14;
/*
Server subcategories

View File

@ -1,23 +1,18 @@
package electrosphere.renderer.meshgen;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
import electrosphere.engine.Globals;
@ -25,14 +20,13 @@ import electrosphere.entity.types.terrain.TerrainChunkData;
import electrosphere.renderer.model.Material;
import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
public class TerrainChunkModelGeneration {
//http://paulbourke.net/geometry/polygonise/
static int edgeTable[]={
public static int edgeTable[]={
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
@ -68,7 +62,7 @@ public class TerrainChunkModelGeneration {
};
//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},
{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},
@ -625,7 +619,7 @@ public class TerrainChunkModelGeneration {
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-------+ ^ Y

View File

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

View File

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

View File

@ -7,14 +7,12 @@ import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.server.content.serialization.ContentSerialization;
import electrosphere.server.content.serialization.EntitySerialization;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.pathfinding.NavMeshUtils;
import electrosphere.server.saves.SaveUtils;
import electrosphere.util.FileUtils;
@ -54,7 +52,8 @@ public class ServerContentManager {
hydrateRawContent(realm,cell,contentRaw);
} else {
//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 {
//just because content wasn't generated doesn't mean there isn't data saved under that key