rewrite client side chunks + transvoxel integration
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
d6c476b4a3
commit
d2ccf3c479
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,7 +11,7 @@
|
|||||||
/nb-configuration.xml
|
/nb-configuration.xml
|
||||||
|
|
||||||
/Telephone-*.jar
|
/Telephone-*.jar
|
||||||
/NetArranger-*.jar
|
/NetArranger*.jar
|
||||||
/lwjglx-debug-*.jar
|
/lwjglx-debug-*.jar
|
||||||
/hs_err_pid*
|
/hs_err_pid*
|
||||||
/replay_pid*
|
/replay_pid*
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
#maven.buildNumber.plugin properties file
|
#maven.buildNumber.plugin properties file
|
||||||
#Mon Oct 28 16:07:42 EDT 2024
|
#Mon Nov 04 12:41:10 EST 2024
|
||||||
buildNumber=364
|
buildNumber=375
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
@page chunkgenoptimizations Chunk Generation Optimizations
|
||||||
|
|
||||||
|
Strategies to try:
|
||||||
|
- Cache "is surface" "is sky" "is cave" at generator level, then looking x,z against cached values to find whether the newly requested chunk is surface or not
|
||||||
@ -4,4 +4,5 @@
|
|||||||
- @subpage biomeselection
|
- @subpage biomeselection
|
||||||
- @subpage biomegenerationproblems
|
- @subpage biomegenerationproblems
|
||||||
- @subpage terraingenerationprocess
|
- @subpage terraingenerationprocess
|
||||||
- @subpage voxelgenideas
|
- @subpage voxelgenideas
|
||||||
|
- @subpage chunkgenoptimizations
|
||||||
@ -914,6 +914,22 @@ Update default resolution in config
|
|||||||
Fix main menu ui test
|
Fix main menu ui test
|
||||||
Refactor math utils to spatial math utils to make room for more fundamental utils
|
Refactor math utils to spatial math utils to make room for more fundamental utils
|
||||||
|
|
||||||
|
(10/29/2024)
|
||||||
|
Begin drawcellmanager rewrite
|
||||||
|
|
||||||
|
(10/30/2024)
|
||||||
|
Integrate transvoxel algorithm
|
||||||
|
Document NetArranger
|
||||||
|
Break out datastructures library
|
||||||
|
|
||||||
|
(10/31/2024)
|
||||||
|
Fix some transvoxel bugs
|
||||||
|
Optimizations
|
||||||
|
Refactoring generator code
|
||||||
|
|
||||||
|
(11/01/2024)
|
||||||
|
Optimizations
|
||||||
|
Fix transvoxel xnzn edge generation
|
||||||
|
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|||||||
43
pom.xml
43
pom.xml
@ -305,7 +305,15 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.studiorailgun</groupId>
|
<groupId>io.github.studiorailgun</groupId>
|
||||||
<artifactId>MathUtils</artifactId>
|
<artifactId>MathUtils</artifactId>
|
||||||
<version>1.0.1</version>
|
<version>1.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--DataStructures-->
|
||||||
|
<!--License: MIT-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.studiorailgun</groupId>
|
||||||
|
<artifactId>DataStructures</artifactId>
|
||||||
|
<version>1.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
@ -440,6 +448,24 @@
|
|||||||
</arguments>
|
</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>Run Net Arranger</id>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>exec</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<executable>java.exe</executable>
|
||||||
|
<arguments>
|
||||||
|
<argument>-jar</argument>
|
||||||
|
<argument>NetArranger.jar</argument>
|
||||||
|
</arguments>
|
||||||
|
<successCodes>
|
||||||
|
<successCode>0</successCode>
|
||||||
|
<successCode>1</successCode>
|
||||||
|
</successCodes>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
@ -452,6 +478,20 @@
|
|||||||
<!-- To execute this profile, run a command like "mvn test -P integration" -->
|
<!-- To execute this profile, run a command like "mvn test -P integration" -->
|
||||||
<profile>
|
<profile>
|
||||||
<id>integration</id>
|
<id>integration</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.2</version>
|
||||||
|
<configuration>
|
||||||
|
<!--If you want the logs to throw exceptions on opengl errors, remove the "n" after .jar=t-->
|
||||||
|
<argLine>-javaagent:./lwjglx-debug-1.0.0.jar=t;o=trace.log</argLine>
|
||||||
|
<forkCount>0</forkCount>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
<properties>
|
<properties>
|
||||||
<!--The tests to run-->
|
<!--The tests to run-->
|
||||||
<groups>fast,unit,integration</groups>
|
<groups>fast,unit,integration</groups>
|
||||||
@ -471,6 +511,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<!--If you want the logs to throw exceptions on opengl errors, remove the "n" after .jar=t-->
|
<!--If you want the logs to throw exceptions on opengl errors, remove the "n" after .jar=t-->
|
||||||
<argLine>-javaagent:./lwjglx-debug-1.0.0.jar=t;o=trace.log</argLine>
|
<argLine>-javaagent:./lwjglx-debug-1.0.0.jar=t;o=trace.log</argLine>
|
||||||
|
<forkCount>0</forkCount>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -78,7 +79,7 @@ public class FluidCellManager {
|
|||||||
*/
|
*/
|
||||||
public FluidCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
|
public FluidCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
|
||||||
if(Globals.clientWorldData != null){
|
if(Globals.clientWorldData != null){
|
||||||
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
|
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / ServerTerrainChunk.CHUNK_DIMENSION * 1.0f);
|
||||||
}
|
}
|
||||||
cells = new HashSet<FluidCell>();
|
cells = new HashSet<FluidCell>();
|
||||||
hasNotRequested = new HashSet<String>();
|
hasNotRequested = new HashSet<String>();
|
||||||
@ -209,24 +210,55 @@ public class FluidCellManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the manager has not requested a cell yet
|
||||||
|
* @return true if a cell has not been requested yet, false otherwise
|
||||||
|
*/
|
||||||
public boolean containsUnrequestedCell(){
|
public boolean containsUnrequestedCell(){
|
||||||
return hasNotRequested.size() > 0;
|
return hasNotRequested.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of unrequested cells
|
||||||
|
* @return The number of unrequested cells
|
||||||
|
*/
|
||||||
|
public int getUnrequestedSize(){
|
||||||
|
return hasNotRequested.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the manager has a cell that is not drawable
|
||||||
|
* @return true if there is an undrawable cell, false otherwise
|
||||||
|
*/
|
||||||
public boolean containsUndrawableCell(){
|
public boolean containsUndrawableCell(){
|
||||||
return undrawable.size() > 0;
|
return undrawable.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of undrawable cells
|
||||||
|
* @return The number of undrawable cells
|
||||||
|
*/
|
||||||
|
public int getUndrawableSize(){
|
||||||
|
return undrawable.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the manager has a cell that is updateable
|
||||||
|
* @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 real space into cell space
|
||||||
|
* @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 / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -321,9 +353,10 @@ public class FluidCellManager {
|
|||||||
* Updates cells that need updating in this manager
|
* Updates cells that need updating in this manager
|
||||||
*/
|
*/
|
||||||
public void update(){
|
public void update(){
|
||||||
|
Globals.profiler.beginCpuSample("FluidCellManager.update");
|
||||||
calculateDeltas();
|
calculateDeltas();
|
||||||
if(update){
|
if(update){
|
||||||
if(containsUnrequestedCell() && !containsUndrawableCell()){
|
if(containsUnrequestedCell()){
|
||||||
updateUnrequestedCell();
|
updateUnrequestedCell();
|
||||||
} else if(containsUndrawableCell()){
|
} else if(containsUndrawableCell()){
|
||||||
makeCellDrawable();
|
makeCellDrawable();
|
||||||
@ -331,6 +364,7 @@ public class FluidCellManager {
|
|||||||
updateCellModel();
|
updateCellModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -83,6 +83,7 @@ public class ClientFoliageManager {
|
|||||||
* @param worldPos The world position
|
* @param worldPos The world position
|
||||||
*/
|
*/
|
||||||
private void updatePosition(Vector3i worldPos){
|
private void updatePosition(Vector3i worldPos){
|
||||||
|
Globals.profiler.beginCpuSample("ClientFoliageManager.updatePosition");
|
||||||
FoliageChunk foundChunk = null;
|
FoliageChunk foundChunk = null;
|
||||||
for(FoliageChunk chunk : chunkUpdateCache){
|
for(FoliageChunk chunk : chunkUpdateCache){
|
||||||
if(chunk.getWorldPos().equals(worldPos)){
|
if(chunk.getWorldPos().equals(worldPos)){
|
||||||
@ -98,7 +99,8 @@ public class ClientFoliageManager {
|
|||||||
} else {
|
} else {
|
||||||
chunkUpdateCache.remove(foundChunk);
|
chunkUpdateCache.remove(foundChunk);
|
||||||
}
|
}
|
||||||
foundChunk.updateCells();
|
foundChunk.updateCells(false);
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,7 +132,7 @@ public class ClientFoliageManager {
|
|||||||
public boolean dependenciesAreReady(){
|
public boolean dependenciesAreReady(){
|
||||||
return
|
return
|
||||||
Globals.clientWorldData != null &&
|
Globals.clientWorldData != null &&
|
||||||
Globals.drawCellManager != null &&
|
Globals.clientDrawCellManager != null &&
|
||||||
Globals.playerEntity != null
|
Globals.playerEntity != null
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -142,7 +144,7 @@ public class ClientFoliageManager {
|
|||||||
public void evaluateChunk(Vector3i worldPos){
|
public void evaluateChunk(Vector3i worldPos){
|
||||||
for(FoliageChunk chunk : chunkUpdateCache){
|
for(FoliageChunk chunk : chunkUpdateCache){
|
||||||
if(chunk.getWorldPos().equals(worldPos)){
|
if(chunk.getWorldPos().equals(worldPos)){
|
||||||
chunk.updateCells();
|
chunk.updateCells(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -212,7 +212,7 @@ public class FoliageCell {
|
|||||||
if(voxelPosition.y + 1 >= ServerTerrainChunk.CHUNK_DIMENSION){
|
if(voxelPosition.y + 1 >= ServerTerrainChunk.CHUNK_DIMENSION){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!Globals.drawCellManager.generatedPhysics(worldPosition)){
|
if(!Globals.clientDrawCellManager.isFullLOD(worldPosition)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
||||||
|
|||||||
@ -34,6 +34,11 @@ public class FoliageChunk {
|
|||||||
*/
|
*/
|
||||||
static final double HALF_RES_DIST = 30;
|
static final double HALF_RES_DIST = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks whether this chunk contains a foliage voxel or not
|
||||||
|
*/
|
||||||
|
boolean containsFoliageVoxel = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The octree holding all the chunks to evaluate
|
* The octree holding all the chunks to evaluate
|
||||||
*/
|
*/
|
||||||
@ -75,27 +80,56 @@ public class FoliageChunk {
|
|||||||
this.currentChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
this.currentChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||||
// //evaluate top cells if chunk above this one exists
|
// //evaluate top cells if chunk above this one exists
|
||||||
this.aboveChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0));
|
this.aboveChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0));
|
||||||
this.updateCells();
|
this.updateCells(true);
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates all cells in the chunk
|
* Updates all cells in the chunk
|
||||||
|
* @param force true if should ignore cache, false otherwise
|
||||||
*/
|
*/
|
||||||
public void updateCells(){
|
public void updateCells(boolean force){
|
||||||
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
||||||
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
//re-evaluate whether contains foliage voxel or not
|
||||||
//the sets to iterate through
|
if(force){
|
||||||
boolean updated = true;
|
this.containsFoliageVoxel = checkContainsFoliageVoxel();
|
||||||
int attempts = 0;
|
}
|
||||||
while(updated && attempts < 3){
|
if(force || containsFoliageVoxel){
|
||||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
updated = this.recursivelyUpdateCells(rootNode, playerPos);
|
//the sets to iterate through
|
||||||
attempts++;
|
boolean updated = true;
|
||||||
|
int attempts = 0;
|
||||||
|
while(updated && attempts < 3){
|
||||||
|
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||||
|
updated = this.recursivelyUpdateCells(rootNode, playerPos);
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the chunk contains a foliage voxel or not
|
||||||
|
* @return true if contains foliage voxel, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean checkContainsFoliageVoxel(){
|
||||||
|
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(this.getWorldPos());
|
||||||
|
if(data == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
||||||
|
for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){
|
||||||
|
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
||||||
|
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(new Vector3i(x,y,z))).getAmbientFoliage();
|
||||||
|
if(foliageTypesSupported != null && foliageTypesSupported.size() > 0){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively update child nodes
|
* Recursively update child nodes
|
||||||
* @param node The root node
|
* @param node The root node
|
||||||
@ -104,6 +138,7 @@ public class FoliageChunk {
|
|||||||
private boolean recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
private boolean recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
||||||
boolean updated = false;
|
boolean updated = false;
|
||||||
if(this.shouldSplit(playerPos, node)){
|
if(this.shouldSplit(playerPos, node)){
|
||||||
|
Globals.profiler.beginCpuSample("FoliageChunk.split");
|
||||||
//perform op
|
//perform op
|
||||||
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
||||||
|
|
||||||
@ -119,8 +154,10 @@ public class FoliageChunk {
|
|||||||
);
|
);
|
||||||
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel()));
|
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel()));
|
||||||
});
|
});
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if(this.shouldJoin(playerPos, node)) {
|
} else if(this.shouldJoin(playerPos, node)) {
|
||||||
|
// Globals.profiler.beginCpuSample("FoliageChunk.join");
|
||||||
//perform op
|
//perform op
|
||||||
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
||||||
|
|
||||||
@ -129,9 +166,12 @@ public class FoliageChunk {
|
|||||||
|
|
||||||
//do creations
|
//do creations
|
||||||
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel()));
|
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel()));
|
||||||
|
// Globals.profiler.endCpuSample();
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if(shouldGenerate(playerPos, node)){
|
} else if(shouldGenerate(playerPos, node)){
|
||||||
|
// Globals.profiler.beginCpuSample("FoliageChunk.generate");
|
||||||
node.getData().generate();
|
node.getData().generate();
|
||||||
|
// Globals.profiler.endCpuSample();
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if(!node.isLeaf()){
|
} else if(!node.isLeaf()){
|
||||||
List<ChunkTreeNode<FoliageCell>> children = new LinkedList<ChunkTreeNode<FoliageCell>>(node.getChildren());
|
List<ChunkTreeNode<FoliageCell>> children = new LinkedList<ChunkTreeNode<FoliageCell>>(node.getChildren());
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import org.joml.Vector3d;
|
|||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client's data on the world
|
* Client's data on the world
|
||||||
*/
|
*/
|
||||||
@ -31,8 +33,6 @@ public class ClientWorldData {
|
|||||||
Vector3f worldMinPoint;
|
Vector3f worldMinPoint;
|
||||||
Vector3f worldMaxPoint;
|
Vector3f worldMaxPoint;
|
||||||
|
|
||||||
int dynamicInterpolationRatio;
|
|
||||||
|
|
||||||
float randomDampener;
|
float randomDampener;
|
||||||
|
|
||||||
|
|
||||||
@ -42,13 +42,11 @@ public class ClientWorldData {
|
|||||||
public ClientWorldData(
|
public ClientWorldData(
|
||||||
Vector3f worldMinPoint,
|
Vector3f worldMinPoint,
|
||||||
Vector3f worldMaxPoint,
|
Vector3f worldMaxPoint,
|
||||||
int dynamicInterpolationRatio,
|
|
||||||
float randomDampener,
|
float randomDampener,
|
||||||
int worldDiscreteSize
|
int worldDiscreteSize
|
||||||
) {
|
) {
|
||||||
this.worldMinPoint = worldMinPoint;
|
this.worldMinPoint = worldMinPoint;
|
||||||
this.worldMaxPoint = worldMaxPoint;
|
this.worldMaxPoint = worldMaxPoint;
|
||||||
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
|
||||||
this.randomDampener = randomDampener;
|
this.randomDampener = randomDampener;
|
||||||
this.worldDiscreteSize = worldDiscreteSize;
|
this.worldDiscreteSize = worldDiscreteSize;
|
||||||
}
|
}
|
||||||
@ -64,10 +62,6 @@ public class ClientWorldData {
|
|||||||
return worldMaxPoint;
|
return worldMaxPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDynamicInterpolationRatio() {
|
|
||||||
return dynamicInterpolationRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getRandomDampener() {
|
public float getRandomDampener() {
|
||||||
return randomDampener;
|
return randomDampener;
|
||||||
}
|
}
|
||||||
@ -78,11 +72,11 @@ public class ClientWorldData {
|
|||||||
|
|
||||||
|
|
||||||
public int convertRealToChunkSpace(double real){
|
public int convertRealToChunkSpace(double real){
|
||||||
return (int)Math.floor(real / dynamicInterpolationRatio);
|
return (int)Math.floor(real / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float convertChunkToRealSpace(int chunk){
|
public float convertChunkToRealSpace(int chunk){
|
||||||
return chunk * dynamicInterpolationRatio;
|
return chunk * ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int convertRealToWorld(double real){
|
public int convertRealToWorld(double real){
|
||||||
|
|||||||
@ -166,7 +166,7 @@ public class ClientSimulation {
|
|||||||
* Loads terrain that is in queue
|
* Loads terrain that is in queue
|
||||||
*/
|
*/
|
||||||
public void loadTerrain(){
|
public void loadTerrain(){
|
||||||
Globals.profiler.beginCpuSample("load terrain");
|
Globals.profiler.beginCpuSample("ClientSimulation.loadTerrain");
|
||||||
if(Globals.clientTerrainManager != null){
|
if(Globals.clientTerrainManager != null){
|
||||||
Globals.clientTerrainManager.handleMessages();
|
Globals.clientTerrainManager.handleMessages();
|
||||||
updateTerrainCellManager();
|
updateTerrainCellManager();
|
||||||
@ -185,9 +185,9 @@ public class ClientSimulation {
|
|||||||
///
|
///
|
||||||
/// C L I E N T C E L L M A N A G E R
|
/// C L I E N T C E L L M A N A G E R
|
||||||
///
|
///
|
||||||
if(Globals.drawCellManager != null && Globals.clientWorldData != null){
|
if(Globals.clientDrawCellManager != null && Globals.clientWorldData != null){
|
||||||
//Cell manager do your things
|
//Cell manager do your things
|
||||||
Globals.drawCellManager.update();
|
Globals.clientDrawCellManager.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,31 @@ public class ChunkData {
|
|||||||
//Used in DrawCell to keep track of which positions to invalidate
|
//Used in DrawCell to keep track of which positions to invalidate
|
||||||
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The word x coordinate
|
||||||
|
*/
|
||||||
|
int worldX;
|
||||||
|
/**
|
||||||
|
* The word y coordinate
|
||||||
|
*/
|
||||||
|
int worldY;
|
||||||
|
/**
|
||||||
|
* The word z coordinate
|
||||||
|
*/
|
||||||
|
int worldZ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a chunk data
|
||||||
|
* @param worldX The word x coordinate
|
||||||
|
* @param worldY The word y coordinate
|
||||||
|
* @param worldZ The word z coordinate
|
||||||
|
*/
|
||||||
|
public ChunkData(int worldX, int worldY, int worldZ){
|
||||||
|
this.worldX = worldX;
|
||||||
|
this.worldY = worldY;
|
||||||
|
this.worldZ = worldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the voxel type array in this container
|
* Gets the voxel type array in this container
|
||||||
@ -178,5 +203,13 @@ public class ChunkData {
|
|||||||
return position.x + "_" + position.y + "_" + position.z;
|
return position.x + "_" + position.y + "_" + position.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the world position of the chunk data
|
||||||
|
* @return The world position
|
||||||
|
*/
|
||||||
|
public Vector3i getWorldPos(){
|
||||||
|
return new Vector3i(worldX,worldY,worldZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.HashUtils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acts as a cache in front of terrain model to streamline receiving chunks
|
* Acts as a cache in front of terrain model to streamline receiving chunks
|
||||||
@ -17,16 +19,21 @@ public class ClientTerrainCache {
|
|||||||
//cache capacity
|
//cache capacity
|
||||||
int cacheSize;
|
int cacheSize;
|
||||||
//the map of chunk key -> chunk data
|
//the map of chunk key -> chunk data
|
||||||
Map<String,ChunkData> cacheMap = new ConcurrentHashMap<String,ChunkData>();
|
Map<Long,ChunkData> cacheMap = new ConcurrentHashMap<Long,ChunkData>();
|
||||||
//the list of keys in the cache
|
//the list of keys in the cache
|
||||||
List<String> cacheList = new CopyOnWriteArrayList<String>();
|
List<Long> cacheList = new CopyOnWriteArrayList<Long>();
|
||||||
//A map of chunk to its world position
|
//A map of chunk to its world position
|
||||||
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>();
|
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map tracking chunks that have been requested
|
||||||
|
*/
|
||||||
|
Map<Long,Boolean> requestedChunks = new ConcurrentHashMap<Long,Boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param cacheSize The capacity of the cache
|
* @param cacheSize The capacity of the cache
|
||||||
*/
|
*/
|
||||||
public ClientTerrainCache(int cacheSize){
|
public ClientTerrainCache(int cacheSize){
|
||||||
this.cacheSize = cacheSize;
|
this.cacheSize = cacheSize;
|
||||||
}
|
}
|
||||||
@ -42,8 +49,10 @@ public class ClientTerrainCache {
|
|||||||
cacheMap.put(getKey(worldX,worldY,worldZ),chunkData);
|
cacheMap.put(getKey(worldX,worldY,worldZ),chunkData);
|
||||||
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
||||||
while(cacheList.size() > cacheSize){
|
while(cacheList.size() > cacheSize){
|
||||||
String currentChunk = cacheList.remove(0);
|
Long currentChunk = cacheList.remove(0);
|
||||||
cacheMap.remove(currentChunk);
|
ChunkData data = cacheMap.remove(currentChunk);
|
||||||
|
Vector3i worldPos = data.getWorldPos();
|
||||||
|
requestedChunks.remove(getKey(worldPos.x,worldPos.y,worldPos.z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +73,8 @@ public class ClientTerrainCache {
|
|||||||
* @param worldZ The z world position
|
* @param worldZ The z world position
|
||||||
* @return The cache key
|
* @return The cache key
|
||||||
*/
|
*/
|
||||||
public String getKey(int worldX, int worldY, int worldZ){
|
public long getKey(int worldX, int worldY, int worldZ){
|
||||||
return worldX + "_" + worldY + "_" + worldZ;
|
return HashUtils.cantorHash(worldX, worldY, worldZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,5 +119,34 @@ public class ClientTerrainCache {
|
|||||||
public Vector3i getChunkPosition(ChunkData chunk){
|
public Vector3i getChunkPosition(ChunkData chunk){
|
||||||
return chunkPositionMap.get(chunk);
|
return chunkPositionMap.get(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of cells that have been requested
|
||||||
|
* @return The number of cells that have been requested
|
||||||
|
*/
|
||||||
|
public int getRequestedCellCount(){
|
||||||
|
return this.requestedChunks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a chunk has been requested or not
|
||||||
|
* @param worldX The x coordinate in the world
|
||||||
|
* @param worldY The y coordinate in the world
|
||||||
|
* @param worldZ The z coordinate in the world
|
||||||
|
* @return true if it has been requested, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasRequested(int worldX, int worldY, int worldZ){
|
||||||
|
return this.requestedChunks.containsKey(getKey(worldX, worldY, worldZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a chunk as requested
|
||||||
|
* @param worldX The x coordinate in the world
|
||||||
|
* @param worldY The y coordinate in the world
|
||||||
|
* @param worldZ The z coordinate in the world
|
||||||
|
*/
|
||||||
|
public void markAsRequested(int worldX, int worldY, int worldZ){
|
||||||
|
this.requestedChunks.put(getKey(worldX, worldY, worldZ),true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,690 @@
|
|||||||
|
package electrosphere.client.terrain.cells;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.terrain.cells.DrawCell.DrawCellFace;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.util.ds.octree.WorldOctTree;
|
||||||
|
import electrosphere.util.ds.octree.WorldOctTree.FloatingChunkTreeNode;
|
||||||
|
import electrosphere.util.math.GeomUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages draw cells on the client
|
||||||
|
*/
|
||||||
|
public class ClientDrawCellManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of times to try updating per frame. Lower this to reduce lag but slow down terrain mesh generation.
|
||||||
|
*/
|
||||||
|
static final int UPDATE_ATTEMPTS_PER_FRAME = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance to draw at full resolution
|
||||||
|
*/
|
||||||
|
public static final double FULL_RES_DIST = 5 * ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance for half resolution
|
||||||
|
*/
|
||||||
|
public static final double HALF_RES_DIST = 15 * ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The octree holding all the chunks to evaluate
|
||||||
|
*/
|
||||||
|
WorldOctTree<DrawCell> chunkTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks whether the cell manager updated last frame or not
|
||||||
|
*/
|
||||||
|
boolean updatedLastFrame = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls whether the client draw cell manager should update or not
|
||||||
|
*/
|
||||||
|
boolean shouldUpdate = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The voxel texture atlas
|
||||||
|
*/
|
||||||
|
VoxelTextureAtlas textureAtlas;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimensions of the world
|
||||||
|
*/
|
||||||
|
int worldDim = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks the number of currently valid cells (ie didn't require an update this frame)
|
||||||
|
*/
|
||||||
|
int validCellCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of maximum resolution chunks
|
||||||
|
*/
|
||||||
|
int maxResCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of half resolution chunks
|
||||||
|
*/
|
||||||
|
int halfResCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of generated chunks
|
||||||
|
*/
|
||||||
|
int generated = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param voxelTextureAtlas The voxel texture atlas
|
||||||
|
* @param worldDim The size of the world in chunks
|
||||||
|
*/
|
||||||
|
public ClientDrawCellManager(VoxelTextureAtlas voxelTextureAtlas, int worldDim){
|
||||||
|
this.chunkTree = new WorldOctTree<DrawCell>(new Vector3i(0,0,0), new Vector3i(worldDim, worldDim, worldDim));
|
||||||
|
this.worldDim = worldDim;
|
||||||
|
this.textureAtlas = voxelTextureAtlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates all cells in the chunk
|
||||||
|
*/
|
||||||
|
public void update(){
|
||||||
|
Globals.profiler.beginCpuSample("ClientDrawCellManager.updateCells");
|
||||||
|
if(shouldUpdate && Globals.playerEntity != null){
|
||||||
|
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
|
//the sets to iterate through
|
||||||
|
updatedLastFrame = true;
|
||||||
|
int attempts = 0;
|
||||||
|
validCellCount = 0;
|
||||||
|
while(updatedLastFrame && attempts < UPDATE_ATTEMPTS_PER_FRAME){
|
||||||
|
FloatingChunkTreeNode<DrawCell> rootNode = this.chunkTree.getRoot();
|
||||||
|
updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos);
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively update child nodes
|
||||||
|
* @param node The root node
|
||||||
|
* @param playerPos The player's position
|
||||||
|
* @return true if there is work remaining to be done, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean recursivelyUpdateCells(FloatingChunkTreeNode<DrawCell> node, Vector3d playerPos){
|
||||||
|
Vector3d playerRealPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
|
boolean updated = false;
|
||||||
|
if(this.shouldSplit(playerPos, node)){
|
||||||
|
Globals.profiler.beginCpuSample("ClientDrawCellManager.split");
|
||||||
|
//perform op
|
||||||
|
FloatingChunkTreeNode<DrawCell> container = chunkTree.split(node);
|
||||||
|
|
||||||
|
//do deletions
|
||||||
|
this.recursivelyDestroy(node);
|
||||||
|
|
||||||
|
//do creations
|
||||||
|
container.getChildren().forEach(child -> {
|
||||||
|
Vector3i cellWorldPos = new Vector3i(
|
||||||
|
child.getMinBound().x,
|
||||||
|
child.getMinBound().y,
|
||||||
|
child.getMinBound().z
|
||||||
|
);
|
||||||
|
DrawCell drawCell = DrawCell.generateTerrainCell(cellWorldPos);
|
||||||
|
child.convertToLeaf(drawCell);
|
||||||
|
});
|
||||||
|
|
||||||
|
//update neighbors
|
||||||
|
this.conditionalUpdateAdjacentNodes(container, container.getChildren().get(0).getLevel());
|
||||||
|
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
updated = true;
|
||||||
|
} else if(this.shouldJoin(playerPos, node)) {
|
||||||
|
Globals.profiler.beginCpuSample("ClientDrawCellManager.join");
|
||||||
|
//perform op
|
||||||
|
FloatingChunkTreeNode<DrawCell> newLeaf = chunkTree.join(node);
|
||||||
|
|
||||||
|
//do deletions
|
||||||
|
this.recursivelyDestroy(node);
|
||||||
|
|
||||||
|
//do creations
|
||||||
|
DrawCell drawCell = DrawCell.generateTerrainCell(node.getMinBound());
|
||||||
|
newLeaf.convertToLeaf(drawCell);
|
||||||
|
|
||||||
|
//update neighbors
|
||||||
|
this.conditionalUpdateAdjacentNodes(newLeaf, newLeaf.getLevel());
|
||||||
|
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
updated = true;
|
||||||
|
} else if(shouldRequest(playerPos, node)){
|
||||||
|
Globals.profiler.beginCpuSample("ClientDrawCellManager.request");
|
||||||
|
DrawCell cell = node.getData();
|
||||||
|
this.requestChunks(node);
|
||||||
|
cell.setHasRequested(true);
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
updated = true;
|
||||||
|
} else if(shouldGenerate(playerPos, node)){
|
||||||
|
Globals.profiler.beginCpuSample("ClientDrawCellManager.generate");
|
||||||
|
int lodLevel = this.getLODLevel(playerRealPos, node);
|
||||||
|
List<DrawCellFace> highResFaces = this.solveHighResFace(node);
|
||||||
|
if(containsDataToGenerate(node,highResFaces)){
|
||||||
|
node.getData().generateDrawableEntity(textureAtlas, lodLevel, highResFaces);
|
||||||
|
}
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
updated = true;
|
||||||
|
} else if(!node.isLeaf()){
|
||||||
|
this.validCellCount++;
|
||||||
|
List<FloatingChunkTreeNode<DrawCell>> children = new LinkedList<FloatingChunkTreeNode<DrawCell>>(node.getChildren());
|
||||||
|
for(FloatingChunkTreeNode<DrawCell> child : children){
|
||||||
|
boolean childUpdate = recursivelyUpdateCells(child, playerPos);
|
||||||
|
if(childUpdate == true){
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum distance from a node to a point
|
||||||
|
* @param pos the position to check against
|
||||||
|
* @param node the node
|
||||||
|
* @return the distance
|
||||||
|
*/
|
||||||
|
public double getMinDistance(Vector3d pos, FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
Vector3i min = node.getMinBound();
|
||||||
|
Vector3i max = node.getMaxBound();
|
||||||
|
return GeomUtils.getMinDistanceAABB(pos, Globals.clientWorldData.convertWorldToRealSpace(min), Globals.clientWorldData.convertWorldToRealSpace(max));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this should be split or not
|
||||||
|
* @param pos the player position
|
||||||
|
* @param node The node
|
||||||
|
* @return true if should split, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean shouldSplit(Vector3d pos, FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
//breaking out into dedicated function so can add case handling ie if we want
|
||||||
|
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||||
|
return
|
||||||
|
node.isLeaf() &&
|
||||||
|
node.canSplit() &&
|
||||||
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() < this.chunkTree.getMaxLevel() - 1 &&
|
||||||
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() < this.chunkTree.getMaxLevel() &&
|
||||||
|
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the LOD level of the draw cell
|
||||||
|
* @param pos The position of the cell
|
||||||
|
* @param node The node to consider
|
||||||
|
* @return -1 if outside of render range, -1 if the node is not a valid draw cell leaf, otherwise returns the LOD level
|
||||||
|
*/
|
||||||
|
private int getLODLevel(Vector3d pos, FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
return this.chunkTree.getMaxLevel() - node.getLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solves which face (if any) is the high res face for a LOD chunk
|
||||||
|
* @param node The node for the chunk
|
||||||
|
* @return The face if there is a higher resolution face, null otherwise
|
||||||
|
*/
|
||||||
|
private List<DrawCellFace> solveHighResFace(FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
//don't bother to check if it's a full res chunk
|
||||||
|
if(node.getLevel() == this.chunkTree.getMaxLevel()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int lodMultiplitier = this.chunkTree.getMaxLevel() - node.getLevel() + 1;
|
||||||
|
int spacing = (int)Math.pow(2,lodMultiplitier);
|
||||||
|
List<DrawCellFace> faces = new LinkedList<DrawCellFace>();
|
||||||
|
if(node.getMinBound().x - 1 >= 0){
|
||||||
|
FloatingChunkTreeNode<DrawCell> xNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(-1,1,1), false);
|
||||||
|
if(xNegNode != null && xNegNode.getLevel() > node.getLevel()){
|
||||||
|
faces.add(DrawCellFace.X_NEGATIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMinBound().y - 1 >= 0){
|
||||||
|
FloatingChunkTreeNode<DrawCell> yNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,-1,1), false);
|
||||||
|
if(yNegNode != null && yNegNode.getLevel() > node.getLevel()){
|
||||||
|
faces.add(DrawCellFace.Y_NEGATIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMinBound().z - 1 >= 0){
|
||||||
|
FloatingChunkTreeNode<DrawCell> zNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,1,-1), false);
|
||||||
|
if(zNegNode != null && zNegNode.getLevel() > node.getLevel()){
|
||||||
|
faces.add(DrawCellFace.Z_NEGATIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMaxBound().x + spacing + 1 < this.worldDim){
|
||||||
|
FloatingChunkTreeNode<DrawCell> xPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(spacing + 1,1,1), false);
|
||||||
|
if(xPosNode != null && xPosNode.getLevel() > node.getLevel()){
|
||||||
|
faces.add(DrawCellFace.X_POSITIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMaxBound().y + spacing + 1 < this.worldDim){
|
||||||
|
FloatingChunkTreeNode<DrawCell> yPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,spacing + 1,1), false);
|
||||||
|
if(yPosNode != null && yPosNode.getLevel() > node.getLevel()){
|
||||||
|
faces.add(DrawCellFace.Y_POSITIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMaxBound().z + spacing + 1 < this.worldDim){
|
||||||
|
FloatingChunkTreeNode<DrawCell> zPosNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(1,1,spacing + 1), false);
|
||||||
|
if(zPosNode != null && zPosNode.getLevel() > node.getLevel()){
|
||||||
|
faces.add(DrawCellFace.Z_POSITIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(faces.size() > 0){
|
||||||
|
return faces;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditionally updates all adjacent nodes if their level would require transition cells in the voxel rasterization
|
||||||
|
* @param node The node to search from adjacencies from
|
||||||
|
* @param level The level to check against
|
||||||
|
*/
|
||||||
|
private void conditionalUpdateAdjacentNodes(FloatingChunkTreeNode<DrawCell> node, int level){
|
||||||
|
//don't bother to check if it's a lowest-res chunk
|
||||||
|
if(this.chunkTree.getMaxLevel() - level > DrawCell.LOWEST_LOD){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(node.getMinBound().x - 1 >= 0){
|
||||||
|
FloatingChunkTreeNode<DrawCell> xNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(-1,0,0), false);
|
||||||
|
if(xNegNode != null && xNegNode.getLevel() < level){
|
||||||
|
xNegNode.getData().setHasGenerated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMinBound().y - 1 >= 0){
|
||||||
|
FloatingChunkTreeNode<DrawCell> yNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(0,-1,0), false);
|
||||||
|
if(yNegNode != null && yNegNode.getLevel() < level){
|
||||||
|
yNegNode.getData().setHasGenerated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMinBound().z - 1 >= 0){
|
||||||
|
FloatingChunkTreeNode<DrawCell> zNegNode = this.chunkTree.search(new Vector3i(node.getMinBound()).add(0,0,-1), false);
|
||||||
|
if(zNegNode != null && zNegNode.getLevel() < level){
|
||||||
|
zNegNode.getData().setHasGenerated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMaxBound().x + 1 < this.worldDim){
|
||||||
|
FloatingChunkTreeNode<DrawCell> xPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(1,-1,-1), false);
|
||||||
|
if(xPosNode != null && xPosNode.getLevel() < level){
|
||||||
|
xPosNode.getData().setHasGenerated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMaxBound().y + 1 < this.worldDim){
|
||||||
|
FloatingChunkTreeNode<DrawCell> yPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(-1,1,-1), false);
|
||||||
|
if(yPosNode != null && yPosNode.getLevel() < level){
|
||||||
|
yPosNode.getData().setHasGenerated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.getMaxBound().z + 1 < this.worldDim){
|
||||||
|
FloatingChunkTreeNode<DrawCell> zPosNode = this.chunkTree.search(new Vector3i(node.getMaxBound()).add(-1,-1,1), false);
|
||||||
|
if(zPosNode != null && zPosNode.getLevel() < level){
|
||||||
|
zPosNode.getData().setHasGenerated(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this should be joined or not
|
||||||
|
* @param pos the player position
|
||||||
|
* @param node The node
|
||||||
|
* @return true if should be joined, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean shouldJoin(Vector3d pos, FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
//breaking out into dedicated function so can add case handling ie if we want
|
||||||
|
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||||
|
return
|
||||||
|
node.getLevel() > 0 &&
|
||||||
|
!node.isLeaf() &&
|
||||||
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel() &&
|
||||||
|
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
this.getMinDistance(pos, node) > HALF_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this cell should request chunk data
|
||||||
|
* @param pos the player's position
|
||||||
|
* @param node the node
|
||||||
|
* @return true if should request chunk data, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean shouldRequest(Vector3d pos, FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
return
|
||||||
|
node.isLeaf() &&
|
||||||
|
node.getData() != null &&
|
||||||
|
!node.getData().hasRequested() &&
|
||||||
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel()
|
||||||
|
// &&
|
||||||
|
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel() - 1
|
||||||
|
&&
|
||||||
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this cell should generate
|
||||||
|
* @param pos the player's position
|
||||||
|
* @param node the node
|
||||||
|
* @return true if should generate, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean shouldGenerate(Vector3d pos, FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
return
|
||||||
|
node.isLeaf() &&
|
||||||
|
node.getData() != null &&
|
||||||
|
!node.getData().hasGenerated() &&
|
||||||
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel()
|
||||||
|
// &&
|
||||||
|
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel() - 1
|
||||||
|
&&
|
||||||
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the node should have destroy called on it
|
||||||
|
* @param node The node
|
||||||
|
* @return true if should destroy, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean shouldDestroy(FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
return
|
||||||
|
node.getData() != null &&
|
||||||
|
node.getData().getEntity() != null
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the foliage chunk
|
||||||
|
*/
|
||||||
|
protected void destroy(){
|
||||||
|
this.recursivelyDestroy(this.chunkTree.getRoot());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively destroy a tree
|
||||||
|
* @param node The root of the tree
|
||||||
|
*/
|
||||||
|
private void recursivelyDestroy(FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
if(node.getChildren().size() > 0){
|
||||||
|
node.getChildren().forEach(child -> recursivelyDestroy(child));
|
||||||
|
}
|
||||||
|
if(node.getData() != null){
|
||||||
|
node.getData().destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the cell manager made an update last frame or not
|
||||||
|
* @return true if an update occurred, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean updatedLastFrame(){
|
||||||
|
return this.updatedLastFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the position is within the full LOD range
|
||||||
|
* @param worldPos The world position
|
||||||
|
* @return true if within full LOD range, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isFullLOD(Vector3i worldPos){
|
||||||
|
Vector3d playerRealPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
|
Vector3d chunkMin = Globals.clientWorldData.convertWorldToRealSpace(worldPos);
|
||||||
|
Vector3d chunkMax = Globals.clientWorldData.convertWorldToRealSpace(new Vector3i(worldPos).add(1,1,1));
|
||||||
|
return GeomUtils.getMinDistanceAABB(playerRealPos, chunkMin, chunkMax) <= FULL_RES_DIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evicts all cells
|
||||||
|
*/
|
||||||
|
public void evictAll(){
|
||||||
|
this.chunkTree.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a draw cell as updateable
|
||||||
|
* @param worldX The world x position
|
||||||
|
* @param worldY The world y position
|
||||||
|
* @param worldZ The world z position
|
||||||
|
*/
|
||||||
|
public void markUpdateable(float worldX, float worldY, float worldZ){
|
||||||
|
throw new Error("Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests all chunks for a given draw cell
|
||||||
|
* @param cell The cell
|
||||||
|
*/
|
||||||
|
private void requestChunks(WorldOctTree.FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
DrawCell cell = node.getData();
|
||||||
|
int lodMultiplitier = this.chunkTree.getMaxLevel() - node.getLevel() + 1;
|
||||||
|
for(int i = 0; i < 2 * lodMultiplitier; i++){
|
||||||
|
for(int j = 0; j < 2 * lodMultiplitier; j++){
|
||||||
|
for(int k = 0; k < 2 * lodMultiplitier; k++){
|
||||||
|
Vector3i posToCheck = new Vector3i(cell.getWorldPos()).add(i,j,k);
|
||||||
|
if(
|
||||||
|
posToCheck.x >= 0 &&
|
||||||
|
posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.y >= 0 &&
|
||||||
|
posToCheck.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.z >= 0 &&
|
||||||
|
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z)
|
||||||
|
){
|
||||||
|
//client should request chunk data from server for each chunk necessary to create the model
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + posToCheck);
|
||||||
|
Globals.clientTerrainManager.requestChunk(posToCheck.x, posToCheck.y, posToCheck.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if all chunk data required to generate this draw cell is present
|
||||||
|
* @param node The node
|
||||||
|
* @param highResFace The higher resolution face of a not-full-resolution chunk. Null if the chunk is max resolution or there is no higher resolution face for the current chunk
|
||||||
|
* @return true if all data is available, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean containsDataToGenerate(WorldOctTree.FloatingChunkTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
|
||||||
|
DrawCell cell = node.getData();
|
||||||
|
int lodMultiplitier = this.chunkTree.getMaxLevel() - node.getLevel() + 1;
|
||||||
|
for(int i = 0; i < 2 * lodMultiplitier; i++){
|
||||||
|
for(int j = 0; j < 2 * lodMultiplitier; j++){
|
||||||
|
for(int k = 0; k < 2 * lodMultiplitier; k++){
|
||||||
|
Vector3i posToCheck = new Vector3i(cell.getWorldPos()).add(i,j,k);
|
||||||
|
if(
|
||||||
|
posToCheck.x >= 0 &&
|
||||||
|
posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.y >= 0 &&
|
||||||
|
posToCheck.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.z >= 0 &&
|
||||||
|
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z)
|
||||||
|
){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(highResFaces != null){
|
||||||
|
for(DrawCellFace highResFace : highResFaces){
|
||||||
|
//x & y are in face-space
|
||||||
|
for(int x = 0; x < 2 * lodMultiplitier; x++){
|
||||||
|
for(int y = 0; y < 2 * lodMultiplitier; y++){
|
||||||
|
Vector3i posToCheck = null;
|
||||||
|
//implicitly performing transforms to adapt from face-space to world space
|
||||||
|
switch(highResFace){
|
||||||
|
case X_POSITIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(lodMultiplitier,x,y);
|
||||||
|
} break;
|
||||||
|
case X_NEGATIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(-1,x,y);
|
||||||
|
} break;
|
||||||
|
case Y_POSITIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x,lodMultiplitier,y);
|
||||||
|
} break;
|
||||||
|
case Y_NEGATIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x,-1,y);
|
||||||
|
} break;
|
||||||
|
case Z_POSITIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x,y,lodMultiplitier);
|
||||||
|
} break;
|
||||||
|
case Z_NEGATIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x,y,-1);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if(
|
||||||
|
posToCheck.x >= 0 &&
|
||||||
|
posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.y >= 0 &&
|
||||||
|
posToCheck.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.z >= 0 &&
|
||||||
|
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z)
|
||||||
|
){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the draw cell manager should update or not
|
||||||
|
* @param shouldUpdate true if should update, false otherwise
|
||||||
|
*/
|
||||||
|
public void setShouldUpdate(boolean shouldUpdate){
|
||||||
|
this.shouldUpdate = shouldUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the client draw cell manager should update or not
|
||||||
|
* @return true if should update, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean getShouldUpdate(){
|
||||||
|
return this.shouldUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of currently valid cells
|
||||||
|
* @return The number of currently valid cells
|
||||||
|
*/
|
||||||
|
public int getValidCellCount(){
|
||||||
|
return validCellCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the status of the draw cell manager
|
||||||
|
*/
|
||||||
|
public void updateStatus(){
|
||||||
|
maxResCount = 0;
|
||||||
|
halfResCount = 0;
|
||||||
|
generated = 0;
|
||||||
|
this.recursivelyCalculateStatus(this.chunkTree.getRoot());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively calculates the status of the manager
|
||||||
|
* @param node The root node
|
||||||
|
*/
|
||||||
|
private void recursivelyCalculateStatus(FloatingChunkTreeNode<DrawCell> node){
|
||||||
|
if(node.getLevel() == this.chunkTree.getMaxLevel() - 1){
|
||||||
|
halfResCount++;
|
||||||
|
}
|
||||||
|
if(node.getLevel() == this.chunkTree.getMaxLevel()){
|
||||||
|
maxResCount++;
|
||||||
|
}
|
||||||
|
if(node.getData() != null && node.getData().hasGenerated()){
|
||||||
|
generated++;
|
||||||
|
}
|
||||||
|
if(node.getChildren() != null && node.getChildren().size() > 0){
|
||||||
|
List<FloatingChunkTreeNode<DrawCell>> children = new LinkedList<FloatingChunkTreeNode<DrawCell>>(node.getChildren());
|
||||||
|
for(FloatingChunkTreeNode<DrawCell> child : children){
|
||||||
|
recursivelyCalculateStatus(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets The number of maximum resolution chunks
|
||||||
|
* @return The number of maximum resolution chunks
|
||||||
|
*/
|
||||||
|
public int getMaxResCount() {
|
||||||
|
return maxResCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets The number of half resolution chunks
|
||||||
|
* @return The number of half resolution chunks
|
||||||
|
*/
|
||||||
|
public int getHalfResCount() {
|
||||||
|
return halfResCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets The number of generated chunks
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getGenerated() {
|
||||||
|
return generated;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package electrosphere.client.terrain.cells;
|
package electrosphere.client.terrain.cells;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.joml.Quaterniond;
|
import org.joml.Quaterniond;
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
@ -10,6 +12,7 @@ import electrosphere.engine.Globals;
|
|||||||
import electrosphere.entity.ClientEntityUtils;
|
import electrosphere.entity.ClientEntityUtils;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.types.terrain.TerrainChunk;
|
import electrosphere.entity.types.terrain.TerrainChunk;
|
||||||
|
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
|
||||||
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
|
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,15 +42,57 @@ public class DrawCell {
|
|||||||
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];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An invalid LOD level
|
||||||
|
*/
|
||||||
|
public static final int INVALID_LOD_LEVEL = -1;
|
||||||
|
|
||||||
//the maximum detail LOD level
|
/**
|
||||||
|
* The maximum detail LOD level
|
||||||
|
*/
|
||||||
public static final int FULL_DETAIL_LOD = 0;
|
public static final int FULL_DETAIL_LOD = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The half detail lod level
|
||||||
|
*/
|
||||||
|
public static final int HALF_DETAIL_LOD = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lowest available LOD
|
||||||
|
*/
|
||||||
|
public static final int LOWEST_LOD = HALF_DETAIL_LOD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lod level of this draw cell
|
||||||
|
*/
|
||||||
|
int lodLevel = FULL_DETAIL_LOD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks whether the draw cell has requested its chunk data or not
|
||||||
|
*/
|
||||||
|
boolean hasRequested = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks whether the draw cell has generated its entity or not
|
||||||
|
*/
|
||||||
|
boolean hasGenerated = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initial voxel type encountered
|
||||||
|
*/
|
||||||
|
int initialVoxelType = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if there are multiple types of voxels in this chunk
|
||||||
|
*/
|
||||||
|
boolean multiVoxelType = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor
|
* Private constructor
|
||||||
*/
|
*/
|
||||||
DrawCell(){
|
private DrawCell(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,17 +111,35 @@ public class DrawCell {
|
|||||||
/**
|
/**
|
||||||
* Generates a drawable entity based on this chunk
|
* Generates a drawable entity based on this chunk
|
||||||
*/
|
*/
|
||||||
public void generateDrawableEntity(VoxelTextureAtlas atlas, int lod, DrawCellFace higherLODFace){
|
public void generateDrawableEntity(VoxelTextureAtlas atlas, int lod, List<DrawCellFace> higherLODFaces){
|
||||||
|
Globals.profiler.beginCpuSample("DrawCell.fillInData");
|
||||||
|
boolean success = this.fillInData(lod);
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
if(!success){
|
||||||
|
this.setHasRequested(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(modelEntity != null){
|
if(modelEntity != null){
|
||||||
Globals.clientScene.deregisterEntity(modelEntity);
|
Globals.clientScene.deregisterEntity(modelEntity);
|
||||||
}
|
}
|
||||||
this.fillInData();
|
|
||||||
TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, types, lod);
|
TransvoxelChunkData chunkData = new TransvoxelChunkData(weights, types, lod);
|
||||||
if(lod > FULL_DETAIL_LOD){
|
if(higherLODFaces != null){
|
||||||
|
for(DrawCellFace face : higherLODFaces){
|
||||||
|
Globals.profiler.beginCpuSample("DrawCell.fillInFaceData");
|
||||||
|
success = this.fillInFaceData(chunkData,face,lod);
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
if(!success){
|
||||||
|
this.setHasRequested(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(chunkData, lod, atlas);
|
if(lod == INVALID_LOD_LEVEL){
|
||||||
|
throw new Error("Trying to generate invalid LOD");
|
||||||
|
}
|
||||||
|
modelEntity = TerrainChunk.clientCreateTerrainChunkEntity(chunkData, lod, atlas, this.hasPolygons());
|
||||||
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos(), new Quaterniond());
|
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos(), new Quaterniond());
|
||||||
|
this.setHasGenerated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,147 +153,322 @@ public class DrawCell {
|
|||||||
worldPos.z * ChunkData.CHUNK_SIZE
|
worldPos.z * ChunkData.CHUNK_SIZE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the world-space position of the draw cell
|
||||||
|
* @return the world-space position
|
||||||
|
*/
|
||||||
|
protected Vector3i getWorldPos(){
|
||||||
|
return new Vector3i(worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys a drawcell including its physics
|
* Destroys a drawcell including its physics
|
||||||
*/
|
*/
|
||||||
public void destroy(){
|
public void destroy(){
|
||||||
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
||||||
collisionEngine.destroyPhysics(modelEntity);
|
if(modelEntity != null){
|
||||||
ClientEntityUtils.destroyEntity(modelEntity);
|
collisionEngine.destroyPhysics(modelEntity);
|
||||||
|
ClientEntityUtils.destroyEntity(modelEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the entity for the cell
|
||||||
|
* @return The entity if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public Entity getEntity(){
|
||||||
|
return modelEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills in the internal arrays of data for generate terrain models
|
* Fills in the internal arrays of data for generate terrain models
|
||||||
|
* @return true if the data was successfully filled, false otherwise
|
||||||
*/
|
*/
|
||||||
private void fillInData(){
|
private boolean fillInData(int lod){
|
||||||
//
|
int spacingFactor = (int)Math.pow(2,lod);
|
||||||
//fill in data
|
for(int x = 0; x < ChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||||
//
|
for(int y = 0; y < ChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||||
//main chunk
|
for(int z = 0; z < ChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
|
||||||
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(
|
||||||
for(int x = 0; x < ChunkData.CHUNK_SIZE; x++){
|
worldPos.x + (x * spacingFactor) / ChunkData.CHUNK_SIZE,
|
||||||
for(int y = 0; y < ChunkData.CHUNK_SIZE; y++){
|
worldPos.y + (y * spacingFactor) / ChunkData.CHUNK_SIZE,
|
||||||
for(int z = 0; z < ChunkData.CHUNK_SIZE; z++){
|
worldPos.z + (z * spacingFactor) / ChunkData.CHUNK_SIZE
|
||||||
weights[x][y][z] = currentChunk.getWeight(x,y,z);
|
);
|
||||||
types[x][y][z] = currentChunk.getType(x,y,z);
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
weights[x][y][z] = currentChunk.getWeight(
|
||||||
|
(x * spacingFactor) % ChunkData.CHUNK_SIZE,
|
||||||
|
(y * spacingFactor) % ChunkData.CHUNK_SIZE,
|
||||||
|
(z * spacingFactor) % ChunkData.CHUNK_SIZE
|
||||||
|
);
|
||||||
|
types[x][y][z] = currentChunk.getType(
|
||||||
|
(x * spacingFactor) % ChunkData.CHUNK_SIZE,
|
||||||
|
(y * spacingFactor) % ChunkData.CHUNK_SIZE,
|
||||||
|
(z * spacingFactor) % ChunkData.CHUNK_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
//checks to see if there is only one type of voxel in this chunk
|
||||||
|
if(!this.multiVoxelType){
|
||||||
|
if(this.initialVoxelType == -1){
|
||||||
|
this.initialVoxelType = types[x][y][z];
|
||||||
|
} else if(this.initialVoxelType != types[x][y][z]){
|
||||||
|
this.multiVoxelType = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//face X
|
return true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//face Y
|
|
||||||
if(worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
|
|
||||||
currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y + 1, worldPos.z);
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
for(int j = 0; j < ChunkData.CHUNK_SIZE; j++){
|
|
||||||
weights[i][ChunkData.CHUNK_SIZE][j] = currentChunk.getWeight(i, 0, j);
|
|
||||||
types[i][ChunkData.CHUNK_SIZE][j] = currentChunk.getType(i, 0, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
for(int j = 0; j < ChunkData.CHUNK_SIZE; j++){
|
|
||||||
weights[i][ChunkData.CHUNK_SIZE][j] = -1;
|
|
||||||
types[i][ChunkData.CHUNK_SIZE][j] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//face Z
|
|
||||||
if(worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
|
|
||||||
currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z + 1);
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
for(int j = 0; j < ChunkData.CHUNK_SIZE; j++){
|
|
||||||
weights[i][j][ChunkData.CHUNK_SIZE] = currentChunk.getWeight(i, j, 0);
|
|
||||||
types[i][j][ChunkData.CHUNK_SIZE] = currentChunk.getType(i, j, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
for(int j = 0; j < ChunkData.CHUNK_SIZE; j++){
|
|
||||||
weights[i][j][ChunkData.CHUNK_SIZE] = -1;
|
|
||||||
types[i][j][ChunkData.CHUNK_SIZE] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//edge X-Y
|
|
||||||
if(
|
|
||||||
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
|
||||||
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
|
||||||
){
|
|
||||||
currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z);
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
weights[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][i] = currentChunk.getWeight(0, 0, i);
|
|
||||||
types [ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][i] = currentChunk.getType(0, 0, i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
weights[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][i] = -1;
|
|
||||||
types [ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//edge X-Z
|
|
||||||
if(
|
|
||||||
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
|
||||||
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
|
||||||
){
|
|
||||||
currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y, worldPos.z + 1);
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
weights[ChunkData.CHUNK_SIZE][i][ChunkData.CHUNK_SIZE] = currentChunk.getWeight(0, i, 0);
|
|
||||||
types [ChunkData.CHUNK_SIZE][i][ChunkData.CHUNK_SIZE] = currentChunk.getType(0, i, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
weights[ChunkData.CHUNK_SIZE][i][ChunkData.CHUNK_SIZE] = -1;
|
|
||||||
types [ChunkData.CHUNK_SIZE][i][ChunkData.CHUNK_SIZE] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//edge Y-Z
|
|
||||||
if(
|
|
||||||
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
|
||||||
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
|
||||||
){
|
|
||||||
currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y + 1, worldPos.z + 1);
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
weights[i][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = currentChunk.getWeight(i, 0, 0);
|
|
||||||
types [i][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = currentChunk.getType(i, 0, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(int i = 0; i < ChunkData.CHUNK_SIZE; i++){
|
|
||||||
weights[i][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = -1;
|
|
||||||
types [i][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(
|
|
||||||
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
|
||||||
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
|
||||||
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
|
||||||
){
|
|
||||||
currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z + 1);
|
|
||||||
if(currentChunk != null){
|
|
||||||
weights[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = currentChunk.getWeight(0, 0, 0);
|
|
||||||
types[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = currentChunk.getType(0, 0, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
weights[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = -1;
|
|
||||||
types[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills in the data for the higher resolution face
|
||||||
|
* @param chunkData The data for the chunk to generate
|
||||||
|
* @param higherLODFace The face that is higher LOD
|
||||||
|
* @param lod The Level of Detail for this chunk
|
||||||
|
* @return true if successfully filled in data, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean fillInFaceData(TransvoxelChunkData chunkData, DrawCellFace higherLODFace, int lod){
|
||||||
|
int mainSpacing = (int)Math.pow(2,lod);
|
||||||
|
int higherResSpacing = (int)Math.pow(2,lod - 1);
|
||||||
|
float[][] faceWeights = new float[TransvoxelModelGeneration.FACE_DATA_DIMENSIONS][TransvoxelModelGeneration.FACE_DATA_DIMENSIONS];
|
||||||
|
int[][] faceTypes = new int[TransvoxelModelGeneration.FACE_DATA_DIMENSIONS][TransvoxelModelGeneration.FACE_DATA_DIMENSIONS];
|
||||||
|
//allocate face array
|
||||||
|
for(int x = 0; x < TransvoxelModelGeneration.FACE_DATA_DIMENSIONS; x++){
|
||||||
|
for(int y = 0; y < TransvoxelModelGeneration.FACE_DATA_DIMENSIONS; y++){
|
||||||
|
int worldCoordOffset1 = (x * higherResSpacing) / ChunkData.CHUNK_SIZE;
|
||||||
|
int worldCoordOffset2 = (y * higherResSpacing) / ChunkData.CHUNK_SIZE;
|
||||||
|
//solve coordinates relative to the face
|
||||||
|
int localCoord1 = (x * higherResSpacing) % ChunkData.CHUNK_SIZE;
|
||||||
|
int localCoord2 = (y * higherResSpacing) % ChunkData.CHUNK_SIZE;
|
||||||
|
|
||||||
|
//implicitly performing transforms to adapt from face-space to world & local space
|
||||||
|
switch(higherLODFace){
|
||||||
|
case X_POSITIVE: {
|
||||||
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(
|
||||||
|
worldPos.x + (17 * mainSpacing) / ChunkData.CHUNK_SIZE,
|
||||||
|
worldPos.y + worldCoordOffset1,
|
||||||
|
worldPos.z + worldCoordOffset2
|
||||||
|
));
|
||||||
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
faceWeights[x][y] = currentChunk.getWeight(
|
||||||
|
0,
|
||||||
|
localCoord1,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
faceTypes[x][y] = currentChunk.getType(
|
||||||
|
0,
|
||||||
|
localCoord1,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case X_NEGATIVE: {
|
||||||
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(
|
||||||
|
worldPos.x,
|
||||||
|
worldPos.y + worldCoordOffset1,
|
||||||
|
worldPos.z + worldCoordOffset2
|
||||||
|
));
|
||||||
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
faceWeights[x][y] = currentChunk.getWeight(
|
||||||
|
0,
|
||||||
|
localCoord1,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
faceTypes[x][y] = currentChunk.getType(
|
||||||
|
0,
|
||||||
|
localCoord1,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case Y_POSITIVE: {
|
||||||
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(
|
||||||
|
worldPos.x + worldCoordOffset1,
|
||||||
|
worldPos.y + (17 * mainSpacing) / ChunkData.CHUNK_SIZE,
|
||||||
|
worldPos.z + worldCoordOffset2
|
||||||
|
));
|
||||||
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
faceWeights[x][y] = currentChunk.getWeight(
|
||||||
|
localCoord1,
|
||||||
|
0,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
faceTypes[x][y] = currentChunk.getType(
|
||||||
|
localCoord1,
|
||||||
|
0,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case Y_NEGATIVE: {
|
||||||
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(
|
||||||
|
worldPos.x + worldCoordOffset1,
|
||||||
|
worldPos.y,
|
||||||
|
worldPos.z + worldCoordOffset2
|
||||||
|
));
|
||||||
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
faceWeights[x][y] = currentChunk.getWeight(
|
||||||
|
localCoord1,
|
||||||
|
0,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
faceTypes[x][y] = currentChunk.getType(
|
||||||
|
localCoord1,
|
||||||
|
0,
|
||||||
|
localCoord2
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case Z_POSITIVE: {
|
||||||
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(
|
||||||
|
worldPos.x + worldCoordOffset1,
|
||||||
|
worldPos.y + worldCoordOffset2,
|
||||||
|
worldPos.z + (17 * mainSpacing) / ChunkData.CHUNK_SIZE
|
||||||
|
));
|
||||||
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
faceWeights[x][y] = currentChunk.getWeight(
|
||||||
|
localCoord1,
|
||||||
|
localCoord2,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
faceTypes[x][y] = currentChunk.getType(
|
||||||
|
localCoord1,
|
||||||
|
localCoord2,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case Z_NEGATIVE: {
|
||||||
|
ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(
|
||||||
|
worldPos.x + worldCoordOffset1,
|
||||||
|
worldPos.y + worldCoordOffset2,
|
||||||
|
worldPos.z
|
||||||
|
));
|
||||||
|
if(currentChunk == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
faceWeights[x][y] = currentChunk.getWeight(
|
||||||
|
localCoord1,
|
||||||
|
localCoord2,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
faceTypes[x][y] = currentChunk.getType(
|
||||||
|
localCoord1,
|
||||||
|
localCoord2,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
// Vector3i sampleChunkWorldPos = new Vector3i(
|
||||||
|
// worldPos.x + (x * higherResSpacing) / ChunkData.CHUNK_SIZE,
|
||||||
|
// worldPos.y + (y * higherResSpacing) / ChunkData.CHUNK_SIZE,
|
||||||
|
// worldPos.z + (z * spacingFactor) / ChunkData.CHUNK_SIZE
|
||||||
|
// );
|
||||||
|
// ChunkData currentChunk = Globals.clientTerrainManager.getChunkDataAtWorldPoint(sampleChunkWorldPos);
|
||||||
|
// if(currentChunk == null){
|
||||||
|
// throw new Error("Chunk is null! " + worldPos);
|
||||||
|
// }
|
||||||
|
// weights[x][y][z] = currentChunk.getWeight(
|
||||||
|
// (x * higherResSpacing) % ChunkData.CHUNK_SIZE,
|
||||||
|
// (y * higherResSpacing) % ChunkData.CHUNK_SIZE,
|
||||||
|
// (z * spacingFactor) % ChunkData.CHUNK_SIZE
|
||||||
|
// );
|
||||||
|
// types[x][y][z] = currentChunk.getType(
|
||||||
|
// (x * higherResSpacing) % ChunkData.CHUNK_SIZE,
|
||||||
|
// (y * higherResSpacing) % ChunkData.CHUNK_SIZE,
|
||||||
|
// (z * spacingFactor) % ChunkData.CHUNK_SIZE
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch(higherLODFace){
|
||||||
|
case X_POSITIVE: {
|
||||||
|
chunkData.addXPositiveEdge(faceWeights, faceTypes);
|
||||||
|
} break;
|
||||||
|
case X_NEGATIVE: {
|
||||||
|
chunkData.addXNegativeEdge(faceWeights, faceTypes);
|
||||||
|
} break;
|
||||||
|
case Y_POSITIVE: {
|
||||||
|
chunkData.addYPositiveEdge(faceWeights, faceTypes);
|
||||||
|
} break;
|
||||||
|
case Y_NEGATIVE: {
|
||||||
|
chunkData.addYNegativeEdge(faceWeights, faceTypes);
|
||||||
|
} break;
|
||||||
|
case Z_POSITIVE: {
|
||||||
|
chunkData.addZPositiveEdge(faceWeights, faceTypes);
|
||||||
|
} break;
|
||||||
|
case Z_NEGATIVE: {
|
||||||
|
chunkData.addZNegativeEdge(faceWeights, faceTypes);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the LOD level
|
||||||
|
* @return The LOD level
|
||||||
|
*/
|
||||||
|
public int getLodLevel() {
|
||||||
|
return lodLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the LOD level
|
||||||
|
* @param lodLevel The LOD level
|
||||||
|
*/
|
||||||
|
public void setLodLevel(int lodLevel) {
|
||||||
|
this.lodLevel = lodLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this draw cell has requested its chunk data or not
|
||||||
|
* @return true if has requested, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasRequested() {
|
||||||
|
return hasRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this draw cell has requested its chunk data or not
|
||||||
|
* @param hasRequested true if has requested, false otherwise
|
||||||
|
*/
|
||||||
|
public void setHasRequested(boolean hasRequested) {
|
||||||
|
this.hasRequested = hasRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this draw cell has generated its entity or not
|
||||||
|
* @return true if has generated, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasGenerated() {
|
||||||
|
return hasGenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this draw cell has generated its entity or not
|
||||||
|
* @param hasGenerated true if has generated, false otherwise
|
||||||
|
*/
|
||||||
|
public void setHasGenerated(boolean hasGenerated) {
|
||||||
|
this.hasGenerated = hasGenerated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this draw cell will generate polygons or not
|
||||||
|
* @return true if it has polygons, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean hasPolygons(){
|
||||||
|
return this.multiVoxelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package electrosphere.client.terrain.cells;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ import electrosphere.net.parser.net.message.TerrainMessage;
|
|||||||
import electrosphere.renderer.shader.ShaderProgram;
|
import electrosphere.renderer.shader.ShaderProgram;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
/**
|
/**
|
||||||
* Manages the graphical entities for the terrain chunks
|
* Manages the graphical entities for the terrain chunks
|
||||||
*
|
*
|
||||||
@ -235,7 +237,7 @@ public class DrawCellManager {
|
|||||||
);
|
);
|
||||||
cells.add(cell);
|
cells.add(cell);
|
||||||
keyCellMap.put(targetKey,cell);
|
keyCellMap.put(targetKey,cell);
|
||||||
DrawCellFace higherLODFace = null;
|
List<DrawCellFace> higherLODFace = null;
|
||||||
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
|
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
|
||||||
|
|
||||||
//evaluate for foliage
|
//evaluate for foliage
|
||||||
@ -261,7 +263,7 @@ public class DrawCellManager {
|
|||||||
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
){
|
){
|
||||||
keyCellMap.get(targetKey).destroy();
|
keyCellMap.get(targetKey).destroy();
|
||||||
DrawCellFace higherLODFace = null;
|
List<DrawCellFace> higherLODFace = null;
|
||||||
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
|
keyCellMap.get(targetKey).generateDrawableEntity(atlas,0,higherLODFace);
|
||||||
}
|
}
|
||||||
drawable.add(targetKey);
|
drawable.add(targetKey);
|
||||||
@ -304,7 +306,7 @@ public class DrawCellManager {
|
|||||||
* @return the cell coordinate
|
* @return the cell coordinate
|
||||||
*/
|
*/
|
||||||
public int transformRealSpaceToCellSpace(double input){
|
public int transformRealSpaceToCellSpace(double input){
|
||||||
return (int)(input / Globals.clientWorldData.getDynamicInterpolationRatio());
|
return (int)(input / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -8,12 +8,14 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
import electrosphere.client.scene.ClientWorldData;
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.cache.ChunkData;
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
import electrosphere.client.terrain.cache.ClientTerrainCache;
|
import electrosphere.client.terrain.cache.ClientTerrainCache;
|
||||||
|
import electrosphere.client.terrain.cells.ClientDrawCellManager;
|
||||||
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
|
import electrosphere.client.terrain.cells.VoxelTextureAtlas;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.types.terrain.TerrainChunkData;
|
import electrosphere.entity.types.terrain.TerrainChunkData;
|
||||||
@ -21,6 +23,7 @@ import electrosphere.logger.LoggerInterface;
|
|||||||
import electrosphere.net.parser.net.message.TerrainMessage;
|
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||||
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
|
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
|
||||||
import electrosphere.renderer.model.Model;
|
import electrosphere.renderer.model.Model;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,12 +33,22 @@ public class ClientTerrainManager {
|
|||||||
|
|
||||||
//queues messages from server
|
//queues messages from server
|
||||||
List<TerrainMessage> messageQueue = new CopyOnWriteArrayList<TerrainMessage>();
|
List<TerrainMessage> messageQueue = new CopyOnWriteArrayList<TerrainMessage>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the terrain manager (eg if adding message from network)
|
||||||
|
*/
|
||||||
|
static Semaphore lock = new Semaphore(1);
|
||||||
|
|
||||||
//The interpolation ratio of terrain
|
//The interpolation ratio of terrain
|
||||||
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 = 500;
|
static final int CACHE_SIZE = 1500 + (int)(ClientDrawCellManager.FULL_RES_DIST * 10) + (int)(ClientDrawCellManager.HALF_RES_DIST * 10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the cache in bytes
|
||||||
|
*/
|
||||||
|
static final int CACHE_SIZE_IN_MB = (CACHE_SIZE * ServerTerrainChunk.CHUNK_DIMENSION * ServerTerrainChunk.CHUNK_DIMENSION * ServerTerrainChunk.CHUNK_DIMENSION * 2 * 4) / 1024 / 1024;
|
||||||
|
|
||||||
//used for caching the macro values
|
//used for caching the macro values
|
||||||
ClientTerrainCache terrainCache;
|
ClientTerrainCache terrainCache;
|
||||||
@ -58,6 +71,8 @@ public class ClientTerrainManager {
|
|||||||
* Handles messages that have been received from the server
|
* Handles messages that have been received from the server
|
||||||
*/
|
*/
|
||||||
public void handleMessages(){
|
public void handleMessages(){
|
||||||
|
Globals.profiler.beginCpuSample("ClientTerrainManager.handleMessages");
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
|
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
|
||||||
for(TerrainMessage message : messageQueue){
|
for(TerrainMessage message : messageQueue){
|
||||||
messageQueue.remove(message);
|
messageQueue.remove(message);
|
||||||
@ -83,7 +98,7 @@ public class ClientTerrainManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChunkData data = new ChunkData();
|
ChunkData data = new ChunkData(message.getworldX(), message.getworldY(), message.getworldZ());
|
||||||
data.setVoxelType(values);
|
data.setVoxelType(values);
|
||||||
data.setVoxelWeight(weights);
|
data.setVoxelWeight(weights);
|
||||||
terrainCache.addChunkDataToCache(
|
terrainCache.addChunkDataToCache(
|
||||||
@ -99,6 +114,8 @@ public class ClientTerrainManager {
|
|||||||
for(TerrainMessage message : bouncedMessages){
|
for(TerrainMessage message : bouncedMessages){
|
||||||
messageQueue.add(message);
|
messageQueue.add(message);
|
||||||
}
|
}
|
||||||
|
lock.release();
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +130,9 @@ public class ClientTerrainManager {
|
|||||||
* @param message The message
|
* @param message The message
|
||||||
*/
|
*/
|
||||||
public void attachTerrainMessage(TerrainMessage message){
|
public void attachTerrainMessage(TerrainMessage message){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
messageQueue.add(message);
|
messageQueue.add(message);
|
||||||
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,6 +154,22 @@ public class ClientTerrainManager {
|
|||||||
public boolean containsChunkDataAtWorldPoint(Vector3i worldPos){
|
public boolean containsChunkDataAtWorldPoint(Vector3i worldPos){
|
||||||
return terrainCache.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z);
|
return terrainCache.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a chunk from the server
|
||||||
|
* @param worldX the world x coordinate of the chunk
|
||||||
|
* @param worldY the world y coordinate of the chunk
|
||||||
|
* @param worldZ the world z coordinate of the chunk
|
||||||
|
*/
|
||||||
|
public void requestChunk(int worldX, int worldY, int worldZ){
|
||||||
|
if(!this.terrainCache.hasRequested(worldX, worldY, worldZ)){
|
||||||
|
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage(
|
||||||
|
worldX,
|
||||||
|
worldY,
|
||||||
|
worldZ
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that the cache contains chunk data at a real-space coordinate
|
* Checks that the cache contains chunk data at a real-space coordinate
|
||||||
@ -184,7 +219,9 @@ public class ClientTerrainManager {
|
|||||||
UUID newUUID = UUID.randomUUID();
|
UUID newUUID = UUID.randomUUID();
|
||||||
promisedHash = newUUID.toString();
|
promisedHash = newUUID.toString();
|
||||||
TerrainChunkGenQueueItem queueItem = new TerrainChunkGenQueueItem(data, promisedHash, atlas);
|
TerrainChunkGenQueueItem queueItem = new TerrainChunkGenQueueItem(data, promisedHash, atlas);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
terrainChunkGenerationQueue.add(queueItem);
|
terrainChunkGenerationQueue.add(queueItem);
|
||||||
|
lock.release();
|
||||||
return promisedHash;
|
return promisedHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,12 +229,14 @@ public class ClientTerrainManager {
|
|||||||
* Pushes all terrain data in queue to the gpu and registers the resulting models
|
* Pushes all terrain data in queue to the gpu and registers the resulting models
|
||||||
*/
|
*/
|
||||||
public static void generateTerrainChunkGeometry(){
|
public static void generateTerrainChunkGeometry(){
|
||||||
Globals.profiler.beginCpuSample("generateTerrainChunkGeometry");
|
Globals.profiler.beginCpuSample("ClientTerrainManager.generateTerrainChunkGeometry");
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
for(TerrainChunkGenQueueItem queueItem : terrainChunkGenerationQueue){
|
for(TerrainChunkGenQueueItem queueItem : terrainChunkGenerationQueue){
|
||||||
Model terrainModel = TerrainChunkModelGeneration.generateTerrainModel(queueItem.getData(), queueItem.getAtlas());
|
Model terrainModel = TerrainChunkModelGeneration.generateTerrainModel(queueItem.getData(), queueItem.getAtlas());
|
||||||
Globals.assetManager.registerModelToSpecificString(terrainModel, queueItem.getPromisedHash());
|
Globals.assetManager.registerModelToSpecificString(terrainModel, queueItem.getPromisedHash());
|
||||||
}
|
}
|
||||||
terrainChunkGenerationQueue.clear();
|
terrainChunkGenerationQueue.clear();
|
||||||
|
lock.release();
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,5 +256,13 @@ public class ClientTerrainManager {
|
|||||||
public Vector3i getPositionOfChunk(ChunkData chunk){
|
public Vector3i getPositionOfChunk(ChunkData chunk){
|
||||||
return terrainCache.getChunkPosition(chunk);
|
return terrainCache.getChunkPosition(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of chunks that have been requested
|
||||||
|
* @return The number of chunks
|
||||||
|
*/
|
||||||
|
public int getRequestedCellCount(){
|
||||||
|
return this.terrainCache.getRequestedCellCount();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -184,6 +184,9 @@ public class WindowUtils {
|
|||||||
initTooltipWindow();
|
initTooltipWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits the loading window
|
||||||
|
*/
|
||||||
static void initLoadingWindow(){
|
static void initLoadingWindow(){
|
||||||
Window loadingWindow = Window.create(Globals.renderingEngine.getOpenGLState(), 0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, false);
|
Window loadingWindow = Window.create(Globals.renderingEngine.getOpenGLState(), 0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, false);
|
||||||
Label loadingLabel = Label.createLabel("LOADING");
|
Label loadingLabel = Label.createLabel("LOADING");
|
||||||
@ -208,6 +211,18 @@ public class WindowUtils {
|
|||||||
Globals.elementService.registerWindow(WindowStrings.WINDOW_ITEM_DRAG_CONTAINER, itemDragContainerWindow);
|
Globals.elementService.registerWindow(WindowStrings.WINDOW_ITEM_DRAG_CONTAINER, itemDragContainerWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the loading window
|
||||||
|
*/
|
||||||
|
public static void updateLoadingWindow(String message){
|
||||||
|
Globals.signalSystem.post(SignalType.UI_MODIFICATION,() -> {
|
||||||
|
Window loadingWindow = (Window)Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING);
|
||||||
|
loadingWindow.clear();
|
||||||
|
loadingWindow.addChild(Label.createLabel(message));
|
||||||
|
Globals.signalSystem.post(SignalType.YOGA_APPLY,loadingWindow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the tooltip window
|
* Creates the tooltip window
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
package electrosphere.client.ui.menu.debug;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.renderer.ui.imgui.ImGuiLinePlot;
|
||||||
|
import electrosphere.renderer.ui.imgui.ImGuiLinePlot.ImGuiLinePlotDataset;
|
||||||
|
import electrosphere.renderer.ui.imgui.ImGuiWindow;
|
||||||
|
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
|
||||||
|
import imgui.ImGui;
|
||||||
|
|
||||||
|
public class ImGuiChunkMonitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Num datapoints
|
||||||
|
*/
|
||||||
|
public static final int PRESSURE_GRAPH_POINT_COUNT = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window for viewing chunk status on server and client
|
||||||
|
*/
|
||||||
|
protected static ImGuiWindow chunkMonitorWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the windows in this file
|
||||||
|
*/
|
||||||
|
protected static void createChunkMonitorWindows(){
|
||||||
|
createChunkMonitorWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client scene entity view
|
||||||
|
*/
|
||||||
|
protected static void createChunkMonitorWindow(){
|
||||||
|
chunkMonitorWindow = new ImGuiWindow("Chunk Monitor");
|
||||||
|
|
||||||
|
//client network pressure graph
|
||||||
|
ImGuiLinePlot clientNetworkBandwith = new ImGuiLinePlot("Client Network Pressure",400,400);
|
||||||
|
ImGuiLinePlotDataset clientPressureDataset = new ImGuiLinePlotDataset("Client bytes per frame", PRESSURE_GRAPH_POINT_COUNT);
|
||||||
|
clientPressureDataset.zeroOut();
|
||||||
|
clientNetworkBandwith.addDataset(clientPressureDataset);
|
||||||
|
|
||||||
|
//server network pressure graph
|
||||||
|
ImGuiLinePlot serverNetworkPressureGraph = new ImGuiLinePlot("Server Network Pressure",400,400);
|
||||||
|
ImGuiLinePlotDataset serverPressureDataset = new ImGuiLinePlotDataset("Server bytes per frame", PRESSURE_GRAPH_POINT_COUNT);
|
||||||
|
serverPressureDataset.zeroOut();
|
||||||
|
serverNetworkPressureGraph.addDataset(serverPressureDataset);
|
||||||
|
|
||||||
|
chunkMonitorWindow.setCallback(new ImGuiWindowCallback() {
|
||||||
|
long clientPressureLastValue = 0;
|
||||||
|
long serverPressureLastValue = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exec() {
|
||||||
|
|
||||||
|
|
||||||
|
//ui framework text
|
||||||
|
ImGui.text("Chunk Monitor");
|
||||||
|
|
||||||
|
Globals.clientDrawCellManager.updateStatus();
|
||||||
|
ImGui.text("Renderable chunks: " + Globals.clientDrawCellManager.getGenerated());
|
||||||
|
ImGui.text("Full res chunks: " + Globals.clientDrawCellManager.getMaxResCount());
|
||||||
|
ImGui.text("Half res chunks: " + Globals.clientDrawCellManager.getHalfResCount());
|
||||||
|
|
||||||
|
|
||||||
|
//client network pressure
|
||||||
|
if(Globals.clientConnection != null){
|
||||||
|
long clientPressureNewTotal = Globals.clientConnection.getNumBytesRead();
|
||||||
|
long clientPressureDelta = clientPressureNewTotal - clientPressureLastValue;
|
||||||
|
clientPressureDataset.addPoint(clientPressureDelta);
|
||||||
|
clientPressureLastValue = clientPressureNewTotal;
|
||||||
|
}
|
||||||
|
clientNetworkBandwith.draw();
|
||||||
|
|
||||||
|
//server network pressure
|
||||||
|
if(Globals.server != null && Globals.server.getFirstConnection() != null){
|
||||||
|
long serverPressureNewTotal = Globals.server.getFirstConnection().getNumBytesRead();
|
||||||
|
long serverPressureDelta = serverPressureNewTotal - serverPressureLastValue;
|
||||||
|
serverPressureDataset.addPoint(serverPressureDelta);
|
||||||
|
serverPressureLastValue = serverPressureNewTotal;
|
||||||
|
}
|
||||||
|
serverNetworkPressureGraph.draw();
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chunkMonitorWindow.setOpen(false);
|
||||||
|
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(chunkMonitorWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -47,7 +47,7 @@ public class ImGuiTestGen {
|
|||||||
if(ImGui.button("Regenerate")){
|
if(ImGui.button("Regenerate")){
|
||||||
GriddedDataCellManager gridManager = (GriddedDataCellManager)Globals.realmManager.first().getDataCellManager();
|
GriddedDataCellManager gridManager = (GriddedDataCellManager)Globals.realmManager.first().getDataCellManager();
|
||||||
gridManager.evictAll();
|
gridManager.evictAll();
|
||||||
Globals.drawCellManager.evictAll();
|
Globals.clientDrawCellManager.evictAll();
|
||||||
Globals.clientTerrainManager.evictAll();
|
Globals.clientTerrainManager.evictAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +80,11 @@ public class ImGuiTestGen {
|
|||||||
if(ImGui.inputInt("biome[1][1]", biome11)){
|
if(ImGui.inputInt("biome[1][1]", biome11)){
|
||||||
terrainModel.getBiome()[1][1] = biome11.shortValue();
|
terrainModel.getBiome()[1][1] = biome11.shortValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Toggles whether the client draws cell manager should update or not
|
||||||
|
if(ImGui.button("Toggle ClientDrawCellManager updates")){
|
||||||
|
Globals.clientDrawCellManager.setShouldUpdate(!Globals.clientDrawCellManager.getShouldUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -51,6 +51,7 @@ public class ImGuiWindowMacros {
|
|||||||
ImGuiLogger.createLoggersWindows();
|
ImGuiLogger.createLoggersWindows();
|
||||||
ImGuiRenderer.createRendererWindows();
|
ImGuiRenderer.createRendererWindows();
|
||||||
ImGuiTestGen.createTestGenWindows();
|
ImGuiTestGen.createTestGenWindows();
|
||||||
|
ImGuiChunkMonitor.createChunkMonitorWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,6 +184,10 @@ public class ImGuiWindowMacros {
|
|||||||
){
|
){
|
||||||
ImGuiTestGen.testGenWindow.setOpen(true);
|
ImGuiTestGen.testGenWindow.setOpen(true);
|
||||||
}
|
}
|
||||||
|
//chunk monitor
|
||||||
|
if(ImGui.button("Chunk Monitor")){
|
||||||
|
ImGuiChunkMonitor.chunkMonitorWindow.setOpen(true);
|
||||||
|
}
|
||||||
//close button
|
//close button
|
||||||
if(ImGui.button("Close")){
|
if(ImGui.button("Close")){
|
||||||
mainDebugWindow.setOpen(false);
|
mainDebugWindow.setOpen(false);
|
||||||
|
|||||||
@ -724,7 +724,9 @@ public class CollisionEngine {
|
|||||||
DBody rigidBody = PhysicsEntityUtils.getDBody(e);
|
DBody rigidBody = PhysicsEntityUtils.getDBody(e);
|
||||||
deregisterCollisionObject(rigidBody,PhysicsEntityUtils.getCollidable(e));
|
deregisterCollisionObject(rigidBody,PhysicsEntityUtils.getCollidable(e));
|
||||||
e.removeData(EntityDataStrings.PHYSICS_COLLISION_BODY);
|
e.removeData(EntityDataStrings.PHYSICS_COLLISION_BODY);
|
||||||
deregisterPhysicsObject(rigidBody);
|
if(rigidBody != null){
|
||||||
|
deregisterPhysicsObject(rigidBody);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(ServerPhysicsSyncTree.hasTree(e)){
|
if(ServerPhysicsSyncTree.hasTree(e)){
|
||||||
ServerPhysicsSyncTree.detachTree(e, ServerPhysicsSyncTree.getTree(e));
|
ServerPhysicsSyncTree.detachTree(e, ServerPhysicsSyncTree.getTree(e));
|
||||||
|
|||||||
@ -62,7 +62,7 @@ public class CollisionWorldData {
|
|||||||
|
|
||||||
public int getDynamicInterpolationRatio(){
|
public int getDynamicInterpolationRatio(){
|
||||||
if(clientWorldData != null){
|
if(clientWorldData != null){
|
||||||
return clientWorldData.getDynamicInterpolationRatio();
|
return clientWorldData.getWorldDiscreteSize();
|
||||||
} else {
|
} else {
|
||||||
return serverWorldData.getDynamicInterpolationRatio();
|
return serverWorldData.getDynamicInterpolationRatio();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import electrosphere.client.player.ClientPlayerData;
|
|||||||
import electrosphere.client.scene.ClientSceneWrapper;
|
import electrosphere.client.scene.ClientSceneWrapper;
|
||||||
import electrosphere.client.scene.ClientWorldData;
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.sim.ClientSimulation;
|
import electrosphere.client.sim.ClientSimulation;
|
||||||
import electrosphere.client.terrain.cells.DrawCellManager;
|
import electrosphere.client.terrain.cells.ClientDrawCellManager;
|
||||||
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.client.ui.menu.WindowUtils;
|
import electrosphere.client.ui.menu.WindowUtils;
|
||||||
@ -235,7 +235,7 @@ public class Globals {
|
|||||||
//
|
//
|
||||||
//Generic OpenGL Statements
|
//Generic OpenGL Statements
|
||||||
//
|
//
|
||||||
public static long window;
|
public static long window = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ public class Globals {
|
|||||||
|
|
||||||
//chunk stuff
|
//chunk stuff
|
||||||
//draw cell manager
|
//draw cell manager
|
||||||
public static DrawCellManager drawCellManager;
|
public static ClientDrawCellManager clientDrawCellManager;
|
||||||
public static VoxelTextureAtlas voxelTextureAtlas = new VoxelTextureAtlas();
|
public static VoxelTextureAtlas voxelTextureAtlas = new VoxelTextureAtlas();
|
||||||
|
|
||||||
//fluid cell manager
|
//fluid cell manager
|
||||||
@ -696,6 +696,7 @@ public class Globals {
|
|||||||
Globals.realmManager = null;
|
Globals.realmManager = null;
|
||||||
Globals.clientSceneWrapper = null;
|
Globals.clientSceneWrapper = null;
|
||||||
Globals.clientScene = null;
|
Globals.clientScene = null;
|
||||||
|
Globals.clientWorldData = null;
|
||||||
Globals.audioEngine = null;
|
Globals.audioEngine = null;
|
||||||
Globals.renderingEngine = null;
|
Globals.renderingEngine = null;
|
||||||
Globals.threadManager = null;
|
Globals.threadManager = null;
|
||||||
|
|||||||
@ -420,14 +420,7 @@ public class Main {
|
|||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
|
|
||||||
} catch (NullPointerException ex){
|
} catch (NullPointerException ex){
|
||||||
LoggerInterface.loggerEngine.ERROR("Main frame uncaught NPE", ex);
|
LoggerInterface.loggerEngine.ERROR(ex);
|
||||||
//after a while, jvm will stop reporting stack traces with errors
|
|
||||||
//need to explicitly kill the vm if you want to see the stack trace
|
|
||||||
if(Globals.ENGINE_DEBUG){
|
|
||||||
System.exit(1);
|
|
||||||
} else {
|
|
||||||
throw new Error("NPE!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import electrosphere.client.entity.crosshair.Crosshair;
|
|||||||
import electrosphere.client.fluid.cells.FluidCellManager;
|
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.terrain.cells.DrawCellManager;
|
import electrosphere.client.terrain.cells.ClientDrawCellManager;
|
||||||
import electrosphere.client.ui.menu.MenuGenerators;
|
import electrosphere.client.ui.menu.MenuGenerators;
|
||||||
import electrosphere.client.ui.menu.WindowStrings;
|
import electrosphere.client.ui.menu.WindowStrings;
|
||||||
import electrosphere.client.ui.menu.WindowUtils;
|
import electrosphere.client.ui.menu.WindowUtils;
|
||||||
@ -29,16 +29,27 @@ import electrosphere.net.NetUtils;
|
|||||||
import electrosphere.net.client.ClientNetworking;
|
import electrosphere.net.client.ClientNetworking;
|
||||||
import electrosphere.renderer.actor.Actor;
|
import electrosphere.renderer.actor.Actor;
|
||||||
import electrosphere.renderer.actor.ActorTextureMask;
|
import electrosphere.renderer.actor.ActorTextureMask;
|
||||||
import electrosphere.renderer.ui.elements.Window;
|
|
||||||
|
|
||||||
public class ClientLoading {
|
public class ClientLoading {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of frames to wait before updating status of draw cell manager loading
|
||||||
|
*/
|
||||||
|
static final int DRAW_CELL_UPDATE_RATE = 60;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of frames the draw cell is expected to take (minimum) to init
|
||||||
|
*/
|
||||||
|
static final int DRAW_CELL_EXPECTED_MINIMUM_FRAMES_TO_INIT = 100;
|
||||||
|
|
||||||
|
|
||||||
protected static void loadCharacterServer(Object[] params){
|
protected static void loadCharacterServer(Object[] params){
|
||||||
Window loadingWindow = (Window)Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING);
|
|
||||||
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), false);
|
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), false);
|
||||||
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
|
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
|
||||||
loadingWindow.setVisible(true);
|
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING), true);
|
||||||
|
WindowUtils.updateLoadingWindow("Waiting on server");
|
||||||
//disable menu input
|
//disable menu input
|
||||||
Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
|
Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
|
||||||
//initialize the client thread (client)
|
//initialize the client thread (client)
|
||||||
@ -54,7 +65,7 @@ public class ClientLoading {
|
|||||||
//eventually should replace with at ui to select an already created character or create a new one
|
//eventually should replace with at ui to select an already created character or create a new one
|
||||||
WindowUtils.replaceMainMenuContents(MenuGeneratorsMultiplayer.createMultiplayerCharacterCreationWindow());
|
WindowUtils.replaceMainMenuContents(MenuGeneratorsMultiplayer.createMultiplayerCharacterCreationWindow());
|
||||||
//make loading dialog disappear
|
//make loading dialog disappear
|
||||||
loadingWindow.setVisible(false);
|
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING), false);
|
||||||
//make character creation window visible
|
//make character creation window visible
|
||||||
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), true);
|
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), true);
|
||||||
//recapture window
|
//recapture window
|
||||||
@ -70,6 +81,7 @@ public class ClientLoading {
|
|||||||
Globals.signalSystem.post(SignalType.UI_MODIFICATION, () -> {
|
Globals.signalSystem.post(SignalType.UI_MODIFICATION, () -> {
|
||||||
WindowUtils.closeWindow(WindowStrings.WINDOW_MENU_MAIN);
|
WindowUtils.closeWindow(WindowStrings.WINDOW_MENU_MAIN);
|
||||||
WindowUtils.recursiveSetVisible(WindowStrings.WINDOW_LOADING, true);
|
WindowUtils.recursiveSetVisible(WindowStrings.WINDOW_LOADING, true);
|
||||||
|
WindowUtils.updateLoadingWindow("LOADING");
|
||||||
});
|
});
|
||||||
//disable menu input
|
//disable menu input
|
||||||
Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
|
Globals.controlHandler.hintUpdateControlState(ControlHandler.ControlsState.NO_INPUT);
|
||||||
@ -263,7 +275,8 @@ public class ClientLoading {
|
|||||||
*/
|
*/
|
||||||
static void initDrawCellManager(boolean blockForInit){
|
static void initDrawCellManager(boolean blockForInit){
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
while(blockForInit && (Globals.clientWorldData == null || InitialAssetLoading.atlasQueuedTexture == null || !InitialAssetLoading.atlasQueuedTexture.hasLoaded())){
|
WindowUtils.updateLoadingWindow("WAITING ON WORLD DATA");
|
||||||
|
while(blockForInit && (Globals.clientWorldData == null || InitialAssetLoading.atlasQueuedTexture == null || !InitialAssetLoading.atlasQueuedTexture.hasLoaded()) && Globals.threadManager.shouldKeepRunning()){
|
||||||
try {
|
try {
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
iterations++;
|
iterations++;
|
||||||
@ -278,28 +291,25 @@ public class ClientLoading {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//initialize draw cell manager
|
//initialize draw cell manager
|
||||||
Globals.drawCellManager = new DrawCellManager(Globals.clientTerrainManager, 0, 0, 0);
|
// Globals.drawCellManager = new DrawCellManager(Globals.clientTerrainManager, 0, 0, 0);
|
||||||
//construct texture atlas
|
Globals.clientDrawCellManager = new ClientDrawCellManager(Globals.voxelTextureAtlas, Globals.clientWorldData.getWorldDiscreteSize());
|
||||||
Globals.drawCellManager.attachTextureAtlas(Globals.voxelTextureAtlas);
|
|
||||||
//set our draw cell manager to actually generate drawable chunks
|
|
||||||
Globals.drawCellManager.setGenerateDrawables(true);
|
|
||||||
//Alerts the client simulation that it should start loading terrain
|
//Alerts the client simulation that it should start loading terrain
|
||||||
Globals.clientSimulation.setLoadingTerrain(true);
|
Globals.clientSimulation.setLoadingTerrain(true);
|
||||||
//wait for all the terrain data to arrive
|
//wait for all the terrain data to arrive
|
||||||
while(blockForInit && Globals.drawCellManager.containsUnrequestedCell()){
|
int i = 0;
|
||||||
|
while(blockForInit && Globals.clientDrawCellManager.updatedLastFrame() && Globals.threadManager.shouldKeepRunning()){
|
||||||
|
i++;
|
||||||
|
if(i % DRAW_CELL_UPDATE_RATE == 0){
|
||||||
|
WindowUtils.updateLoadingWindow("WAITING ON SERVER TO SEND TERRAIN (" + Globals.clientTerrainManager.getAllChunks().size() + "/" + Globals.clientTerrainManager.getRequestedCellCount() + ")");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(i < DRAW_CELL_EXPECTED_MINIMUM_FRAMES_TO_INIT){
|
||||||
while(blockForInit && Globals.drawCellManager.containsUndrawableCell()){
|
LoggerInterface.loggerEngine.WARNING("Probably didn't block for draw cell manager initialization!");
|
||||||
try {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +320,8 @@ public class ClientLoading {
|
|||||||
static void initFluidCellManager(boolean blockForInit){
|
static void initFluidCellManager(boolean blockForInit){
|
||||||
|
|
||||||
//wait for world data
|
//wait for world data
|
||||||
while(blockForInit && Globals.clientWorldData == null){
|
WindowUtils.updateLoadingWindow("WAITING ON WORLD DATA");
|
||||||
|
while(blockForInit && Globals.clientWorldData == null && Globals.threadManager.shouldKeepRunning()){
|
||||||
try {
|
try {
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
@ -323,7 +334,8 @@ public class ClientLoading {
|
|||||||
Globals.clientSimulation.setLoadingTerrain(true);
|
Globals.clientSimulation.setLoadingTerrain(true);
|
||||||
|
|
||||||
//wait for all the terrain data to arrive
|
//wait for all the terrain data to arrive
|
||||||
while(blockForInit && Globals.fluidCellManager.containsUnrequestedCell()){
|
WindowUtils.updateLoadingWindow("REQUESTING FLUID CHUNKS FROM SERVER (" + Globals.fluidCellManager.getUnrequestedSize() + ")");
|
||||||
|
while(blockForInit && Globals.fluidCellManager.containsUnrequestedCell() && Globals.threadManager.shouldKeepRunning()){
|
||||||
try {
|
try {
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
@ -332,7 +344,8 @@ public class ClientLoading {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//wait for undrawable cells
|
//wait for undrawable cells
|
||||||
while(blockForInit && Globals.fluidCellManager.containsUndrawableCell()){
|
WindowUtils.updateLoadingWindow("WAITING ON SERVER TO SEND FLUID CHUNKS (" + Globals.fluidCellManager.getUndrawableSize() + ")");
|
||||||
|
while(blockForInit && Globals.fluidCellManager.containsUndrawableCell() && Globals.threadManager.shouldKeepRunning()){
|
||||||
try {
|
try {
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import electrosphere.entity.types.creature.CreatureTemplate;
|
|||||||
import electrosphere.entity.types.creature.CreatureToolbarData.ToolbarItem;
|
import electrosphere.entity.types.creature.CreatureToolbarData.ToolbarItem;
|
||||||
import electrosphere.game.data.creature.type.CreatureData;
|
import electrosphere.game.data.creature.type.CreatureData;
|
||||||
import electrosphere.game.data.creature.type.visualattribute.VisualAttribute;
|
import electrosphere.game.data.creature.type.visualattribute.VisualAttribute;
|
||||||
import electrosphere.game.server.world.MacroData;
|
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.net.NetUtils;
|
import electrosphere.net.NetUtils;
|
||||||
import electrosphere.net.client.ClientNetworking;
|
import electrosphere.net.client.ClientNetworking;
|
||||||
@ -26,41 +25,17 @@ import electrosphere.net.server.Server;
|
|||||||
import electrosphere.net.server.ServerConnectionHandler;
|
import electrosphere.net.server.ServerConnectionHandler;
|
||||||
import electrosphere.net.server.player.Player;
|
import electrosphere.net.server.player.Player;
|
||||||
import electrosphere.server.datacell.Realm;
|
import electrosphere.server.datacell.Realm;
|
||||||
import electrosphere.server.simulation.MacroSimulation;
|
|
||||||
import electrosphere.server.simulation.MicroSimulation;
|
import electrosphere.server.simulation.MicroSimulation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for all loading thread types
|
* Utilities for all loading thread types
|
||||||
*/
|
*/
|
||||||
public class LoadingUtils {
|
public class LoadingUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
// static void initCommonWorldData(boolean FLAG_INIT_SERVER){
|
* The size of the buffer
|
||||||
// if(Globals.commonWorldData == null){
|
*/
|
||||||
// if(FLAG_INIT_SERVER){
|
static final int STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
|
||||||
// Globals.commonWorldData = new CommonWorldData(Globals.serverWorldData, Globals.serverTerrainManager);
|
|
||||||
// if(Globals.macroSimulation != null){
|
|
||||||
// Town startTown = Globals.macroData.getTowns().get(0);
|
|
||||||
// Vector2i firstPos = startTown.getPositions().get(0);
|
|
||||||
// // double startX = firstPos.x * Globals.serverTerrainManager.getChunkWidth();
|
|
||||||
// // double startZ = firstPos.y * Globals.serverTerrainManager.getChunkWidth();
|
|
||||||
// double startX = Globals.commonWorldData.convertWorldToReal(firstPos.x);
|
|
||||||
// double startZ = Globals.commonWorldData.convertWorldToReal(firstPos.y);
|
|
||||||
// Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// //basically wait for the client to receive the world metadata
|
|
||||||
// while(!Globals.clientConnection.getClientProtocol().hasReceivedWorld()){
|
|
||||||
// try {
|
|
||||||
// TimeUnit.MILLISECONDS.sleep(5);
|
|
||||||
// } catch (InterruptedException ex) {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //then create common world data
|
|
||||||
// Globals.commonWorldData = new CommonWorldData(Globals.clientWorldData, Globals.clientTerrainManager);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -93,7 +68,12 @@ public class LoadingUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final int STREAM_BUFFER_SIZE = 32 * 1024 * 1024;
|
|
||||||
|
/**
|
||||||
|
* Initializes a local connection
|
||||||
|
* @param runServerThread true if should run the server in a separate thread, false otherwise
|
||||||
|
* @return The server connection
|
||||||
|
*/
|
||||||
static ServerConnectionHandler initLocalConnection(boolean runServerThread){
|
static ServerConnectionHandler initLocalConnection(boolean runServerThread){
|
||||||
ServerConnectionHandler rVal = null;
|
ServerConnectionHandler rVal = null;
|
||||||
try {
|
try {
|
||||||
@ -106,7 +86,7 @@ public class LoadingUtils {
|
|||||||
PipedInputStream clientInput = new PipedInputStream(STREAM_BUFFER_SIZE);
|
PipedInputStream clientInput = new PipedInputStream(STREAM_BUFFER_SIZE);
|
||||||
PipedOutputStream serverOutput = new PipedOutputStream(clientInput);
|
PipedOutputStream serverOutput = new PipedOutputStream(clientInput);
|
||||||
//server -> client pipe
|
//server -> client pipe
|
||||||
PipedInputStream serverInput = new PipedInputStream();
|
PipedInputStream serverInput = new PipedInputStream(STREAM_BUFFER_SIZE);
|
||||||
PipedOutputStream clientOutput;
|
PipedOutputStream clientOutput;
|
||||||
clientOutput = new PipedOutputStream(serverInput);
|
clientOutput = new PipedOutputStream(serverInput);
|
||||||
//start server communication thread
|
//start server communication thread
|
||||||
|
|||||||
@ -29,6 +29,14 @@ public class Signal {
|
|||||||
YOGA_DESTROY,
|
YOGA_DESTROY,
|
||||||
UI_MODIFICATION,
|
UI_MODIFICATION,
|
||||||
|
|
||||||
|
//
|
||||||
|
//Terrain
|
||||||
|
//
|
||||||
|
REQUEST_CHUNK,
|
||||||
|
CHUNK_CREATED,
|
||||||
|
REQUEST_CHUNK_EDIT,
|
||||||
|
CHUNK_EDITED,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.engine.loadingthreads.LoadingThread;
|
import electrosphere.engine.loadingthreads.LoadingThread;
|
||||||
import electrosphere.engine.threads.LabeledThread.ThreadLabel;
|
import electrosphere.engine.threads.LabeledThread.ThreadLabel;
|
||||||
|
import electrosphere.entity.types.terrain.TerrainChunk;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
import electrosphere.util.CodeUtils;
|
import electrosphere.util.CodeUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,6 +112,19 @@ public class ThreadManager {
|
|||||||
Globals.server.close();
|
Globals.server.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Globals.realmManager.getRealms() != null){
|
||||||
|
for(Realm realm : Globals.realmManager.getRealms()){
|
||||||
|
if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null){
|
||||||
|
realm.getServerWorldData().getServerTerrainManager().closeThreads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halds all terrain chunk threads
|
||||||
|
*/
|
||||||
|
TerrainChunk.haltThreads();
|
||||||
|
|
||||||
//
|
//
|
||||||
//interrupt all threads
|
//interrupt all threads
|
||||||
for(int i = 0; i < 3; i++){
|
for(int i = 0; i < 3; i++){
|
||||||
|
|||||||
@ -129,9 +129,6 @@ public class EntityCreationUtils {
|
|||||||
*/
|
*/
|
||||||
public static void makeEntityDrawablePreexistingModel(Entity entity, String modelPath){
|
public static void makeEntityDrawablePreexistingModel(Entity entity, String modelPath){
|
||||||
entity.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorOfLoadingModel(modelPath));
|
entity.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorOfLoadingModel(modelPath));
|
||||||
entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
|
|
||||||
entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());
|
|
||||||
entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
|
|
||||||
entity.putData(EntityDataStrings.DATA_STRING_DRAW, true);
|
entity.putData(EntityDataStrings.DATA_STRING_DRAW, true);
|
||||||
entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
|
entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
|
||||||
Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE);
|
Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE);
|
||||||
|
|||||||
@ -127,6 +127,15 @@ public class Scene {
|
|||||||
return (Entity)entityIdMap.get(id);
|
return (Entity)entityIdMap.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a scene contains a given entity
|
||||||
|
* @param e The entity
|
||||||
|
* @return true if the scene contains the entity, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean containsEntity(Entity e){
|
||||||
|
return entityIdMap.containsKey(e.getId());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a behavior tree to simulate each scene simulation frame
|
* Registers a behavior tree to simulate each scene simulation frame
|
||||||
* @param tree The behavior tree to register
|
* @param tree The behavior tree to register
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
package electrosphere.entity.types.terrain;
|
package electrosphere.entity.types.terrain;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
import electrosphere.client.terrain.cells.DrawCell;
|
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;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.EntityCreationUtils;
|
import electrosphere.entity.EntityCreationUtils;
|
||||||
import electrosphere.entity.EntityDataStrings;
|
import electrosphere.entity.EntityDataStrings;
|
||||||
@ -20,32 +24,44 @@ import electrosphere.server.datacell.Realm;
|
|||||||
*/
|
*/
|
||||||
public class TerrainChunk {
|
public class TerrainChunk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for generating terrain chunks
|
||||||
|
*/
|
||||||
|
static ExecutorService generationService = Executors.newFixedThreadPool(2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a client terrain chunk based on weights and values provided
|
* Creates a client terrain chunk based on weights and values provided
|
||||||
* @param chunkData the chunk data to generate with
|
* @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
|
* @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 hasPolygons true if the chunk has polygons to generate a model with, false otherwise
|
||||||
* @return The terrain chunk entity
|
* @return The terrain chunk entity
|
||||||
*/
|
*/
|
||||||
public static Entity clientCreateTerrainChunkEntity(TransvoxelChunkData chunkData, int levelOfDetail, VoxelTextureAtlas atlas){
|
public static Entity clientCreateTerrainChunkEntity(TransvoxelChunkData chunkData, int levelOfDetail, VoxelTextureAtlas atlas, boolean hasPolygons){
|
||||||
|
Globals.profiler.beginCpuSample("TerrainChunk.clientCreateTerrainChunkEntity");
|
||||||
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();
|
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
|
||||||
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
|
|
||||||
if(data.vertices.size() > 0 && levelOfDetail == DrawCell.FULL_DETAIL_LOD){
|
if(hasPolygons){
|
||||||
PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
|
generationService.submit(() -> {
|
||||||
|
TerrainChunkData data;
|
||||||
|
if(levelOfDetail == DrawCell.FULL_DETAIL_LOD){
|
||||||
|
data = TerrainChunkModelGeneration.generateTerrainChunkData(chunkData.terrainGrid, chunkData.textureGrid);
|
||||||
|
} else {
|
||||||
|
data = TransvoxelModelGeneration.generateTerrainChunkData(chunkData);
|
||||||
|
}
|
||||||
|
if(Globals.clientScene.containsEntity(rVal)){
|
||||||
|
String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas);
|
||||||
|
EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath);
|
||||||
|
if(levelOfDetail == DrawCell.FULL_DETAIL_LOD){
|
||||||
|
PhysicsEntityUtils.clientAttachTerrainChunkRigidBody(rVal, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
rVal.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
||||||
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
|
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +75,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, DrawCell.FULL_DETAIL_LOD);
|
TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(weights, values);
|
||||||
|
|
||||||
Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
|
Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
|
||||||
if(data.vertices.size() > 0){
|
if(data.vertices.size() > 0){
|
||||||
@ -84,4 +100,11 @@ public class TerrainChunk {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halts all running generation threads
|
||||||
|
*/
|
||||||
|
public static void haltThreads(){
|
||||||
|
generationService.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,11 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* Client networking thread
|
* Client networking thread
|
||||||
*/
|
*/
|
||||||
public class ClientNetworking implements Runnable {
|
public class ClientNetworking implements Runnable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Milliseconds after which reading is considered slow enough to be warning-worthy
|
||||||
|
*/
|
||||||
|
static final int SOCKET_READ_WARNING_THRESHOLD = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The server's address
|
* The server's address
|
||||||
@ -62,7 +67,7 @@ public class ClientNetworking implements Runnable {
|
|||||||
|
|
||||||
//thresholds for when to send pings and to determine when we've disconnected
|
//thresholds for when to send pings and to determine when we've disconnected
|
||||||
static final long SEND_PING_THRESHOLD = 3000;
|
static final long SEND_PING_THRESHOLD = 3000;
|
||||||
static final long PING_DISCONNECT_THRESHOLD = 20000;
|
static final long PING_DISCONNECT_THRESHOLD = 60 * 1000;
|
||||||
//times for calculating ping-pong
|
//times for calculating ping-pong
|
||||||
long lastPingTime = 0;
|
long lastPingTime = 0;
|
||||||
long lastPongTime = 0;
|
long lastPongTime = 0;
|
||||||
@ -174,18 +179,43 @@ public class ClientNetworking implements Runnable {
|
|||||||
//start parsing messages
|
//start parsing messages
|
||||||
initialized = true;
|
initialized = true;
|
||||||
while(Globals.threadManager.shouldKeepRunning() && !this.shouldDisconnect){
|
while(Globals.threadManager.shouldKeepRunning() && !this.shouldDisconnect){
|
||||||
|
|
||||||
|
//
|
||||||
//attempt poll incoming messages
|
//attempt poll incoming messages
|
||||||
parser.readMessagesIn();
|
long readStart = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
parser.readMessagesIn();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LoggerInterface.loggerNetworking.ERROR(e);
|
||||||
|
}
|
||||||
|
if(System.currentTimeMillis() - readStart > SOCKET_READ_WARNING_THRESHOLD){
|
||||||
|
LoggerInterface.loggerNetworking.WARNING("Client is slow to read from network! Delay: " + (System.currentTimeMillis() - readStart) + " Number of total bytes read(mb): " + (parser.getNumberOfBytesRead() / 1024 / 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
//outgoing messages
|
//outgoing messages
|
||||||
try {
|
try {
|
||||||
parser.pushMessagesOut();
|
parser.pushMessagesOut();
|
||||||
} catch(IOException e){
|
} catch(IOException e){
|
||||||
LoggerInterface.loggerNetworking.ERROR(e);
|
LoggerInterface.loggerNetworking.ERROR(e);
|
||||||
}
|
}
|
||||||
//parses messages asynchronously
|
|
||||||
this.parseMessagesAsynchronously();
|
|
||||||
|
|
||||||
//ping logic
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//parses messages asynchronously
|
||||||
|
boolean foundMessages = this.parseMessagesAsynchronously();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//timeout logic
|
||||||
|
//if received message from server, can't have timed out
|
||||||
|
if(foundMessages){
|
||||||
|
this.markReceivedPongMessage();
|
||||||
|
}
|
||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
//basically if we haven't sent a ping in a while, send one
|
//basically if we haven't sent a ping in a while, send one
|
||||||
if(currentTime - lastPingTime > SEND_PING_THRESHOLD){
|
if(currentTime - lastPingTime > SEND_PING_THRESHOLD){
|
||||||
@ -228,7 +258,8 @@ public class ClientNetworking implements Runnable {
|
|||||||
/**
|
/**
|
||||||
* Parses messages asynchronously
|
* Parses messages asynchronously
|
||||||
*/
|
*/
|
||||||
public void parseMessagesAsynchronously(){
|
public boolean parseMessagesAsynchronously(){
|
||||||
|
boolean foundMessages = false;
|
||||||
if(initialized){
|
if(initialized){
|
||||||
while(parser.hasIncomingMessaage()){
|
while(parser.hasIncomingMessaage()){
|
||||||
NetworkMessage message = parser.popIncomingMessage();
|
NetworkMessage message = parser.popIncomingMessage();
|
||||||
@ -241,9 +272,11 @@ public class ClientNetworking implements Runnable {
|
|||||||
//do something
|
//do something
|
||||||
Globals.profiler.beginCpuSample("ClientProtocol.handleMessage");
|
Globals.profiler.beginCpuSample("ClientProtocol.handleMessage");
|
||||||
this.messageProtocol.handleAsyncMessage(message);
|
this.messageProtocol.handleAsyncMessage(message);
|
||||||
|
foundMessages = true;
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return foundMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -314,6 +347,17 @@ public class ClientNetworking implements Runnable {
|
|||||||
public boolean isInitialized(){
|
public boolean isInitialized(){
|
||||||
return initialized;
|
return initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total number of bytes read by this connection
|
||||||
|
* @return The total number of bytes
|
||||||
|
*/
|
||||||
|
public long getNumBytesRead(){
|
||||||
|
if(this.parser == null){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return this.parser.getNumberOfBytesRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,9 +97,11 @@ public class MessageProtocol {
|
|||||||
}
|
}
|
||||||
//queue bounced messages for synchronous resolution
|
//queue bounced messages for synchronous resolution
|
||||||
if(result != null){
|
if(result != null){
|
||||||
|
Globals.profiler.beginAggregateCpuSample("MessageProtocol(client) Await lock to synchronize message");
|
||||||
this.synchronousMessageLock.acquireUninterruptibly();
|
this.synchronousMessageLock.acquireUninterruptibly();
|
||||||
this.synchronousMessageQueue.add(result);
|
this.synchronousMessageQueue.add(result);
|
||||||
this.synchronousMessageLock.release();
|
this.synchronousMessageLock.release();
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,6 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
|
|||||||
//Vector3f worldMinPoint, Vector3f worldMaxPoint, int dynamicInterpolationRatio, float randomDampener, int worldDiscreteSize
|
//Vector3f worldMinPoint, Vector3f worldMaxPoint, int dynamicInterpolationRatio, float randomDampener, int worldDiscreteSize
|
||||||
new Vector3f(message.getworldMinX(),0,message.getworldMinY()),
|
new Vector3f(message.getworldMinX(),0,message.getworldMinY()),
|
||||||
new Vector3f(message.getworldMaxX(),32,message.getworldMaxY()),
|
new Vector3f(message.getworldMaxX(),32,message.getworldMaxY()),
|
||||||
ChunkData.CHUNK_SIZE,
|
|
||||||
message.getrandomDampener(),
|
message.getrandomDampener(),
|
||||||
message.getworldSizeDiscrete()
|
message.getworldSizeDiscrete()
|
||||||
);
|
);
|
||||||
@ -44,9 +43,10 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
|
|||||||
case SPAWNPOSITION:
|
case SPAWNPOSITION:
|
||||||
LoggerInterface.loggerNetworking.WARNING("Received spawnPosition packet on client. This is deprecated!");
|
LoggerInterface.loggerNetworking.WARNING("Received spawnPosition packet on client. This is deprecated!");
|
||||||
break;
|
break;
|
||||||
case SENDCHUNKDATA:
|
case SENDCHUNKDATA: {
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Client) Received terrain at " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ());
|
||||||
Globals.clientTerrainManager.attachTerrainMessage(message);
|
Globals.clientTerrainManager.attachTerrainMessage(message);
|
||||||
break;
|
} break;
|
||||||
case UPDATEVOXEL: {
|
case UPDATEVOXEL: {
|
||||||
//
|
//
|
||||||
//find what all drawcells might be updated by this voxel update
|
//find what all drawcells might be updated by this voxel update
|
||||||
@ -97,9 +97,10 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
|
|||||||
if(Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z)){
|
if(Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z)){
|
||||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z);
|
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z);
|
||||||
if(data != null){
|
if(data != null){
|
||||||
Globals.drawCellManager.markUpdateable(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z);
|
Globals.clientDrawCellManager.markUpdateable(worldPosToUpdate.x, worldPosToUpdate.y, worldPosToUpdate.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Globals.clientFoliageManager.evaluateChunk(worldPos);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case SENDFLUIDDATA: {
|
case SENDFLUIDDATA: {
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AuthMessage extends NetworkMessage {
|
public class AuthMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum AuthMessageType {
|
public enum AuthMessageType {
|
||||||
AUTHREQUEST,
|
AUTHREQUEST,
|
||||||
AUTHDETAILS,
|
AUTHDETAILS,
|
||||||
@ -14,10 +17,17 @@ public class AuthMessage extends NetworkMessage {
|
|||||||
AUTHFAILURE,
|
AUTHFAILURE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
AuthMessageType messageType;
|
AuthMessageType messageType;
|
||||||
String user;
|
String user;
|
||||||
String pass;
|
String pass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
AuthMessage(AuthMessageType messageType){
|
AuthMessage(AuthMessageType messageType){
|
||||||
this.type = MessageType.AUTH_MESSAGE;
|
this.type = MessageType.AUTH_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -27,26 +37,48 @@ public class AuthMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets user
|
||||||
|
*/
|
||||||
public String getuser() {
|
public String getuser() {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets user
|
||||||
|
*/
|
||||||
public void setuser(String user) {
|
public void setuser(String user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets pass
|
||||||
|
*/
|
||||||
public String getpass() {
|
public String getpass() {
|
||||||
return pass;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets pass
|
||||||
|
*/
|
||||||
public void setpass(String pass) {
|
public void setpass(String pass) {
|
||||||
this.pass = pass;
|
this.pass = pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.AUTH_MESSAGE_TYPE_AUTHREQUEST:
|
case TypeBytes.AUTH_MESSAGE_TYPE_AUTHREQUEST:
|
||||||
@ -73,18 +105,27 @@ public class AuthMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type AuthRequest
|
||||||
|
*/
|
||||||
public static AuthMessage parseAuthRequestMessage(CircularByteBuffer byteBuffer){
|
public static AuthMessage parseAuthRequestMessage(CircularByteBuffer byteBuffer){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHREQUEST);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHREQUEST);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type AuthRequest
|
||||||
|
*/
|
||||||
public static AuthMessage constructAuthRequestMessage(){
|
public static AuthMessage constructAuthRequestMessage(){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHREQUEST);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHREQUEST);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type AuthDetails can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseAuthDetailsMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseAuthDetailsMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -117,6 +158,9 @@ public class AuthMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type AuthDetails
|
||||||
|
*/
|
||||||
public static AuthMessage parseAuthDetailsMessage(CircularByteBuffer byteBuffer){
|
public static AuthMessage parseAuthDetailsMessage(CircularByteBuffer byteBuffer){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHDETAILS);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHDETAILS);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -125,6 +169,9 @@ public class AuthMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type AuthDetails
|
||||||
|
*/
|
||||||
public static AuthMessage constructAuthDetailsMessage(String user,String pass){
|
public static AuthMessage constructAuthDetailsMessage(String user,String pass){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHDETAILS);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHDETAILS);
|
||||||
rVal.setuser(user);
|
rVal.setuser(user);
|
||||||
@ -133,24 +180,36 @@ public class AuthMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type AuthSuccess
|
||||||
|
*/
|
||||||
public static AuthMessage parseAuthSuccessMessage(CircularByteBuffer byteBuffer){
|
public static AuthMessage parseAuthSuccessMessage(CircularByteBuffer byteBuffer){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHSUCCESS);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHSUCCESS);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type AuthSuccess
|
||||||
|
*/
|
||||||
public static AuthMessage constructAuthSuccessMessage(){
|
public static AuthMessage constructAuthSuccessMessage(){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHSUCCESS);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHSUCCESS);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type AuthFailure
|
||||||
|
*/
|
||||||
public static AuthMessage parseAuthFailureMessage(CircularByteBuffer byteBuffer){
|
public static AuthMessage parseAuthFailureMessage(CircularByteBuffer byteBuffer){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHFAILURE);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHFAILURE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type AuthFailure
|
||||||
|
*/
|
||||||
public static AuthMessage constructAuthFailureMessage(){
|
public static AuthMessage constructAuthFailureMessage(){
|
||||||
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHFAILURE);
|
AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHFAILURE);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class CharacterMessage extends NetworkMessage {
|
public class CharacterMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum CharacterMessageType {
|
public enum CharacterMessageType {
|
||||||
REQUESTCHARACTERLIST,
|
REQUESTCHARACTERLIST,
|
||||||
RESPONSECHARACTERLIST,
|
RESPONSECHARACTERLIST,
|
||||||
@ -17,9 +20,16 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
RESPONSESPAWNCHARACTER,
|
RESPONSESPAWNCHARACTER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
CharacterMessageType messageType;
|
CharacterMessageType messageType;
|
||||||
String data;
|
String data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
CharacterMessage(CharacterMessageType messageType){
|
CharacterMessage(CharacterMessageType messageType){
|
||||||
this.type = MessageType.CHARACTER_MESSAGE;
|
this.type = MessageType.CHARACTER_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -29,18 +39,34 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets data
|
||||||
|
*/
|
||||||
public String getdata() {
|
public String getdata() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets data
|
||||||
|
*/
|
||||||
public void setdata(String data) {
|
public void setdata(String data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST:
|
case TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST:
|
||||||
@ -77,18 +103,27 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestCharacterList
|
||||||
|
*/
|
||||||
public static CharacterMessage parseRequestCharacterListMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseRequestCharacterListMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCHARACTERLIST);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCHARACTERLIST);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestCharacterList
|
||||||
|
*/
|
||||||
public static CharacterMessage constructRequestCharacterListMessage(){
|
public static CharacterMessage constructRequestCharacterListMessage(){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCHARACTERLIST);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCHARACTERLIST);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type ResponseCharacterList can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseResponseCharacterListMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseResponseCharacterListMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -108,6 +143,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ResponseCharacterList
|
||||||
|
*/
|
||||||
public static CharacterMessage parseResponseCharacterListMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseResponseCharacterListMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECHARACTERLIST);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECHARACTERLIST);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -115,6 +153,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ResponseCharacterList
|
||||||
|
*/
|
||||||
public static CharacterMessage constructResponseCharacterListMessage(String data){
|
public static CharacterMessage constructResponseCharacterListMessage(String data){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECHARACTERLIST);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECHARACTERLIST);
|
||||||
rVal.setdata(data);
|
rVal.setdata(data);
|
||||||
@ -122,6 +163,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type RequestCreateCharacter can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseRequestCreateCharacterMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseRequestCreateCharacterMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -141,6 +185,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestCreateCharacter
|
||||||
|
*/
|
||||||
public static CharacterMessage parseRequestCreateCharacterMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseRequestCreateCharacterMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCREATECHARACTER);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCREATECHARACTER);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -148,6 +195,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestCreateCharacter
|
||||||
|
*/
|
||||||
public static CharacterMessage constructRequestCreateCharacterMessage(String data){
|
public static CharacterMessage constructRequestCreateCharacterMessage(String data){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCREATECHARACTER);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCREATECHARACTER);
|
||||||
rVal.setdata(data);
|
rVal.setdata(data);
|
||||||
@ -155,42 +205,63 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ResponseCreateCharacterSuccess
|
||||||
|
*/
|
||||||
public static CharacterMessage parseResponseCreateCharacterSuccessMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseResponseCreateCharacterSuccessMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERSUCCESS);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERSUCCESS);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ResponseCreateCharacterSuccess
|
||||||
|
*/
|
||||||
public static CharacterMessage constructResponseCreateCharacterSuccessMessage(){
|
public static CharacterMessage constructResponseCreateCharacterSuccessMessage(){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERSUCCESS);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERSUCCESS);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ResponseCreateCharacterFailure
|
||||||
|
*/
|
||||||
public static CharacterMessage parseResponseCreateCharacterFailureMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseResponseCreateCharacterFailureMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERFAILURE);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERFAILURE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ResponseCreateCharacterFailure
|
||||||
|
*/
|
||||||
public static CharacterMessage constructResponseCreateCharacterFailureMessage(){
|
public static CharacterMessage constructResponseCreateCharacterFailureMessage(){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERFAILURE);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERFAILURE);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestSpawnCharacter
|
||||||
|
*/
|
||||||
public static CharacterMessage parseRequestSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseRequestSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestSpawnCharacter
|
||||||
|
*/
|
||||||
public static CharacterMessage constructRequestSpawnCharacterMessage(){
|
public static CharacterMessage constructRequestSpawnCharacterMessage(){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type ResponseSpawnCharacter can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseResponseSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseResponseSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -210,6 +281,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ResponseSpawnCharacter
|
||||||
|
*/
|
||||||
public static CharacterMessage parseResponseSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
public static CharacterMessage parseResponseSpawnCharacterMessage(CircularByteBuffer byteBuffer){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSESPAWNCHARACTER);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSESPAWNCHARACTER);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -217,6 +291,9 @@ public class CharacterMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ResponseSpawnCharacter
|
||||||
|
*/
|
||||||
public static CharacterMessage constructResponseSpawnCharacterMessage(String data){
|
public static CharacterMessage constructResponseSpawnCharacterMessage(String data){
|
||||||
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSESPAWNCHARACTER);
|
CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSESPAWNCHARACTER);
|
||||||
rVal.setdata(data);
|
rVal.setdata(data);
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class CombatMessage extends NetworkMessage {
|
public class CombatMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum CombatMessageType {
|
public enum CombatMessageType {
|
||||||
SERVERREPORTHITBOXCOLLISION,
|
SERVERREPORTHITBOXCOLLISION,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
CombatMessageType messageType;
|
CombatMessageType messageType;
|
||||||
int entityID;
|
int entityID;
|
||||||
int receiverEntityID;
|
int receiverEntityID;
|
||||||
@ -25,6 +31,10 @@ public class CombatMessage extends NetworkMessage {
|
|||||||
String hitboxType;
|
String hitboxType;
|
||||||
String hurtboxType;
|
String hurtboxType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
CombatMessage(CombatMessageType messageType){
|
CombatMessage(CombatMessageType messageType){
|
||||||
this.type = MessageType.COMBAT_MESSAGE;
|
this.type = MessageType.COMBAT_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -34,106 +44,188 @@ public class CombatMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets entityID
|
||||||
|
*/
|
||||||
public int getentityID() {
|
public int getentityID() {
|
||||||
return entityID;
|
return entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entityID
|
||||||
|
*/
|
||||||
public void setentityID(int entityID) {
|
public void setentityID(int entityID) {
|
||||||
this.entityID = entityID;
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets receiverEntityID
|
||||||
|
*/
|
||||||
public int getreceiverEntityID() {
|
public int getreceiverEntityID() {
|
||||||
return receiverEntityID;
|
return receiverEntityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets receiverEntityID
|
||||||
|
*/
|
||||||
public void setreceiverEntityID(int receiverEntityID) {
|
public void setreceiverEntityID(int receiverEntityID) {
|
||||||
this.receiverEntityID = receiverEntityID;
|
this.receiverEntityID = receiverEntityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets positionX
|
||||||
|
*/
|
||||||
public double getpositionX() {
|
public double getpositionX() {
|
||||||
return positionX;
|
return positionX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets positionX
|
||||||
|
*/
|
||||||
public void setpositionX(double positionX) {
|
public void setpositionX(double positionX) {
|
||||||
this.positionX = positionX;
|
this.positionX = positionX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets positionY
|
||||||
|
*/
|
||||||
public double getpositionY() {
|
public double getpositionY() {
|
||||||
return positionY;
|
return positionY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets positionY
|
||||||
|
*/
|
||||||
public void setpositionY(double positionY) {
|
public void setpositionY(double positionY) {
|
||||||
this.positionY = positionY;
|
this.positionY = positionY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets positionZ
|
||||||
|
*/
|
||||||
public double getpositionZ() {
|
public double getpositionZ() {
|
||||||
return positionZ;
|
return positionZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets positionZ
|
||||||
|
*/
|
||||||
public void setpositionZ(double positionZ) {
|
public void setpositionZ(double positionZ) {
|
||||||
this.positionZ = positionZ;
|
this.positionZ = positionZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationX
|
||||||
|
*/
|
||||||
public double getrotationX() {
|
public double getrotationX() {
|
||||||
return rotationX;
|
return rotationX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationX
|
||||||
|
*/
|
||||||
public void setrotationX(double rotationX) {
|
public void setrotationX(double rotationX) {
|
||||||
this.rotationX = rotationX;
|
this.rotationX = rotationX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationY
|
||||||
|
*/
|
||||||
public double getrotationY() {
|
public double getrotationY() {
|
||||||
return rotationY;
|
return rotationY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationY
|
||||||
|
*/
|
||||||
public void setrotationY(double rotationY) {
|
public void setrotationY(double rotationY) {
|
||||||
this.rotationY = rotationY;
|
this.rotationY = rotationY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationZ
|
||||||
|
*/
|
||||||
public double getrotationZ() {
|
public double getrotationZ() {
|
||||||
return rotationZ;
|
return rotationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationZ
|
||||||
|
*/
|
||||||
public void setrotationZ(double rotationZ) {
|
public void setrotationZ(double rotationZ) {
|
||||||
this.rotationZ = rotationZ;
|
this.rotationZ = rotationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationW
|
||||||
|
*/
|
||||||
public double getrotationW() {
|
public double getrotationW() {
|
||||||
return rotationW;
|
return rotationW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationW
|
||||||
|
*/
|
||||||
public void setrotationW(double rotationW) {
|
public void setrotationW(double rotationW) {
|
||||||
this.rotationW = rotationW;
|
this.rotationW = rotationW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets time
|
||||||
|
*/
|
||||||
public long gettime() {
|
public long gettime() {
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets time
|
||||||
|
*/
|
||||||
public void settime(long time) {
|
public void settime(long time) {
|
||||||
this.time = time;
|
this.time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets hitboxType
|
||||||
|
*/
|
||||||
public String gethitboxType() {
|
public String gethitboxType() {
|
||||||
return hitboxType;
|
return hitboxType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets hitboxType
|
||||||
|
*/
|
||||||
public void sethitboxType(String hitboxType) {
|
public void sethitboxType(String hitboxType) {
|
||||||
this.hitboxType = hitboxType;
|
this.hitboxType = hitboxType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets hurtboxType
|
||||||
|
*/
|
||||||
public String gethurtboxType() {
|
public String gethurtboxType() {
|
||||||
return hurtboxType;
|
return hurtboxType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets hurtboxType
|
||||||
|
*/
|
||||||
public void sethurtboxType(String hurtboxType) {
|
public void sethurtboxType(String hurtboxType) {
|
||||||
this.hurtboxType = hurtboxType;
|
this.hurtboxType = hurtboxType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION:
|
case TypeBytes.COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION:
|
||||||
@ -142,6 +234,9 @@ public class CombatMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type serverReportHitboxCollision can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseserverReportHitboxCollisionMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseserverReportHitboxCollisionMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -192,6 +287,9 @@ public class CombatMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type serverReportHitboxCollision
|
||||||
|
*/
|
||||||
public static CombatMessage parseserverReportHitboxCollisionMessage(CircularByteBuffer byteBuffer){
|
public static CombatMessage parseserverReportHitboxCollisionMessage(CircularByteBuffer byteBuffer){
|
||||||
CombatMessage rVal = new CombatMessage(CombatMessageType.SERVERREPORTHITBOXCOLLISION);
|
CombatMessage rVal = new CombatMessage(CombatMessageType.SERVERREPORTHITBOXCOLLISION);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -206,6 +304,9 @@ public class CombatMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type serverReportHitboxCollision
|
||||||
|
*/
|
||||||
public static CombatMessage constructserverReportHitboxCollisionMessage(int entityID,int receiverEntityID,long time,String hitboxType,String hurtboxType,double positionX,double positionY,double positionZ){
|
public static CombatMessage constructserverReportHitboxCollisionMessage(int entityID,int receiverEntityID,long time,String hitboxType,String hurtboxType,double positionX,double positionY,double positionZ){
|
||||||
CombatMessage rVal = new CombatMessage(CombatMessageType.SERVERREPORTHITBOXCOLLISION);
|
CombatMessage rVal = new CombatMessage(CombatMessageType.SERVERREPORTHITBOXCOLLISION);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class EntityMessage extends NetworkMessage {
|
public class EntityMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum EntityMessageType {
|
public enum EntityMessageType {
|
||||||
CREATE,
|
CREATE,
|
||||||
MOVEUPDATE,
|
MOVEUPDATE,
|
||||||
@ -20,6 +23,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
SYNCPHYSICS,
|
SYNCPHYSICS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
EntityMessageType messageType;
|
EntityMessageType messageType;
|
||||||
int entityCategory;
|
int entityCategory;
|
||||||
String entitySubtype;
|
String entitySubtype;
|
||||||
@ -56,6 +62,10 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
int bTreeID;
|
int bTreeID;
|
||||||
int propertyValueInt;
|
int propertyValueInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
EntityMessage(EntityMessageType messageType){
|
EntityMessage(EntityMessageType messageType){
|
||||||
this.type = MessageType.ENTITY_MESSAGE;
|
this.type = MessageType.ENTITY_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -65,282 +75,496 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets entityCategory
|
||||||
|
*/
|
||||||
public int getentityCategory() {
|
public int getentityCategory() {
|
||||||
return entityCategory;
|
return entityCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entityCategory
|
||||||
|
*/
|
||||||
public void setentityCategory(int entityCategory) {
|
public void setentityCategory(int entityCategory) {
|
||||||
this.entityCategory = entityCategory;
|
this.entityCategory = entityCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets entitySubtype
|
||||||
|
*/
|
||||||
public String getentitySubtype() {
|
public String getentitySubtype() {
|
||||||
return entitySubtype;
|
return entitySubtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entitySubtype
|
||||||
|
*/
|
||||||
public void setentitySubtype(String entitySubtype) {
|
public void setentitySubtype(String entitySubtype) {
|
||||||
this.entitySubtype = entitySubtype;
|
this.entitySubtype = entitySubtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets entityID
|
||||||
|
*/
|
||||||
public int getentityID() {
|
public int getentityID() {
|
||||||
return entityID;
|
return entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entityID
|
||||||
|
*/
|
||||||
public void setentityID(int entityID) {
|
public void setentityID(int entityID) {
|
||||||
this.entityID = entityID;
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets creatureTemplate
|
||||||
|
*/
|
||||||
public String getcreatureTemplate() {
|
public String getcreatureTemplate() {
|
||||||
return creatureTemplate;
|
return creatureTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets creatureTemplate
|
||||||
|
*/
|
||||||
public void setcreatureTemplate(String creatureTemplate) {
|
public void setcreatureTemplate(String creatureTemplate) {
|
||||||
this.creatureTemplate = creatureTemplate;
|
this.creatureTemplate = creatureTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets positionX
|
||||||
|
*/
|
||||||
public double getpositionX() {
|
public double getpositionX() {
|
||||||
return positionX;
|
return positionX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets positionX
|
||||||
|
*/
|
||||||
public void setpositionX(double positionX) {
|
public void setpositionX(double positionX) {
|
||||||
this.positionX = positionX;
|
this.positionX = positionX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets positionY
|
||||||
|
*/
|
||||||
public double getpositionY() {
|
public double getpositionY() {
|
||||||
return positionY;
|
return positionY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets positionY
|
||||||
|
*/
|
||||||
public void setpositionY(double positionY) {
|
public void setpositionY(double positionY) {
|
||||||
this.positionY = positionY;
|
this.positionY = positionY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets positionZ
|
||||||
|
*/
|
||||||
public double getpositionZ() {
|
public double getpositionZ() {
|
||||||
return positionZ;
|
return positionZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets positionZ
|
||||||
|
*/
|
||||||
public void setpositionZ(double positionZ) {
|
public void setpositionZ(double positionZ) {
|
||||||
this.positionZ = positionZ;
|
this.positionZ = positionZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationX
|
||||||
|
*/
|
||||||
public double getrotationX() {
|
public double getrotationX() {
|
||||||
return rotationX;
|
return rotationX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationX
|
||||||
|
*/
|
||||||
public void setrotationX(double rotationX) {
|
public void setrotationX(double rotationX) {
|
||||||
this.rotationX = rotationX;
|
this.rotationX = rotationX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationY
|
||||||
|
*/
|
||||||
public double getrotationY() {
|
public double getrotationY() {
|
||||||
return rotationY;
|
return rotationY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationY
|
||||||
|
*/
|
||||||
public void setrotationY(double rotationY) {
|
public void setrotationY(double rotationY) {
|
||||||
this.rotationY = rotationY;
|
this.rotationY = rotationY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationZ
|
||||||
|
*/
|
||||||
public double getrotationZ() {
|
public double getrotationZ() {
|
||||||
return rotationZ;
|
return rotationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationZ
|
||||||
|
*/
|
||||||
public void setrotationZ(double rotationZ) {
|
public void setrotationZ(double rotationZ) {
|
||||||
this.rotationZ = rotationZ;
|
this.rotationZ = rotationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets rotationW
|
||||||
|
*/
|
||||||
public double getrotationW() {
|
public double getrotationW() {
|
||||||
return rotationW;
|
return rotationW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets rotationW
|
||||||
|
*/
|
||||||
public void setrotationW(double rotationW) {
|
public void setrotationW(double rotationW) {
|
||||||
this.rotationW = rotationW;
|
this.rotationW = rotationW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets linVelX
|
||||||
|
*/
|
||||||
public double getlinVelX() {
|
public double getlinVelX() {
|
||||||
return linVelX;
|
return linVelX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets linVelX
|
||||||
|
*/
|
||||||
public void setlinVelX(double linVelX) {
|
public void setlinVelX(double linVelX) {
|
||||||
this.linVelX = linVelX;
|
this.linVelX = linVelX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets linVelY
|
||||||
|
*/
|
||||||
public double getlinVelY() {
|
public double getlinVelY() {
|
||||||
return linVelY;
|
return linVelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets linVelY
|
||||||
|
*/
|
||||||
public void setlinVelY(double linVelY) {
|
public void setlinVelY(double linVelY) {
|
||||||
this.linVelY = linVelY;
|
this.linVelY = linVelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets linVelZ
|
||||||
|
*/
|
||||||
public double getlinVelZ() {
|
public double getlinVelZ() {
|
||||||
return linVelZ;
|
return linVelZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets linVelZ
|
||||||
|
*/
|
||||||
public void setlinVelZ(double linVelZ) {
|
public void setlinVelZ(double linVelZ) {
|
||||||
this.linVelZ = linVelZ;
|
this.linVelZ = linVelZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets angVelX
|
||||||
|
*/
|
||||||
public double getangVelX() {
|
public double getangVelX() {
|
||||||
return angVelX;
|
return angVelX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets angVelX
|
||||||
|
*/
|
||||||
public void setangVelX(double angVelX) {
|
public void setangVelX(double angVelX) {
|
||||||
this.angVelX = angVelX;
|
this.angVelX = angVelX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets angVelY
|
||||||
|
*/
|
||||||
public double getangVelY() {
|
public double getangVelY() {
|
||||||
return angVelY;
|
return angVelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets angVelY
|
||||||
|
*/
|
||||||
public void setangVelY(double angVelY) {
|
public void setangVelY(double angVelY) {
|
||||||
this.angVelY = angVelY;
|
this.angVelY = angVelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets angVelZ
|
||||||
|
*/
|
||||||
public double getangVelZ() {
|
public double getangVelZ() {
|
||||||
return angVelZ;
|
return angVelZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets angVelZ
|
||||||
|
*/
|
||||||
public void setangVelZ(double angVelZ) {
|
public void setangVelZ(double angVelZ) {
|
||||||
this.angVelZ = angVelZ;
|
this.angVelZ = angVelZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets linForceX
|
||||||
|
*/
|
||||||
public double getlinForceX() {
|
public double getlinForceX() {
|
||||||
return linForceX;
|
return linForceX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets linForceX
|
||||||
|
*/
|
||||||
public void setlinForceX(double linForceX) {
|
public void setlinForceX(double linForceX) {
|
||||||
this.linForceX = linForceX;
|
this.linForceX = linForceX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets linForceY
|
||||||
|
*/
|
||||||
public double getlinForceY() {
|
public double getlinForceY() {
|
||||||
return linForceY;
|
return linForceY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets linForceY
|
||||||
|
*/
|
||||||
public void setlinForceY(double linForceY) {
|
public void setlinForceY(double linForceY) {
|
||||||
this.linForceY = linForceY;
|
this.linForceY = linForceY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets linForceZ
|
||||||
|
*/
|
||||||
public double getlinForceZ() {
|
public double getlinForceZ() {
|
||||||
return linForceZ;
|
return linForceZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets linForceZ
|
||||||
|
*/
|
||||||
public void setlinForceZ(double linForceZ) {
|
public void setlinForceZ(double linForceZ) {
|
||||||
this.linForceZ = linForceZ;
|
this.linForceZ = linForceZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets angForceX
|
||||||
|
*/
|
||||||
public double getangForceX() {
|
public double getangForceX() {
|
||||||
return angForceX;
|
return angForceX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets angForceX
|
||||||
|
*/
|
||||||
public void setangForceX(double angForceX) {
|
public void setangForceX(double angForceX) {
|
||||||
this.angForceX = angForceX;
|
this.angForceX = angForceX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets angForceY
|
||||||
|
*/
|
||||||
public double getangForceY() {
|
public double getangForceY() {
|
||||||
return angForceY;
|
return angForceY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets angForceY
|
||||||
|
*/
|
||||||
public void setangForceY(double angForceY) {
|
public void setangForceY(double angForceY) {
|
||||||
this.angForceY = angForceY;
|
this.angForceY = angForceY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets angForceZ
|
||||||
|
*/
|
||||||
public double getangForceZ() {
|
public double getangForceZ() {
|
||||||
return angForceZ;
|
return angForceZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets angForceZ
|
||||||
|
*/
|
||||||
public void setangForceZ(double angForceZ) {
|
public void setangForceZ(double angForceZ) {
|
||||||
this.angForceZ = angForceZ;
|
this.angForceZ = angForceZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets yaw
|
||||||
|
*/
|
||||||
public double getyaw() {
|
public double getyaw() {
|
||||||
return yaw;
|
return yaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets yaw
|
||||||
|
*/
|
||||||
public void setyaw(double yaw) {
|
public void setyaw(double yaw) {
|
||||||
this.yaw = yaw;
|
this.yaw = yaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets pitch
|
||||||
|
*/
|
||||||
public double getpitch() {
|
public double getpitch() {
|
||||||
return pitch;
|
return pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets pitch
|
||||||
|
*/
|
||||||
public void setpitch(double pitch) {
|
public void setpitch(double pitch) {
|
||||||
this.pitch = pitch;
|
this.pitch = pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets velocity
|
||||||
|
*/
|
||||||
public double getvelocity() {
|
public double getvelocity() {
|
||||||
return velocity;
|
return velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets velocity
|
||||||
|
*/
|
||||||
public void setvelocity(double velocity) {
|
public void setvelocity(double velocity) {
|
||||||
this.velocity = velocity;
|
this.velocity = velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets treeState
|
||||||
|
*/
|
||||||
public int gettreeState() {
|
public int gettreeState() {
|
||||||
return treeState;
|
return treeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets treeState
|
||||||
|
*/
|
||||||
public void settreeState(int treeState) {
|
public void settreeState(int treeState) {
|
||||||
this.treeState = treeState;
|
this.treeState = treeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets propertyType
|
||||||
|
*/
|
||||||
public int getpropertyType() {
|
public int getpropertyType() {
|
||||||
return propertyType;
|
return propertyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets propertyType
|
||||||
|
*/
|
||||||
public void setpropertyType(int propertyType) {
|
public void setpropertyType(int propertyType) {
|
||||||
this.propertyType = propertyType;
|
this.propertyType = propertyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets propertyValue
|
||||||
|
*/
|
||||||
public int getpropertyValue() {
|
public int getpropertyValue() {
|
||||||
return propertyValue;
|
return propertyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets propertyValue
|
||||||
|
*/
|
||||||
public void setpropertyValue(int propertyValue) {
|
public void setpropertyValue(int propertyValue) {
|
||||||
this.propertyValue = propertyValue;
|
this.propertyValue = propertyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets time
|
||||||
|
*/
|
||||||
public long gettime() {
|
public long gettime() {
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets time
|
||||||
|
*/
|
||||||
public void settime(long time) {
|
public void settime(long time) {
|
||||||
this.time = time;
|
this.time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets bone
|
||||||
|
*/
|
||||||
public String getbone() {
|
public String getbone() {
|
||||||
return bone;
|
return bone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets bone
|
||||||
|
*/
|
||||||
public void setbone(String bone) {
|
public void setbone(String bone) {
|
||||||
this.bone = bone;
|
this.bone = bone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets targetID
|
||||||
|
*/
|
||||||
public int gettargetID() {
|
public int gettargetID() {
|
||||||
return targetID;
|
return targetID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets targetID
|
||||||
|
*/
|
||||||
public void settargetID(int targetID) {
|
public void settargetID(int targetID) {
|
||||||
this.targetID = targetID;
|
this.targetID = targetID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets bTreeID
|
||||||
|
*/
|
||||||
public int getbTreeID() {
|
public int getbTreeID() {
|
||||||
return bTreeID;
|
return bTreeID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets bTreeID
|
||||||
|
*/
|
||||||
public void setbTreeID(int bTreeID) {
|
public void setbTreeID(int bTreeID) {
|
||||||
this.bTreeID = bTreeID;
|
this.bTreeID = bTreeID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets propertyValueInt
|
||||||
|
*/
|
||||||
public int getpropertyValueInt() {
|
public int getpropertyValueInt() {
|
||||||
return propertyValueInt;
|
return propertyValueInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets propertyValueInt
|
||||||
|
*/
|
||||||
public void setpropertyValueInt(int propertyValueInt) {
|
public void setpropertyValueInt(int propertyValueInt) {
|
||||||
this.propertyValueInt = propertyValueInt;
|
this.propertyValueInt = propertyValueInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.ENTITY_MESSAGE_TYPE_CREATE:
|
case TypeBytes.ENTITY_MESSAGE_TYPE_CREATE:
|
||||||
@ -399,6 +623,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type Create can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseCreateMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseCreateMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -458,6 +685,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type Create
|
||||||
|
*/
|
||||||
public static EntityMessage parseCreateMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parseCreateMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.CREATE);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.CREATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -475,6 +705,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type Create
|
||||||
|
*/
|
||||||
public static EntityMessage constructCreateMessage(int entityID,int entityCategory,String entitySubtype,String creatureTemplate,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW){
|
public static EntityMessage constructCreateMessage(int entityID,int entityCategory,String entitySubtype,String creatureTemplate,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.CREATE);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.CREATE);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -492,6 +725,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type moveUpdate
|
||||||
|
*/
|
||||||
public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -510,6 +746,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type moveUpdate
|
||||||
|
*/
|
||||||
public static EntityMessage constructmoveUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double velocity,int propertyValueInt,int treeState){
|
public static EntityMessage constructmoveUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double velocity,int propertyValueInt,int treeState){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -528,6 +767,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type attackUpdate
|
||||||
|
*/
|
||||||
public static EntityMessage parseattackUpdateMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parseattackUpdateMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACKUPDATE);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACKUPDATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -544,6 +786,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type attackUpdate
|
||||||
|
*/
|
||||||
public static EntityMessage constructattackUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double velocity,int treeState){
|
public static EntityMessage constructattackUpdateMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double velocity,int treeState){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACKUPDATE);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACKUPDATE);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -560,18 +805,27 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type startAttack
|
||||||
|
*/
|
||||||
public static EntityMessage parsestartAttackMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parsestartAttackMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.STARTATTACK);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.STARTATTACK);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type startAttack
|
||||||
|
*/
|
||||||
public static EntityMessage constructstartAttackMessage(){
|
public static EntityMessage constructstartAttackMessage(){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.STARTATTACK);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.STARTATTACK);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type Kill
|
||||||
|
*/
|
||||||
public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -580,6 +834,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type Kill
|
||||||
|
*/
|
||||||
public static EntityMessage constructKillMessage(long time,int entityID){
|
public static EntityMessage constructKillMessage(long time,int entityID){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
|
||||||
rVal.settime(time);
|
rVal.settime(time);
|
||||||
@ -588,6 +845,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type Destroy
|
||||||
|
*/
|
||||||
public static EntityMessage parseDestroyMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parseDestroyMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.DESTROY);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.DESTROY);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -595,6 +855,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type Destroy
|
||||||
|
*/
|
||||||
public static EntityMessage constructDestroyMessage(int entityID){
|
public static EntityMessage constructDestroyMessage(int entityID){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.DESTROY);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.DESTROY);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -602,6 +865,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type setProperty
|
||||||
|
*/
|
||||||
public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -612,6 +878,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type setProperty
|
||||||
|
*/
|
||||||
public static EntityMessage constructsetPropertyMessage(int entityID,long time,int propertyType,int propertyValue){
|
public static EntityMessage constructsetPropertyMessage(int entityID,long time,int propertyType,int propertyValue){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -622,6 +891,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type attachEntityToEntity can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -647,6 +919,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type attachEntityToEntity
|
||||||
|
*/
|
||||||
public static EntityMessage parseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACHENTITYTOENTITY);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACHENTITYTOENTITY);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -656,6 +931,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type attachEntityToEntity
|
||||||
|
*/
|
||||||
public static EntityMessage constructattachEntityToEntityMessage(int entityID,String bone,int targetID){
|
public static EntityMessage constructattachEntityToEntityMessage(int entityID,String bone,int targetID){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACHENTITYTOENTITY);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACHENTITYTOENTITY);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -665,6 +943,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type updateEntityViewDir
|
||||||
|
*/
|
||||||
public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -676,6 +957,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type updateEntityViewDir
|
||||||
|
*/
|
||||||
public static EntityMessage constructupdateEntityViewDirMessage(int entityID,long time,int propertyType,double yaw,double pitch){
|
public static EntityMessage constructupdateEntityViewDirMessage(int entityID,long time,int propertyType,double yaw,double pitch){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
@ -687,6 +971,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type syncPhysics
|
||||||
|
*/
|
||||||
public static EntityMessage parsesyncPhysicsMessage(CircularByteBuffer byteBuffer){
|
public static EntityMessage parsesyncPhysicsMessage(CircularByteBuffer byteBuffer){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -714,6 +1001,9 @@ public class EntityMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type syncPhysics
|
||||||
|
*/
|
||||||
public static EntityMessage constructsyncPhysicsMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double linVelX,double linVelY,double linVelZ,double angVelX,double angVelY,double angVelZ,double linForceX,double linForceY,double linForceZ,double angForceX,double angForceY,double angForceZ){
|
public static EntityMessage constructsyncPhysicsMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double linVelX,double linVelY,double linVelZ,double angVelX,double angVelY,double angVelZ,double linForceX,double linForceY,double linForceZ,double angForceX,double angForceY,double angForceZ){
|
||||||
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
|
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
|
||||||
rVal.setentityID(entityID);
|
rVal.setentityID(entityID);
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class InventoryMessage extends NetworkMessage {
|
public class InventoryMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum InventoryMessageType {
|
public enum InventoryMessageType {
|
||||||
ADDITEMTOINVENTORY,
|
ADDITEMTOINVENTORY,
|
||||||
REMOVEITEMFROMINVENTORY,
|
REMOVEITEMFROMINVENTORY,
|
||||||
@ -21,6 +24,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
CLIENTREQUESTPERFORMITEMACTION,
|
CLIENTREQUESTPERFORMITEMACTION,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
InventoryMessageType messageType;
|
InventoryMessageType messageType;
|
||||||
String itemTemplate;
|
String itemTemplate;
|
||||||
String equipPointId;
|
String equipPointId;
|
||||||
@ -31,6 +37,10 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
int itemActionCode;
|
int itemActionCode;
|
||||||
int itemActionCodeState;
|
int itemActionCodeState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
InventoryMessage(InventoryMessageType messageType){
|
InventoryMessage(InventoryMessageType messageType){
|
||||||
this.type = MessageType.INVENTORY_MESSAGE;
|
this.type = MessageType.INVENTORY_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -40,74 +50,132 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets itemTemplate
|
||||||
|
*/
|
||||||
public String getitemTemplate() {
|
public String getitemTemplate() {
|
||||||
return itemTemplate;
|
return itemTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets itemTemplate
|
||||||
|
*/
|
||||||
public void setitemTemplate(String itemTemplate) {
|
public void setitemTemplate(String itemTemplate) {
|
||||||
this.itemTemplate = itemTemplate;
|
this.itemTemplate = itemTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets equipPointId
|
||||||
|
*/
|
||||||
public String getequipPointId() {
|
public String getequipPointId() {
|
||||||
return equipPointId;
|
return equipPointId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets equipPointId
|
||||||
|
*/
|
||||||
public void setequipPointId(String equipPointId) {
|
public void setequipPointId(String equipPointId) {
|
||||||
this.equipPointId = equipPointId;
|
this.equipPointId = equipPointId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets entityId
|
||||||
|
*/
|
||||||
public int getentityId() {
|
public int getentityId() {
|
||||||
return entityId;
|
return entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entityId
|
||||||
|
*/
|
||||||
public void setentityId(int entityId) {
|
public void setentityId(int entityId) {
|
||||||
this.entityId = entityId;
|
this.entityId = entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets equipperId
|
||||||
|
*/
|
||||||
public int getequipperId() {
|
public int getequipperId() {
|
||||||
return equipperId;
|
return equipperId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets equipperId
|
||||||
|
*/
|
||||||
public void setequipperId(int equipperId) {
|
public void setequipperId(int equipperId) {
|
||||||
this.equipperId = equipperId;
|
this.equipperId = equipperId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets containerType
|
||||||
|
*/
|
||||||
public int getcontainerType() {
|
public int getcontainerType() {
|
||||||
return containerType;
|
return containerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets containerType
|
||||||
|
*/
|
||||||
public void setcontainerType(int containerType) {
|
public void setcontainerType(int containerType) {
|
||||||
this.containerType = containerType;
|
this.containerType = containerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets toolbarId
|
||||||
|
*/
|
||||||
public int gettoolbarId() {
|
public int gettoolbarId() {
|
||||||
return toolbarId;
|
return toolbarId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets toolbarId
|
||||||
|
*/
|
||||||
public void settoolbarId(int toolbarId) {
|
public void settoolbarId(int toolbarId) {
|
||||||
this.toolbarId = toolbarId;
|
this.toolbarId = toolbarId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets itemActionCode
|
||||||
|
*/
|
||||||
public int getitemActionCode() {
|
public int getitemActionCode() {
|
||||||
return itemActionCode;
|
return itemActionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets itemActionCode
|
||||||
|
*/
|
||||||
public void setitemActionCode(int itemActionCode) {
|
public void setitemActionCode(int itemActionCode) {
|
||||||
this.itemActionCode = itemActionCode;
|
this.itemActionCode = itemActionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets itemActionCodeState
|
||||||
|
*/
|
||||||
public int getitemActionCodeState() {
|
public int getitemActionCodeState() {
|
||||||
return itemActionCodeState;
|
return itemActionCodeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets itemActionCodeState
|
||||||
|
*/
|
||||||
public void setitemActionCodeState(int itemActionCodeState) {
|
public void setitemActionCodeState(int itemActionCodeState) {
|
||||||
this.itemActionCodeState = itemActionCodeState;
|
this.itemActionCodeState = itemActionCodeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY:
|
case TypeBytes.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY:
|
||||||
@ -152,6 +220,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type addItemToInventory can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseaddItemToInventoryMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseaddItemToInventoryMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -174,6 +245,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type addItemToInventory
|
||||||
|
*/
|
||||||
public static InventoryMessage parseaddItemToInventoryMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseaddItemToInventoryMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -182,6 +256,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type addItemToInventory
|
||||||
|
*/
|
||||||
public static InventoryMessage constructaddItemToInventoryMessage(int entityId,String itemTemplate){
|
public static InventoryMessage constructaddItemToInventoryMessage(int entityId,String itemTemplate){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -190,6 +267,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type removeItemFromInventory
|
||||||
|
*/
|
||||||
public static InventoryMessage parseremoveItemFromInventoryMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseremoveItemFromInventoryMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -197,6 +277,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type removeItemFromInventory
|
||||||
|
*/
|
||||||
public static InventoryMessage constructremoveItemFromInventoryMessage(int entityId){
|
public static InventoryMessage constructremoveItemFromInventoryMessage(int entityId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -204,6 +287,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type clientRequestEquipItem can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseclientRequestEquipItemMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseclientRequestEquipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -226,6 +312,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type clientRequestEquipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage parseclientRequestEquipItemMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseclientRequestEquipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTEQUIPITEM);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -234,6 +323,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type clientRequestEquipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage constructclientRequestEquipItemMessage(String equipPointId,int entityId){
|
public static InventoryMessage constructclientRequestEquipItemMessage(String equipPointId,int entityId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTEQUIPITEM);
|
||||||
rVal.setequipPointId(equipPointId);
|
rVal.setequipPointId(equipPointId);
|
||||||
@ -242,6 +334,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type serverCommandMoveItemContainer can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseserverCommandMoveItemContainerMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseserverCommandMoveItemContainerMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -267,6 +362,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type serverCommandMoveItemContainer
|
||||||
|
*/
|
||||||
public static InventoryMessage parseserverCommandMoveItemContainerMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseserverCommandMoveItemContainerMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDMOVEITEMCONTAINER);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDMOVEITEMCONTAINER);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -276,6 +374,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type serverCommandMoveItemContainer
|
||||||
|
*/
|
||||||
public static InventoryMessage constructserverCommandMoveItemContainerMessage(int entityId,int containerType,String equipPointId){
|
public static InventoryMessage constructserverCommandMoveItemContainerMessage(int entityId,int containerType,String equipPointId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDMOVEITEMCONTAINER);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDMOVEITEMCONTAINER);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -285,6 +386,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type serverCommandEquipItem can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseserverCommandEquipItemMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseserverCommandEquipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -326,6 +430,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type serverCommandEquipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage parseserverCommandEquipItemMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseserverCommandEquipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDEQUIPITEM);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -337,6 +444,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type serverCommandEquipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage constructserverCommandEquipItemMessage(int equipperId,int containerType,String equipPointId,int entityId,String itemTemplate){
|
public static InventoryMessage constructserverCommandEquipItemMessage(int equipperId,int containerType,String equipPointId,int entityId,String itemTemplate){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDEQUIPITEM);
|
||||||
rVal.setequipperId(equipperId);
|
rVal.setequipperId(equipperId);
|
||||||
@ -348,6 +458,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type serverCommandUnequipItem can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseserverCommandUnequipItemMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseserverCommandUnequipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -373,6 +486,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type serverCommandUnequipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage parseserverCommandUnequipItemMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseserverCommandUnequipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDUNEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDUNEQUIPITEM);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -382,6 +498,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type serverCommandUnequipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage constructserverCommandUnequipItemMessage(int equipperId,int containerType,String equipPointId){
|
public static InventoryMessage constructserverCommandUnequipItemMessage(int equipperId,int containerType,String equipPointId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDUNEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDUNEQUIPITEM);
|
||||||
rVal.setequipperId(equipperId);
|
rVal.setequipperId(equipperId);
|
||||||
@ -391,6 +510,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type clientRequestUnequipItem can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseclientRequestUnequipItemMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseclientRequestUnequipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -410,6 +532,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type clientRequestUnequipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage parseclientRequestUnequipItemMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseclientRequestUnequipItemMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTUNEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTUNEQUIPITEM);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -417,6 +542,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type clientRequestUnequipItem
|
||||||
|
*/
|
||||||
public static InventoryMessage constructclientRequestUnequipItemMessage(String equipPointId){
|
public static InventoryMessage constructclientRequestUnequipItemMessage(String equipPointId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTUNEQUIPITEM);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTUNEQUIPITEM);
|
||||||
rVal.setequipPointId(equipPointId);
|
rVal.setequipPointId(equipPointId);
|
||||||
@ -424,6 +552,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type clientRequestAddToolbar
|
||||||
|
*/
|
||||||
public static InventoryMessage parseclientRequestAddToolbarMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseclientRequestAddToolbarMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDTOOLBAR);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDTOOLBAR);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -432,6 +563,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type clientRequestAddToolbar
|
||||||
|
*/
|
||||||
public static InventoryMessage constructclientRequestAddToolbarMessage(int entityId,int toolbarId){
|
public static InventoryMessage constructclientRequestAddToolbarMessage(int entityId,int toolbarId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDTOOLBAR);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDTOOLBAR);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -440,6 +574,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type clientRequestAddNatural
|
||||||
|
*/
|
||||||
public static InventoryMessage parseclientRequestAddNaturalMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseclientRequestAddNaturalMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDNATURAL);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDNATURAL);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -447,6 +584,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type clientRequestAddNatural
|
||||||
|
*/
|
||||||
public static InventoryMessage constructclientRequestAddNaturalMessage(int entityId){
|
public static InventoryMessage constructclientRequestAddNaturalMessage(int entityId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDNATURAL);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDNATURAL);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -454,6 +594,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type clientUpdateToolbar
|
||||||
|
*/
|
||||||
public static InventoryMessage parseclientUpdateToolbarMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseclientUpdateToolbarMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTUPDATETOOLBAR);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTUPDATETOOLBAR);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -461,6 +604,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type clientUpdateToolbar
|
||||||
|
*/
|
||||||
public static InventoryMessage constructclientUpdateToolbarMessage(int toolbarId){
|
public static InventoryMessage constructclientUpdateToolbarMessage(int toolbarId){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTUPDATETOOLBAR);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTUPDATETOOLBAR);
|
||||||
rVal.settoolbarId(toolbarId);
|
rVal.settoolbarId(toolbarId);
|
||||||
@ -468,6 +614,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type clientRequestPerformItemAction can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseclientRequestPerformItemActionMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseclientRequestPerformItemActionMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -493,6 +642,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type clientRequestPerformItemAction
|
||||||
|
*/
|
||||||
public static InventoryMessage parseclientRequestPerformItemActionMessage(CircularByteBuffer byteBuffer){
|
public static InventoryMessage parseclientRequestPerformItemActionMessage(CircularByteBuffer byteBuffer){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTPERFORMITEMACTION);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTPERFORMITEMACTION);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -502,6 +654,9 @@ public class InventoryMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type clientRequestPerformItemAction
|
||||||
|
*/
|
||||||
public static InventoryMessage constructclientRequestPerformItemActionMessage(String equipPointId,int itemActionCode,int itemActionCodeState){
|
public static InventoryMessage constructclientRequestPerformItemActionMessage(String equipPointId,int itemActionCode,int itemActionCodeState){
|
||||||
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTPERFORMITEMACTION);
|
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTPERFORMITEMACTION);
|
||||||
rVal.setequipPointId(equipPointId);
|
rVal.setequipPointId(equipPointId);
|
||||||
|
|||||||
@ -1,20 +1,30 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class LoreMessage extends NetworkMessage {
|
public class LoreMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum LoreMessageType {
|
public enum LoreMessageType {
|
||||||
REQUESTRACES,
|
REQUESTRACES,
|
||||||
RESPONSERACES,
|
RESPONSERACES,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
LoreMessageType messageType;
|
LoreMessageType messageType;
|
||||||
String data;
|
String data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
LoreMessage(LoreMessageType messageType){
|
LoreMessage(LoreMessageType messageType){
|
||||||
this.type = MessageType.LORE_MESSAGE;
|
this.type = MessageType.LORE_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -24,18 +34,34 @@ public class LoreMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets data
|
||||||
|
*/
|
||||||
public String getdata() {
|
public String getdata() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets data
|
||||||
|
*/
|
||||||
public void setdata(String data) {
|
public void setdata(String data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.LORE_MESSAGE_TYPE_REQUESTRACES:
|
case TypeBytes.LORE_MESSAGE_TYPE_REQUESTRACES:
|
||||||
@ -50,18 +76,27 @@ public class LoreMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestRaces
|
||||||
|
*/
|
||||||
public static LoreMessage parseRequestRacesMessage(CircularByteBuffer byteBuffer){
|
public static LoreMessage parseRequestRacesMessage(CircularByteBuffer byteBuffer){
|
||||||
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTRACES);
|
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTRACES);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestRaces
|
||||||
|
*/
|
||||||
public static LoreMessage constructRequestRacesMessage(){
|
public static LoreMessage constructRequestRacesMessage(){
|
||||||
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTRACES);
|
LoreMessage rVal = new LoreMessage(LoreMessageType.REQUESTRACES);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type ResponseRaces can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseResponseRacesMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseResponseRacesMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -81,6 +116,9 @@ public class LoreMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ResponseRaces
|
||||||
|
*/
|
||||||
public static LoreMessage parseResponseRacesMessage(CircularByteBuffer byteBuffer){
|
public static LoreMessage parseResponseRacesMessage(CircularByteBuffer byteBuffer){
|
||||||
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSERACES);
|
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSERACES);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -88,6 +126,9 @@ public class LoreMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ResponseRaces
|
||||||
|
*/
|
||||||
public static LoreMessage constructResponseRacesMessage(String data){
|
public static LoreMessage constructResponseRacesMessage(String data){
|
||||||
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSERACES);
|
LoreMessage rVal = new LoreMessage(LoreMessageType.RESPONSERACES);
|
||||||
rVal.setdata(data);
|
rVal.setdata(data);
|
||||||
|
|||||||
@ -1,37 +1,64 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A network message
|
||||||
|
*/
|
||||||
public abstract class NetworkMessage {
|
public abstract class NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The different categories of network messages
|
||||||
|
*/
|
||||||
public enum MessageType {
|
public enum MessageType {
|
||||||
ENTITY_MESSAGE,
|
ENTITY_MESSAGE,
|
||||||
LORE_MESSAGE,
|
LORE_MESSAGE,
|
||||||
PLAYER_MESSAGE,
|
PLAYER_MESSAGE,
|
||||||
TERRAIN_MESSAGE,
|
TERRAIN_MESSAGE,
|
||||||
SERVER_MESSAGE,
|
SERVER_MESSAGE,
|
||||||
AUTH_MESSAGE,
|
AUTH_MESSAGE,
|
||||||
CHARACTER_MESSAGE,
|
CHARACTER_MESSAGE,
|
||||||
INVENTORY_MESSAGE,
|
INVENTORY_MESSAGE,
|
||||||
SYNCHRONIZATION_MESSAGE,
|
SYNCHRONIZATION_MESSAGE,
|
||||||
COMBAT_MESSAGE,
|
COMBAT_MESSAGE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message
|
||||||
|
*/
|
||||||
MessageType type;
|
MessageType type;
|
||||||
boolean serialized; // has this message been converted to bytes?
|
|
||||||
|
/**
|
||||||
|
* Tracks whether the message has been serialized to bytes or not
|
||||||
|
*/
|
||||||
|
boolean serialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw bytes contained in the message
|
||||||
|
*/
|
||||||
byte[] rawBytes;
|
byte[] rawBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of the message
|
||||||
|
* @return The type of the message
|
||||||
|
*/
|
||||||
public MessageType getType() {
|
public MessageType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the raw bytes of the message
|
||||||
|
* @return The raw bytes
|
||||||
|
*/
|
||||||
public byte[] getRawBytes() {
|
public byte[] getRawBytes() {
|
||||||
return rawBytes;
|
return rawBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the byte stream for the next message
|
||||||
|
* @param byteBuffer The byte buffer
|
||||||
|
* @return The message if one is at the front of the byte stream, null otherwise
|
||||||
|
*/
|
||||||
public static NetworkMessage parseBytestreamForMessage(CircularByteBuffer byteBuffer){
|
public static NetworkMessage parseBytestreamForMessage(CircularByteBuffer byteBuffer){
|
||||||
NetworkMessage rVal = null;
|
NetworkMessage rVal = null;
|
||||||
byte firstByte;
|
byte firstByte;
|
||||||
@ -409,10 +436,17 @@ COMBAT_MESSAGE,
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message is serialized or not
|
||||||
|
* @return true if it is serialized, false otherwise
|
||||||
|
*/
|
||||||
public boolean isSerialized(){
|
public boolean isSerialized(){
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the message
|
||||||
|
*/
|
||||||
abstract void serialize();
|
abstract void serialize();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,30 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PlayerMessage extends NetworkMessage {
|
public class PlayerMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum PlayerMessageType {
|
public enum PlayerMessageType {
|
||||||
SET_ID,
|
SET_ID,
|
||||||
SETINITIALDISCRETEPOSITION,
|
SETINITIALDISCRETEPOSITION,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
PlayerMessageType messageType;
|
PlayerMessageType messageType;
|
||||||
int playerID;
|
int playerID;
|
||||||
int initialDiscretePositionX;
|
int initialDiscretePositionX;
|
||||||
int initialDiscretePositionY;
|
int initialDiscretePositionY;
|
||||||
int initialDiscretePositionZ;
|
int initialDiscretePositionZ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
PlayerMessage(PlayerMessageType messageType){
|
PlayerMessage(PlayerMessageType messageType){
|
||||||
this.type = MessageType.PLAYER_MESSAGE;
|
this.type = MessageType.PLAYER_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -27,42 +34,76 @@ public class PlayerMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets playerID
|
||||||
|
*/
|
||||||
public int getplayerID() {
|
public int getplayerID() {
|
||||||
return playerID;
|
return playerID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets playerID
|
||||||
|
*/
|
||||||
public void setplayerID(int playerID) {
|
public void setplayerID(int playerID) {
|
||||||
this.playerID = playerID;
|
this.playerID = playerID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets initialDiscretePositionX
|
||||||
|
*/
|
||||||
public int getinitialDiscretePositionX() {
|
public int getinitialDiscretePositionX() {
|
||||||
return initialDiscretePositionX;
|
return initialDiscretePositionX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets initialDiscretePositionX
|
||||||
|
*/
|
||||||
public void setinitialDiscretePositionX(int initialDiscretePositionX) {
|
public void setinitialDiscretePositionX(int initialDiscretePositionX) {
|
||||||
this.initialDiscretePositionX = initialDiscretePositionX;
|
this.initialDiscretePositionX = initialDiscretePositionX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets initialDiscretePositionY
|
||||||
|
*/
|
||||||
public int getinitialDiscretePositionY() {
|
public int getinitialDiscretePositionY() {
|
||||||
return initialDiscretePositionY;
|
return initialDiscretePositionY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets initialDiscretePositionY
|
||||||
|
*/
|
||||||
public void setinitialDiscretePositionY(int initialDiscretePositionY) {
|
public void setinitialDiscretePositionY(int initialDiscretePositionY) {
|
||||||
this.initialDiscretePositionY = initialDiscretePositionY;
|
this.initialDiscretePositionY = initialDiscretePositionY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets initialDiscretePositionZ
|
||||||
|
*/
|
||||||
public int getinitialDiscretePositionZ() {
|
public int getinitialDiscretePositionZ() {
|
||||||
return initialDiscretePositionZ;
|
return initialDiscretePositionZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets initialDiscretePositionZ
|
||||||
|
*/
|
||||||
public void setinitialDiscretePositionZ(int initialDiscretePositionZ) {
|
public void setinitialDiscretePositionZ(int initialDiscretePositionZ) {
|
||||||
this.initialDiscretePositionZ = initialDiscretePositionZ;
|
this.initialDiscretePositionZ = initialDiscretePositionZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.PLAYER_MESSAGE_TYPE_SET_ID:
|
case TypeBytes.PLAYER_MESSAGE_TYPE_SET_ID:
|
||||||
@ -81,6 +122,9 @@ public class PlayerMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type Set_ID
|
||||||
|
*/
|
||||||
public static PlayerMessage parseSet_IDMessage(CircularByteBuffer byteBuffer){
|
public static PlayerMessage parseSet_IDMessage(CircularByteBuffer byteBuffer){
|
||||||
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SET_ID);
|
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SET_ID);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -88,6 +132,9 @@ public class PlayerMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type Set_ID
|
||||||
|
*/
|
||||||
public static PlayerMessage constructSet_IDMessage(int playerID){
|
public static PlayerMessage constructSet_IDMessage(int playerID){
|
||||||
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SET_ID);
|
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SET_ID);
|
||||||
rVal.setplayerID(playerID);
|
rVal.setplayerID(playerID);
|
||||||
@ -95,6 +142,9 @@ public class PlayerMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type SetInitialDiscretePosition
|
||||||
|
*/
|
||||||
public static PlayerMessage parseSetInitialDiscretePositionMessage(CircularByteBuffer byteBuffer){
|
public static PlayerMessage parseSetInitialDiscretePositionMessage(CircularByteBuffer byteBuffer){
|
||||||
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SETINITIALDISCRETEPOSITION);
|
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SETINITIALDISCRETEPOSITION);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -104,6 +154,9 @@ public class PlayerMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type SetInitialDiscretePosition
|
||||||
|
*/
|
||||||
public static PlayerMessage constructSetInitialDiscretePositionMessage(int initialDiscretePositionX,int initialDiscretePositionY,int initialDiscretePositionZ){
|
public static PlayerMessage constructSetInitialDiscretePositionMessage(int initialDiscretePositionX,int initialDiscretePositionY,int initialDiscretePositionZ){
|
||||||
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SETINITIALDISCRETEPOSITION);
|
PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SETINITIALDISCRETEPOSITION);
|
||||||
rVal.setinitialDiscretePositionX(initialDiscretePositionX);
|
rVal.setinitialDiscretePositionX(initialDiscretePositionX);
|
||||||
@ -116,7 +169,6 @@ public class PlayerMessage extends NetworkMessage {
|
|||||||
@Override
|
@Override
|
||||||
void serialize(){
|
void serialize(){
|
||||||
byte[] intValues = new byte[8];
|
byte[] intValues = new byte[8];
|
||||||
byte[] stringBytes;
|
|
||||||
switch(this.messageType){
|
switch(this.messageType){
|
||||||
case SET_ID:
|
case SET_ID:
|
||||||
rawBytes = new byte[2+4];
|
rawBytes = new byte[2+4];
|
||||||
|
|||||||
@ -1,19 +1,25 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ServerMessage extends NetworkMessage {
|
public class ServerMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum ServerMessageType {
|
public enum ServerMessageType {
|
||||||
PING,
|
PING,
|
||||||
PONG,
|
PONG,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
ServerMessageType messageType;
|
ServerMessageType messageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
ServerMessage(ServerMessageType messageType){
|
ServerMessage(ServerMessageType messageType){
|
||||||
this.type = MessageType.SERVER_MESSAGE;
|
this.type = MessageType.SERVER_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -23,10 +29,20 @@ public class ServerMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.SERVER_MESSAGE_TYPE_PING:
|
case TypeBytes.SERVER_MESSAGE_TYPE_PING:
|
||||||
@ -45,24 +61,36 @@ public class ServerMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type Ping
|
||||||
|
*/
|
||||||
public static ServerMessage parsePingMessage(CircularByteBuffer byteBuffer){
|
public static ServerMessage parsePingMessage(CircularByteBuffer byteBuffer){
|
||||||
ServerMessage rVal = new ServerMessage(ServerMessageType.PING);
|
ServerMessage rVal = new ServerMessage(ServerMessageType.PING);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type Ping
|
||||||
|
*/
|
||||||
public static ServerMessage constructPingMessage(){
|
public static ServerMessage constructPingMessage(){
|
||||||
ServerMessage rVal = new ServerMessage(ServerMessageType.PING);
|
ServerMessage rVal = new ServerMessage(ServerMessageType.PING);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type Pong
|
||||||
|
*/
|
||||||
public static ServerMessage parsePongMessage(CircularByteBuffer byteBuffer){
|
public static ServerMessage parsePongMessage(CircularByteBuffer byteBuffer){
|
||||||
ServerMessage rVal = new ServerMessage(ServerMessageType.PONG);
|
ServerMessage rVal = new ServerMessage(ServerMessageType.PONG);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type Pong
|
||||||
|
*/
|
||||||
public static ServerMessage constructPongMessage(){
|
public static ServerMessage constructPongMessage(){
|
||||||
ServerMessage rVal = new ServerMessage(ServerMessageType.PONG);
|
ServerMessage rVal = new ServerMessage(ServerMessageType.PONG);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
@ -71,8 +99,6 @@ public class ServerMessage extends NetworkMessage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void serialize(){
|
void serialize(){
|
||||||
byte[] intValues = new byte[8];
|
|
||||||
byte[] stringBytes;
|
|
||||||
switch(this.messageType){
|
switch(this.messageType){
|
||||||
case PING:
|
case PING:
|
||||||
rawBytes = new byte[2];
|
rawBytes = new byte[2];
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SynchronizationMessage extends NetworkMessage {
|
public class SynchronizationMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum SynchronizationMessageType {
|
public enum SynchronizationMessageType {
|
||||||
UPDATECLIENTSTATE,
|
UPDATECLIENTSTATE,
|
||||||
UPDATECLIENTSTRINGSTATE,
|
UPDATECLIENTSTRINGSTATE,
|
||||||
@ -21,6 +24,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
LOADSCENE,
|
LOADSCENE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
SynchronizationMessageType messageType;
|
SynchronizationMessageType messageType;
|
||||||
int entityId;
|
int entityId;
|
||||||
int bTreeId;
|
int bTreeId;
|
||||||
@ -32,6 +38,10 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
float floatValue;
|
float floatValue;
|
||||||
double doubleValue;
|
double doubleValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
SynchronizationMessage(SynchronizationMessageType messageType){
|
SynchronizationMessage(SynchronizationMessageType messageType){
|
||||||
this.type = MessageType.SYNCHRONIZATION_MESSAGE;
|
this.type = MessageType.SYNCHRONIZATION_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -41,82 +51,146 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets entityId
|
||||||
|
*/
|
||||||
public int getentityId() {
|
public int getentityId() {
|
||||||
return entityId;
|
return entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets entityId
|
||||||
|
*/
|
||||||
public void setentityId(int entityId) {
|
public void setentityId(int entityId) {
|
||||||
this.entityId = entityId;
|
this.entityId = entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets bTreeId
|
||||||
|
*/
|
||||||
public int getbTreeId() {
|
public int getbTreeId() {
|
||||||
return bTreeId;
|
return bTreeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets bTreeId
|
||||||
|
*/
|
||||||
public void setbTreeId(int bTreeId) {
|
public void setbTreeId(int bTreeId) {
|
||||||
this.bTreeId = bTreeId;
|
this.bTreeId = bTreeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets fieldId
|
||||||
|
*/
|
||||||
public int getfieldId() {
|
public int getfieldId() {
|
||||||
return fieldId;
|
return fieldId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets fieldId
|
||||||
|
*/
|
||||||
public void setfieldId(int fieldId) {
|
public void setfieldId(int fieldId) {
|
||||||
this.fieldId = fieldId;
|
this.fieldId = fieldId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets bTreeValue
|
||||||
|
*/
|
||||||
public int getbTreeValue() {
|
public int getbTreeValue() {
|
||||||
return bTreeValue;
|
return bTreeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets bTreeValue
|
||||||
|
*/
|
||||||
public void setbTreeValue(int bTreeValue) {
|
public void setbTreeValue(int bTreeValue) {
|
||||||
this.bTreeValue = bTreeValue;
|
this.bTreeValue = bTreeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets stringValue
|
||||||
|
*/
|
||||||
public String getstringValue() {
|
public String getstringValue() {
|
||||||
return stringValue;
|
return stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets stringValue
|
||||||
|
*/
|
||||||
public void setstringValue(String stringValue) {
|
public void setstringValue(String stringValue) {
|
||||||
this.stringValue = stringValue;
|
this.stringValue = stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets intValue
|
||||||
|
*/
|
||||||
public int getintValue() {
|
public int getintValue() {
|
||||||
return intValue;
|
return intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets intValue
|
||||||
|
*/
|
||||||
public void setintValue(int intValue) {
|
public void setintValue(int intValue) {
|
||||||
this.intValue = intValue;
|
this.intValue = intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets longValue
|
||||||
|
*/
|
||||||
public long getlongValue() {
|
public long getlongValue() {
|
||||||
return longValue;
|
return longValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets longValue
|
||||||
|
*/
|
||||||
public void setlongValue(long longValue) {
|
public void setlongValue(long longValue) {
|
||||||
this.longValue = longValue;
|
this.longValue = longValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets floatValue
|
||||||
|
*/
|
||||||
public float getfloatValue() {
|
public float getfloatValue() {
|
||||||
return floatValue;
|
return floatValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets floatValue
|
||||||
|
*/
|
||||||
public void setfloatValue(float floatValue) {
|
public void setfloatValue(float floatValue) {
|
||||||
this.floatValue = floatValue;
|
this.floatValue = floatValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets doubleValue
|
||||||
|
*/
|
||||||
public double getdoubleValue() {
|
public double getdoubleValue() {
|
||||||
return doubleValue;
|
return doubleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets doubleValue
|
||||||
|
*/
|
||||||
public void setdoubleValue(double doubleValue) {
|
public void setdoubleValue(double doubleValue) {
|
||||||
this.doubleValue = doubleValue;
|
this.doubleValue = doubleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTATE:
|
case TypeBytes.SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTATE:
|
||||||
@ -181,6 +255,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateClientState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseUpdateClientStateMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseUpdateClientStateMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -191,6 +268,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateClientState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructUpdateClientStateMessage(int entityId,int bTreeId,int fieldId,int bTreeValue){
|
public static SynchronizationMessage constructUpdateClientStateMessage(int entityId,int bTreeId,int fieldId,int bTreeValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTATE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -201,6 +281,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type UpdateClientStringState can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseUpdateClientStringStateMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseUpdateClientStringStateMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -229,6 +312,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateClientStringState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseUpdateClientStringStateMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseUpdateClientStringStateMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTRINGSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTRINGSTATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -239,6 +325,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateClientStringState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructUpdateClientStringStateMessage(int entityId,int bTreeId,int fieldId,String stringValue){
|
public static SynchronizationMessage constructUpdateClientStringStateMessage(int entityId,int bTreeId,int fieldId,String stringValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTRINGSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTSTRINGSTATE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -249,6 +338,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateClientIntState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseUpdateClientIntStateMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseUpdateClientIntStateMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTINTSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTINTSTATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -259,6 +351,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateClientIntState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructUpdateClientIntStateMessage(int entityId,int bTreeId,int fieldId,int intValue){
|
public static SynchronizationMessage constructUpdateClientIntStateMessage(int entityId,int bTreeId,int fieldId,int intValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTINTSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTINTSTATE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -269,6 +364,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateClientLongState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseUpdateClientLongStateMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseUpdateClientLongStateMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTLONGSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTLONGSTATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -279,6 +377,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateClientLongState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructUpdateClientLongStateMessage(int entityId,int bTreeId,int fieldId,long longValue){
|
public static SynchronizationMessage constructUpdateClientLongStateMessage(int entityId,int bTreeId,int fieldId,long longValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTLONGSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTLONGSTATE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -289,6 +390,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateClientFloatState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseUpdateClientFloatStateMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseUpdateClientFloatStateMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTFLOATSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTFLOATSTATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -299,6 +403,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateClientFloatState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructUpdateClientFloatStateMessage(int entityId,int bTreeId,int fieldId,float floatValue){
|
public static SynchronizationMessage constructUpdateClientFloatStateMessage(int entityId,int bTreeId,int fieldId,float floatValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTFLOATSTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTFLOATSTATE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -309,6 +416,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateClientDoubleState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseUpdateClientDoubleStateMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseUpdateClientDoubleStateMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTDOUBLESTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTDOUBLESTATE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -319,6 +429,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateClientDoubleState
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructUpdateClientDoubleStateMessage(int entityId,int bTreeId,int fieldId,double doubleValue){
|
public static SynchronizationMessage constructUpdateClientDoubleStateMessage(int entityId,int bTreeId,int fieldId,double doubleValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTDOUBLESTATE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.UPDATECLIENTDOUBLESTATE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -329,6 +442,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ClientRequestBTreeAction
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseClientRequestBTreeActionMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseClientRequestBTreeActionMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.CLIENTREQUESTBTREEACTION);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.CLIENTREQUESTBTREEACTION);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -338,6 +454,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ClientRequestBTreeAction
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructClientRequestBTreeActionMessage(int entityId,int bTreeId,int bTreeValue){
|
public static SynchronizationMessage constructClientRequestBTreeActionMessage(int entityId,int bTreeId,int bTreeValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.CLIENTREQUESTBTREEACTION);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.CLIENTREQUESTBTREEACTION);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -347,6 +466,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ServerNotifyBTreeTransition
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseServerNotifyBTreeTransitionMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseServerNotifyBTreeTransitionMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.SERVERNOTIFYBTREETRANSITION);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.SERVERNOTIFYBTREETRANSITION);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -357,6 +479,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ServerNotifyBTreeTransition
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructServerNotifyBTreeTransitionMessage(int entityId,int bTreeId,int fieldId,int bTreeValue){
|
public static SynchronizationMessage constructServerNotifyBTreeTransitionMessage(int entityId,int bTreeId,int fieldId,int bTreeValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.SERVERNOTIFYBTREETRANSITION);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.SERVERNOTIFYBTREETRANSITION);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -367,6 +492,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type AttachTree
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseAttachTreeMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseAttachTreeMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.ATTACHTREE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.ATTACHTREE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -375,6 +503,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type AttachTree
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructAttachTreeMessage(int entityId,int bTreeId){
|
public static SynchronizationMessage constructAttachTreeMessage(int entityId,int bTreeId){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.ATTACHTREE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.ATTACHTREE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -383,6 +514,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type DetatchTree
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseDetatchTreeMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseDetatchTreeMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.DETATCHTREE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.DETATCHTREE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -391,6 +525,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type DetatchTree
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructDetatchTreeMessage(int entityId,int bTreeId){
|
public static SynchronizationMessage constructDetatchTreeMessage(int entityId,int bTreeId){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.DETATCHTREE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.DETATCHTREE);
|
||||||
rVal.setentityId(entityId);
|
rVal.setentityId(entityId);
|
||||||
@ -399,6 +536,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type LoadScene can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseLoadSceneMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseLoadSceneMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -418,6 +558,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type LoadScene
|
||||||
|
*/
|
||||||
public static SynchronizationMessage parseLoadSceneMessage(CircularByteBuffer byteBuffer){
|
public static SynchronizationMessage parseLoadSceneMessage(CircularByteBuffer byteBuffer){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.LOADSCENE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.LOADSCENE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -425,6 +568,9 @@ public class SynchronizationMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type LoadScene
|
||||||
|
*/
|
||||||
public static SynchronizationMessage constructLoadSceneMessage(String stringValue){
|
public static SynchronizationMessage constructLoadSceneMessage(String stringValue){
|
||||||
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.LOADSCENE);
|
SynchronizationMessage rVal = new SynchronizationMessage(SynchronizationMessageType.LOADSCENE);
|
||||||
rVal.setstringValue(stringValue);
|
rVal.setstringValue(stringValue);
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import electrosphere.net.parser.util.ByteStreamUtils;
|
import electrosphere.net.parser.util.ByteStreamUtils;
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TerrainMessage extends NetworkMessage {
|
public class TerrainMessage extends NetworkMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of messages available in this category.
|
||||||
|
*/
|
||||||
public enum TerrainMessageType {
|
public enum TerrainMessageType {
|
||||||
REQUESTMETADATA,
|
REQUESTMETADATA,
|
||||||
RESPONSEMETADATA,
|
RESPONSEMETADATA,
|
||||||
@ -23,6 +26,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
UPDATEFLUIDDATA,
|
UPDATEFLUIDDATA,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this message in particular.
|
||||||
|
*/
|
||||||
TerrainMessageType messageType;
|
TerrainMessageType messageType;
|
||||||
int worldSizeDiscrete;
|
int worldSizeDiscrete;
|
||||||
int dynamicInterpolationRatio;
|
int dynamicInterpolationRatio;
|
||||||
@ -46,6 +52,10 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
float terrainWeight;
|
float terrainWeight;
|
||||||
int terrainValue;
|
int terrainValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param messageType The type of this message
|
||||||
|
*/
|
||||||
TerrainMessage(TerrainMessageType messageType){
|
TerrainMessage(TerrainMessageType messageType){
|
||||||
this.type = MessageType.TERRAIN_MESSAGE;
|
this.type = MessageType.TERRAIN_MESSAGE;
|
||||||
this.messageType = messageType;
|
this.messageType = messageType;
|
||||||
@ -55,178 +65,314 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return this.messageType;
|
return this.messageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldSizeDiscrete
|
||||||
|
*/
|
||||||
public int getworldSizeDiscrete() {
|
public int getworldSizeDiscrete() {
|
||||||
return worldSizeDiscrete;
|
return worldSizeDiscrete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldSizeDiscrete
|
||||||
|
*/
|
||||||
public void setworldSizeDiscrete(int worldSizeDiscrete) {
|
public void setworldSizeDiscrete(int worldSizeDiscrete) {
|
||||||
this.worldSizeDiscrete = worldSizeDiscrete;
|
this.worldSizeDiscrete = worldSizeDiscrete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets dynamicInterpolationRatio
|
||||||
|
*/
|
||||||
public int getdynamicInterpolationRatio() {
|
public int getdynamicInterpolationRatio() {
|
||||||
return dynamicInterpolationRatio;
|
return dynamicInterpolationRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets dynamicInterpolationRatio
|
||||||
|
*/
|
||||||
public void setdynamicInterpolationRatio(int dynamicInterpolationRatio) {
|
public void setdynamicInterpolationRatio(int dynamicInterpolationRatio) {
|
||||||
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets randomDampener
|
||||||
|
*/
|
||||||
public float getrandomDampener() {
|
public float getrandomDampener() {
|
||||||
return randomDampener;
|
return randomDampener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets randomDampener
|
||||||
|
*/
|
||||||
public void setrandomDampener(float randomDampener) {
|
public void setrandomDampener(float randomDampener) {
|
||||||
this.randomDampener = randomDampener;
|
this.randomDampener = randomDampener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldMinX
|
||||||
|
*/
|
||||||
public int getworldMinX() {
|
public int getworldMinX() {
|
||||||
return worldMinX;
|
return worldMinX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldMinX
|
||||||
|
*/
|
||||||
public void setworldMinX(int worldMinX) {
|
public void setworldMinX(int worldMinX) {
|
||||||
this.worldMinX = worldMinX;
|
this.worldMinX = worldMinX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldMinY
|
||||||
|
*/
|
||||||
public int getworldMinY() {
|
public int getworldMinY() {
|
||||||
return worldMinY;
|
return worldMinY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldMinY
|
||||||
|
*/
|
||||||
public void setworldMinY(int worldMinY) {
|
public void setworldMinY(int worldMinY) {
|
||||||
this.worldMinY = worldMinY;
|
this.worldMinY = worldMinY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldMaxX
|
||||||
|
*/
|
||||||
public int getworldMaxX() {
|
public int getworldMaxX() {
|
||||||
return worldMaxX;
|
return worldMaxX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldMaxX
|
||||||
|
*/
|
||||||
public void setworldMaxX(int worldMaxX) {
|
public void setworldMaxX(int worldMaxX) {
|
||||||
this.worldMaxX = worldMaxX;
|
this.worldMaxX = worldMaxX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldMaxY
|
||||||
|
*/
|
||||||
public int getworldMaxY() {
|
public int getworldMaxY() {
|
||||||
return worldMaxY;
|
return worldMaxY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldMaxY
|
||||||
|
*/
|
||||||
public void setworldMaxY(int worldMaxY) {
|
public void setworldMaxY(int worldMaxY) {
|
||||||
this.worldMaxY = worldMaxY;
|
this.worldMaxY = worldMaxY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets value
|
||||||
|
*/
|
||||||
public float getvalue() {
|
public float getvalue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets value
|
||||||
|
*/
|
||||||
public void setvalue(float value) {
|
public void setvalue(float value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldX
|
||||||
|
*/
|
||||||
public int getworldX() {
|
public int getworldX() {
|
||||||
return worldX;
|
return worldX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldX
|
||||||
|
*/
|
||||||
public void setworldX(int worldX) {
|
public void setworldX(int worldX) {
|
||||||
this.worldX = worldX;
|
this.worldX = worldX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldY
|
||||||
|
*/
|
||||||
public int getworldY() {
|
public int getworldY() {
|
||||||
return worldY;
|
return worldY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldY
|
||||||
|
*/
|
||||||
public void setworldY(int worldY) {
|
public void setworldY(int worldY) {
|
||||||
this.worldY = worldY;
|
this.worldY = worldY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets worldZ
|
||||||
|
*/
|
||||||
public int getworldZ() {
|
public int getworldZ() {
|
||||||
return worldZ;
|
return worldZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets worldZ
|
||||||
|
*/
|
||||||
public void setworldZ(int worldZ) {
|
public void setworldZ(int worldZ) {
|
||||||
this.worldZ = worldZ;
|
this.worldZ = worldZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets voxelX
|
||||||
|
*/
|
||||||
public int getvoxelX() {
|
public int getvoxelX() {
|
||||||
return voxelX;
|
return voxelX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets voxelX
|
||||||
|
*/
|
||||||
public void setvoxelX(int voxelX) {
|
public void setvoxelX(int voxelX) {
|
||||||
this.voxelX = voxelX;
|
this.voxelX = voxelX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets voxelY
|
||||||
|
*/
|
||||||
public int getvoxelY() {
|
public int getvoxelY() {
|
||||||
return voxelY;
|
return voxelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets voxelY
|
||||||
|
*/
|
||||||
public void setvoxelY(int voxelY) {
|
public void setvoxelY(int voxelY) {
|
||||||
this.voxelY = voxelY;
|
this.voxelY = voxelY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets voxelZ
|
||||||
|
*/
|
||||||
public int getvoxelZ() {
|
public int getvoxelZ() {
|
||||||
return voxelZ;
|
return voxelZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets voxelZ
|
||||||
|
*/
|
||||||
public void setvoxelZ(int voxelZ) {
|
public void setvoxelZ(int voxelZ) {
|
||||||
this.voxelZ = voxelZ;
|
this.voxelZ = voxelZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets realLocationX
|
||||||
|
*/
|
||||||
public double getrealLocationX() {
|
public double getrealLocationX() {
|
||||||
return realLocationX;
|
return realLocationX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets realLocationX
|
||||||
|
*/
|
||||||
public void setrealLocationX(double realLocationX) {
|
public void setrealLocationX(double realLocationX) {
|
||||||
this.realLocationX = realLocationX;
|
this.realLocationX = realLocationX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets realLocationY
|
||||||
|
*/
|
||||||
public double getrealLocationY() {
|
public double getrealLocationY() {
|
||||||
return realLocationY;
|
return realLocationY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets realLocationY
|
||||||
|
*/
|
||||||
public void setrealLocationY(double realLocationY) {
|
public void setrealLocationY(double realLocationY) {
|
||||||
this.realLocationY = realLocationY;
|
this.realLocationY = realLocationY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets realLocationZ
|
||||||
|
*/
|
||||||
public double getrealLocationZ() {
|
public double getrealLocationZ() {
|
||||||
return realLocationZ;
|
return realLocationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets realLocationZ
|
||||||
|
*/
|
||||||
public void setrealLocationZ(double realLocationZ) {
|
public void setrealLocationZ(double realLocationZ) {
|
||||||
this.realLocationZ = realLocationZ;
|
this.realLocationZ = realLocationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets chunkData
|
||||||
|
*/
|
||||||
public byte[] getchunkData() {
|
public byte[] getchunkData() {
|
||||||
return chunkData;
|
return chunkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets chunkData
|
||||||
|
*/
|
||||||
public void setchunkData(byte[] chunkData) {
|
public void setchunkData(byte[] chunkData) {
|
||||||
this.chunkData = chunkData;
|
this.chunkData = chunkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets chunkResolution
|
||||||
|
*/
|
||||||
public int getchunkResolution() {
|
public int getchunkResolution() {
|
||||||
return chunkResolution;
|
return chunkResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets chunkResolution
|
||||||
|
*/
|
||||||
public void setchunkResolution(int chunkResolution) {
|
public void setchunkResolution(int chunkResolution) {
|
||||||
this.chunkResolution = chunkResolution;
|
this.chunkResolution = chunkResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets terrainWeight
|
||||||
|
*/
|
||||||
public float getterrainWeight() {
|
public float getterrainWeight() {
|
||||||
return terrainWeight;
|
return terrainWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets terrainWeight
|
||||||
|
*/
|
||||||
public void setterrainWeight(float terrainWeight) {
|
public void setterrainWeight(float terrainWeight) {
|
||||||
this.terrainWeight = terrainWeight;
|
this.terrainWeight = terrainWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets terrainValue
|
||||||
|
*/
|
||||||
public int getterrainValue() {
|
public int getterrainValue() {
|
||||||
return terrainValue;
|
return terrainValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets terrainValue
|
||||||
|
*/
|
||||||
public void setterrainValue(int terrainValue) {
|
public void setterrainValue(int terrainValue) {
|
||||||
this.terrainValue = terrainValue;
|
this.terrainValue = terrainValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the packet header from the buffer
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
*/
|
||||||
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
static void stripPacketHeader(CircularByteBuffer byteBuffer){
|
||||||
byteBuffer.read(2);
|
byteBuffer.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this message can be parsed (ie are all bytes present)
|
||||||
|
* @param byteBuffer The buffer
|
||||||
|
* @param secondByte The second byte, signifying the subtype of the message
|
||||||
|
* @return true if the message can be parsed, false otherwise
|
||||||
|
*/
|
||||||
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
|
||||||
switch(secondByte){
|
switch(secondByte){
|
||||||
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTMETADATA:
|
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTMETADATA:
|
||||||
@ -295,18 +441,27 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestMetadata
|
||||||
|
*/
|
||||||
public static TerrainMessage parseRequestMetadataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseRequestMetadataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTMETADATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTMETADATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestMetadata
|
||||||
|
*/
|
||||||
public static TerrainMessage constructRequestMetadataMessage(){
|
public static TerrainMessage constructRequestMetadataMessage(){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTMETADATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTMETADATA);
|
||||||
rVal.serialize();
|
rVal.serialize();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type ResponseMetadata
|
||||||
|
*/
|
||||||
public static TerrainMessage parseResponseMetadataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseResponseMetadataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -320,6 +475,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type ResponseMetadata
|
||||||
|
*/
|
||||||
public static TerrainMessage constructResponseMetadataMessage(int worldSizeDiscrete,int dynamicInterpolationRatio,float randomDampener,int worldMinX,int worldMinY,int worldMaxX,int worldMaxY){
|
public static TerrainMessage constructResponseMetadataMessage(int worldSizeDiscrete,int dynamicInterpolationRatio,float randomDampener,int worldMinX,int worldMinY,int worldMaxX,int worldMaxY){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
|
||||||
rVal.setworldSizeDiscrete(worldSizeDiscrete);
|
rVal.setworldSizeDiscrete(worldSizeDiscrete);
|
||||||
@ -333,6 +491,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestEditVoxel
|
||||||
|
*/
|
||||||
public static TerrainMessage parseRequestEditVoxelMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseRequestEditVoxelMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -347,6 +508,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestEditVoxel
|
||||||
|
*/
|
||||||
public static TerrainMessage constructRequestEditVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){
|
public static TerrainMessage constructRequestEditVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -361,6 +525,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type UpdateVoxel
|
||||||
|
*/
|
||||||
public static TerrainMessage parseUpdateVoxelMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseUpdateVoxelMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -375,6 +542,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type UpdateVoxel
|
||||||
|
*/
|
||||||
public static TerrainMessage constructUpdateVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){
|
public static TerrainMessage constructUpdateVoxelMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,float terrainWeight,int terrainValue){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -389,6 +559,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestUseTerrainPalette
|
||||||
|
*/
|
||||||
public static TerrainMessage parseRequestUseTerrainPaletteMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseRequestUseTerrainPaletteMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -401,6 +574,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestUseTerrainPalette
|
||||||
|
*/
|
||||||
public static TerrainMessage constructRequestUseTerrainPaletteMessage(double realLocationX,double realLocationY,double realLocationZ,float value,float terrainWeight,int terrainValue){
|
public static TerrainMessage constructRequestUseTerrainPaletteMessage(double realLocationX,double realLocationY,double realLocationZ,float value,float terrainWeight,int terrainValue){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
|
||||||
rVal.setrealLocationX(realLocationX);
|
rVal.setrealLocationX(realLocationX);
|
||||||
@ -413,6 +589,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type SpawnPosition
|
||||||
|
*/
|
||||||
public static TerrainMessage parseSpawnPositionMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseSpawnPositionMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SPAWNPOSITION);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SPAWNPOSITION);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -422,6 +601,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type SpawnPosition
|
||||||
|
*/
|
||||||
public static TerrainMessage constructSpawnPositionMessage(double realLocationX,double realLocationY,double realLocationZ){
|
public static TerrainMessage constructSpawnPositionMessage(double realLocationX,double realLocationY,double realLocationZ){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SPAWNPOSITION);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SPAWNPOSITION);
|
||||||
rVal.setrealLocationX(realLocationX);
|
rVal.setrealLocationX(realLocationX);
|
||||||
@ -431,6 +613,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage parseRequestChunkDataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseRequestChunkDataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTCHUNKDATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -440,6 +625,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructRequestChunkDataMessage(int worldX,int worldY,int worldZ){
|
public static TerrainMessage constructRequestChunkDataMessage(int worldX,int worldY,int worldZ){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTCHUNKDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -449,6 +637,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type sendChunkData can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParsesendChunkDataMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParsesendChunkDataMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -477,6 +668,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type sendChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage parsesendChunkDataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parsesendChunkDataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDCHUNKDATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -487,6 +681,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type sendChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructsendChunkDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
public static TerrainMessage constructsendChunkDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDCHUNKDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -497,6 +694,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestReducedChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage parseRequestReducedChunkDataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseRequestReducedChunkDataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -507,6 +707,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestReducedChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructRequestReducedChunkDataMessage(int worldX,int worldY,int worldZ,int chunkResolution){
|
public static TerrainMessage constructRequestReducedChunkDataMessage(int worldX,int worldY,int worldZ,int chunkResolution){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -517,6 +720,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type SendReducedChunkData can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -548,6 +754,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type SendReducedChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage parseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -559,6 +768,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type SendReducedChunkData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructSendReducedChunkDataMessage(int worldX,int worldY,int worldZ,int chunkResolution,byte[] chunkData){
|
public static TerrainMessage constructSendReducedChunkDataMessage(int worldX,int worldY,int worldZ,int chunkResolution,byte[] chunkData){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -570,6 +782,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type RequestFluidData
|
||||||
|
*/
|
||||||
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);
|
||||||
@ -579,6 +794,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type RequestFluidData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructRequestFluidDataMessage(int worldX,int worldY,int worldZ){
|
public static TerrainMessage constructRequestFluidDataMessage(int worldX,int worldY,int worldZ){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -588,6 +806,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type sendFluidData can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParsesendFluidDataMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParsesendFluidDataMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -616,6 +837,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type sendFluidData
|
||||||
|
*/
|
||||||
public static TerrainMessage parsesendFluidDataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parsesendFluidDataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -626,6 +850,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type sendFluidData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructsendFluidDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
public static TerrainMessage constructsendFluidDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -636,6 +863,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a message of type updateFluidData can be parsed from the byte stream
|
||||||
|
*/
|
||||||
public static boolean canParseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
|
public static boolean canParseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
|
||||||
int currentStreamLength = byteBuffer.getRemaining();
|
int currentStreamLength = byteBuffer.getRemaining();
|
||||||
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
|
||||||
@ -664,6 +894,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a message of type updateFluidData
|
||||||
|
*/
|
||||||
public static TerrainMessage parseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
|
public static TerrainMessage parseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
|
||||||
stripPacketHeader(byteBuffer);
|
stripPacketHeader(byteBuffer);
|
||||||
@ -674,6 +907,9 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a message of type updateFluidData
|
||||||
|
*/
|
||||||
public static TerrainMessage constructupdateFluidDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
public static TerrainMessage constructupdateFluidDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
||||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
|
||||||
rVal.setworldX(worldX);
|
rVal.setworldX(worldX);
|
||||||
@ -687,7 +923,6 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
@Override
|
@Override
|
||||||
void serialize(){
|
void serialize(){
|
||||||
byte[] intValues = new byte[8];
|
byte[] intValues = new byte[8];
|
||||||
byte[] stringBytes;
|
|
||||||
switch(this.messageType){
|
switch(this.messageType){
|
||||||
case REQUESTMETADATA:
|
case REQUESTMETADATA:
|
||||||
rawBytes = new byte[2];
|
rawBytes = new byte[2];
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package electrosphere.net.parser.net.message;
|
package electrosphere.net.parser.net.message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constants used in serializing/deserializing messages
|
||||||
|
*/
|
||||||
public class TypeBytes {
|
public class TypeBytes {
|
||||||
/*
|
/**
|
||||||
Message categories
|
* Message categories
|
||||||
*/
|
*/
|
||||||
public static final byte MESSAGE_TYPE_ENTITY = 0;
|
public static final byte MESSAGE_TYPE_ENTITY = 0;
|
||||||
public static final byte MESSAGE_TYPE_LORE = 1;
|
public static final byte MESSAGE_TYPE_LORE = 1;
|
||||||
public static final byte MESSAGE_TYPE_PLAYER = 2;
|
public static final byte MESSAGE_TYPE_PLAYER = 2;
|
||||||
@ -16,7 +18,7 @@ Message categories
|
|||||||
public static final byte MESSAGE_TYPE_SYNCHRONIZATION = 8;
|
public static final byte MESSAGE_TYPE_SYNCHRONIZATION = 8;
|
||||||
public static final byte MESSAGE_TYPE_COMBAT = 9;
|
public static final byte MESSAGE_TYPE_COMBAT = 9;
|
||||||
/*
|
/*
|
||||||
Entity subcategories
|
Entity subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte ENTITY_MESSAGE_TYPE_CREATE = 0;
|
public static final byte ENTITY_MESSAGE_TYPE_CREATE = 0;
|
||||||
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE = 1;
|
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE = 1;
|
||||||
@ -29,7 +31,7 @@ Message categories
|
|||||||
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR = 8;
|
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR = 8;
|
||||||
public static final byte ENTITY_MESSAGE_TYPE_SYNCPHYSICS = 9;
|
public static final byte ENTITY_MESSAGE_TYPE_SYNCPHYSICS = 9;
|
||||||
/*
|
/*
|
||||||
Entity packet sizes
|
Entity packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE = 86;
|
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE = 86;
|
||||||
public static final byte ENTITY_MESSAGE_TYPE_ATTACKUPDATE_SIZE = 74;
|
public static final byte ENTITY_MESSAGE_TYPE_ATTACKUPDATE_SIZE = 74;
|
||||||
@ -39,27 +41,30 @@ Message categories
|
|||||||
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE = 22;
|
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE = 22;
|
||||||
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE = 34;
|
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE = 34;
|
||||||
public static final short ENTITY_MESSAGE_TYPE_SYNCPHYSICS_SIZE = 166;
|
public static final short ENTITY_MESSAGE_TYPE_SYNCPHYSICS_SIZE = 166;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Lore subcategories
|
Lore subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte LORE_MESSAGE_TYPE_REQUESTRACES = 0;
|
public static final byte LORE_MESSAGE_TYPE_REQUESTRACES = 0;
|
||||||
public static final byte LORE_MESSAGE_TYPE_RESPONSERACES = 1;
|
public static final byte LORE_MESSAGE_TYPE_RESPONSERACES = 1;
|
||||||
/*
|
/*
|
||||||
Lore packet sizes
|
Lore packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte LORE_MESSAGE_TYPE_REQUESTRACES_SIZE = 2;
|
public static final byte LORE_MESSAGE_TYPE_REQUESTRACES_SIZE = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Player subcategories
|
Player subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte PLAYER_MESSAGE_TYPE_SET_ID = 0;
|
public static final byte PLAYER_MESSAGE_TYPE_SET_ID = 0;
|
||||||
public static final byte PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION = 1;
|
public static final byte PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION = 1;
|
||||||
/*
|
/*
|
||||||
Player packet sizes
|
Player packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte PLAYER_MESSAGE_TYPE_SET_ID_SIZE = 6;
|
public static final byte PLAYER_MESSAGE_TYPE_SET_ID_SIZE = 6;
|
||||||
public static final byte PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION_SIZE = 14;
|
public static final byte PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION_SIZE = 14;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Terrain subcategories
|
Terrain subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA = 0;
|
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA = 0;
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA = 1;
|
public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA = 1;
|
||||||
@ -75,7 +80,7 @@ Message categories
|
|||||||
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 11;
|
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 11;
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 12;
|
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 12;
|
||||||
/*
|
/*
|
||||||
Terrain packet sizes
|
Terrain packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA_SIZE = 2;
|
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA_SIZE = 2;
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA_SIZE = 30;
|
public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA_SIZE = 30;
|
||||||
@ -86,31 +91,34 @@ Message categories
|
|||||||
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_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
|
||||||
*/
|
*/
|
||||||
public static final byte SERVER_MESSAGE_TYPE_PING = 0;
|
public static final byte SERVER_MESSAGE_TYPE_PING = 0;
|
||||||
public static final byte SERVER_MESSAGE_TYPE_PONG = 1;
|
public static final byte SERVER_MESSAGE_TYPE_PONG = 1;
|
||||||
/*
|
/*
|
||||||
Server packet sizes
|
Server packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte SERVER_MESSAGE_TYPE_PING_SIZE = 2;
|
public static final byte SERVER_MESSAGE_TYPE_PING_SIZE = 2;
|
||||||
public static final byte SERVER_MESSAGE_TYPE_PONG_SIZE = 2;
|
public static final byte SERVER_MESSAGE_TYPE_PONG_SIZE = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Auth subcategories
|
Auth subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHREQUEST = 0;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHREQUEST = 0;
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHDETAILS = 1;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHDETAILS = 1;
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHSUCCESS = 2;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHSUCCESS = 2;
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHFAILURE = 3;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHFAILURE = 3;
|
||||||
/*
|
/*
|
||||||
Auth packet sizes
|
Auth packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHREQUEST_SIZE = 2;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHREQUEST_SIZE = 2;
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHSUCCESS_SIZE = 2;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHSUCCESS_SIZE = 2;
|
||||||
public static final byte AUTH_MESSAGE_TYPE_AUTHFAILURE_SIZE = 2;
|
public static final byte AUTH_MESSAGE_TYPE_AUTHFAILURE_SIZE = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Character subcategories
|
Character subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST = 0;
|
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST = 0;
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECHARACTERLIST = 1;
|
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECHARACTERLIST = 1;
|
||||||
@ -120,14 +128,15 @@ Message categories
|
|||||||
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER = 5;
|
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER = 5;
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER = 6;
|
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER = 6;
|
||||||
/*
|
/*
|
||||||
Character packet sizes
|
Character packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST_SIZE = 2;
|
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST_SIZE = 2;
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS_SIZE = 2;
|
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS_SIZE = 2;
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE_SIZE = 2;
|
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE_SIZE = 2;
|
||||||
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE = 2;
|
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Inventory subcategories
|
Inventory subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY = 0;
|
public static final byte INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY = 0;
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY = 1;
|
public static final byte INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY = 1;
|
||||||
@ -141,14 +150,15 @@ Message categories
|
|||||||
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR = 9;
|
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR = 9;
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTPERFORMITEMACTION = 10;
|
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTPERFORMITEMACTION = 10;
|
||||||
/*
|
/*
|
||||||
Inventory packet sizes
|
Inventory packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY_SIZE = 6;
|
public static final byte INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY_SIZE = 6;
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR_SIZE = 10;
|
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR_SIZE = 10;
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL_SIZE = 6;
|
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL_SIZE = 6;
|
||||||
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR_SIZE = 6;
|
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR_SIZE = 6;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Synchronization subcategories
|
Synchronization subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTATE = 0;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTATE = 0;
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTRINGSTATE = 1;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTRINGSTATE = 1;
|
||||||
@ -162,7 +172,7 @@ Message categories
|
|||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE = 9;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE = 9;
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_LOADSCENE = 10;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_LOADSCENE = 10;
|
||||||
/*
|
/*
|
||||||
Synchronization packet sizes
|
Synchronization packet sizes
|
||||||
*/
|
*/
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTATE_SIZE = 18;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTSTATE_SIZE = 18;
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTINTSTATE_SIZE = 18;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_UPDATECLIENTINTSTATE_SIZE = 18;
|
||||||
@ -173,12 +183,14 @@ Message categories
|
|||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION_SIZE = 18;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_SERVERNOTIFYBTREETRANSITION_SIZE = 18;
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE_SIZE = 10;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_ATTACHTREE_SIZE = 10;
|
||||||
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE_SIZE = 10;
|
public static final byte SYNCHRONIZATION_MESSAGE_TYPE_DETATCHTREE_SIZE = 10;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Combat subcategories
|
Combat subcategories
|
||||||
*/
|
*/
|
||||||
public static final byte COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION = 0;
|
public static final byte COMBAT_MESSAGE_TYPE_SERVERREPORTHITBOXCOLLISION = 0;
|
||||||
/*
|
/*
|
||||||
Combat packet sizes
|
Combat packet sizes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,120 +0,0 @@
|
|||||||
package electrosphere.net.parser.net.raw;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A circular byte buffer optimized for high throughput (relative to a list) and peaking at early elements of the current position.
|
|
||||||
*/
|
|
||||||
public class CircularByteBuffer {
|
|
||||||
|
|
||||||
//The array backing this circular byte buffer
|
|
||||||
byte[] backingArray;
|
|
||||||
//the current read position of the buffer in the backing array
|
|
||||||
int position;
|
|
||||||
//the remaining bytes to read before the read position equals the write position
|
|
||||||
int remaining;
|
|
||||||
//the capacity of the backing array
|
|
||||||
int capacity;
|
|
||||||
//Lock to make the structure threadsafe
|
|
||||||
Semaphore lock = new Semaphore(1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a CircularByteBuffer
|
|
||||||
* @param capacity The capacity of the backing array in bytes
|
|
||||||
*/
|
|
||||||
public CircularByteBuffer(int capacity){
|
|
||||||
backingArray = new byte[capacity];
|
|
||||||
position = 0;
|
|
||||||
remaining = 0;
|
|
||||||
this.capacity = capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an array of bytes to the circular buffer
|
|
||||||
* @param bytes The bytes
|
|
||||||
* @param len The number of bytes to pull from the array bytes
|
|
||||||
*/
|
|
||||||
public void add(byte[] bytes, int len){
|
|
||||||
lock.acquireUninterruptibly();
|
|
||||||
// System.out.println("Add start");
|
|
||||||
int writePosition = (position + remaining) % capacity;
|
|
||||||
//amount possible to write before wrapping
|
|
||||||
int writeBeforeWrap = capacity - writePosition;
|
|
||||||
//only run wrapping logic if necessary
|
|
||||||
if(len > writeBeforeWrap){
|
|
||||||
System.arraycopy(bytes, 0, backingArray, writePosition, writeBeforeWrap);
|
|
||||||
System.arraycopy(bytes, writeBeforeWrap, backingArray, 0, len - writeBeforeWrap);
|
|
||||||
} else {
|
|
||||||
System.arraycopy(bytes, 0, backingArray, writePosition, len);
|
|
||||||
}
|
|
||||||
remaining = remaining + len;
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Peeks at the next element in the buffer
|
|
||||||
* @return The value of the byte next in the buffer
|
|
||||||
*/
|
|
||||||
public byte peek(){
|
|
||||||
byte rVal = peek(0);
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Peeks at an element @param offset elements further along the buffer from the current position
|
|
||||||
* @param offset The offset, in bytes, to look forward in the buffer
|
|
||||||
* @return The value of the byte at the current position + @param offset
|
|
||||||
*/
|
|
||||||
public byte peek(int offset){
|
|
||||||
lock.acquireUninterruptibly();
|
|
||||||
byte rVal = backingArray[(position + offset) % capacity];
|
|
||||||
lock.release();
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the remaining number of bytes in the buffer
|
|
||||||
* @return The remaining number of bytes
|
|
||||||
*/
|
|
||||||
public int getRemaining(){
|
|
||||||
lock.acquireUninterruptibly();
|
|
||||||
int rVal = remaining;
|
|
||||||
lock.release();
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the capacity of the buffer
|
|
||||||
* @return The capacity
|
|
||||||
*/
|
|
||||||
public int getCapacity(){
|
|
||||||
lock.acquireUninterruptibly();
|
|
||||||
int rVal = capacity;
|
|
||||||
lock.release();
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a given number of bytes from the buffer
|
|
||||||
* @param len The number of bytes to read
|
|
||||||
* @return The bytes in an array
|
|
||||||
*/
|
|
||||||
public byte[] read(int len){
|
|
||||||
lock.acquireUninterruptibly();
|
|
||||||
byte[] rVal = new byte[len];
|
|
||||||
//amount possible to read before loop
|
|
||||||
int toReadBeforeLoop = capacity - position;
|
|
||||||
if(len > capacity - position){
|
|
||||||
System.arraycopy(backingArray, position, rVal, 0, toReadBeforeLoop);
|
|
||||||
System.arraycopy(backingArray, 0, rVal, toReadBeforeLoop, len - toReadBeforeLoop);
|
|
||||||
} else {
|
|
||||||
System.arraycopy(backingArray, position, rVal, 0, len);
|
|
||||||
}
|
|
||||||
position = (position + len) % capacity;
|
|
||||||
remaining = remaining - len;
|
|
||||||
lock.release();
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,76 +1,132 @@
|
|||||||
package electrosphere.net.parser.net.raw;
|
package electrosphere.net.parser.net.raw;
|
||||||
|
|
||||||
import electrosphere.net.parser.net.message.NetworkMessage;
|
import electrosphere.net.parser.net.message.NetworkMessage;
|
||||||
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main message parser. This is used to serialize/deserialize messages to/from the provided streams.
|
||||||
|
*/
|
||||||
public class NetworkParser {
|
public class NetworkParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the read buffer
|
||||||
|
*/
|
||||||
|
static final int READ_BLOCK_SIZE = 16 * 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the circular buffer
|
||||||
|
*/
|
||||||
|
static final int CIRCULAR_BUFFER_SIZE = 64 * 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The input stream for the parser
|
||||||
|
*/
|
||||||
InputStream incomingStream;
|
InputStream incomingStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output stream for the parser
|
||||||
|
*/
|
||||||
OutputStream outgoingStream;
|
OutputStream outgoingStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The queue of incoming messages that have been parsed
|
||||||
|
*/
|
||||||
CopyOnWriteArrayList<NetworkMessage> incomingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
|
CopyOnWriteArrayList<NetworkMessage> incomingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The queue of outgoing messages that have yet to be sent
|
||||||
|
*/
|
||||||
CopyOnWriteArrayList<NetworkMessage> outgoingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
|
CopyOnWriteArrayList<NetworkMessage> outgoingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
|
||||||
|
|
||||||
CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(64 * 1024 * 124);
|
/**
|
||||||
|
* The byte buffer for storing incoming bytes
|
||||||
|
*/
|
||||||
|
CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(CIRCULAR_BUFFER_SIZE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The block array used to read blocks of bytes in
|
||||||
|
*/
|
||||||
|
byte[] readBuffer = new byte[READ_BLOCK_SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The outgoing byte buffer
|
||||||
|
*/
|
||||||
CopyOnWriteArrayList<Byte> outgoingByteQueue = new CopyOnWriteArrayList<Byte>();
|
CopyOnWriteArrayList<Byte> outgoingByteQueue = new CopyOnWriteArrayList<Byte>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bytes read
|
||||||
|
*/
|
||||||
|
long totalBytesRead = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param incomingStream The stream of incoming bytes
|
||||||
|
* @param outgoingStream The stream of outgoing bytes
|
||||||
|
*/
|
||||||
public NetworkParser(InputStream incomingStream, OutputStream outgoingStream){
|
public NetworkParser(InputStream incomingStream, OutputStream outgoingStream){
|
||||||
this.incomingStream = incomingStream;
|
this.incomingStream = incomingStream;
|
||||||
this.outgoingStream = outgoingStream;
|
this.outgoingStream = outgoingStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(){
|
/**
|
||||||
|
* Reads messages from the input stream
|
||||||
}
|
*/
|
||||||
|
public void readMessagesIn() throws IOException {
|
||||||
static final int READ_BUFFER_SIZE = 64 * 1024 * 1024;
|
//read in bytes
|
||||||
byte[] readBuffer = new byte[READ_BUFFER_SIZE];
|
int bytesRead = 0;
|
||||||
public void readMessagesIn(){
|
while(incomingStream.available() > 0){
|
||||||
try {
|
// nextValue = incomingStream.read();
|
||||||
//read in bytes
|
bytesRead = incomingStream.read(readBuffer, 0, READ_BLOCK_SIZE);
|
||||||
int bytesRead = 0;
|
if(bytesRead > 0){
|
||||||
byte currentByte = -1;
|
incomingByteBuffer.add(readBuffer, bytesRead);
|
||||||
while(incomingStream.available() > 0){
|
|
||||||
// nextValue = incomingStream.read();
|
|
||||||
bytesRead = incomingStream.read(readBuffer, 0, READ_BUFFER_SIZE);
|
|
||||||
if(bytesRead > 0){
|
|
||||||
incomingByteBuffer.add(readBuffer, bytesRead);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//parse byte queue for messages
|
totalBytesRead = totalBytesRead + bytesRead;
|
||||||
//for each message, append to clientIncomingMessageQueue
|
}
|
||||||
NetworkMessage newMessage;
|
//parse byte queue for messages
|
||||||
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer))!=null){
|
//for each message, append to clientIncomingMessageQueue
|
||||||
incomingMessageQueue.add(newMessage);
|
NetworkMessage newMessage;
|
||||||
}
|
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer))!=null){
|
||||||
} catch (IOException ex) {
|
incomingMessageQueue.add(newMessage);
|
||||||
ex.printStackTrace();
|
|
||||||
System.exit(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes messages out across the output stream
|
||||||
|
* @throws IOException Thrown if a message fails to serialize or the output stream fails to write
|
||||||
|
*/
|
||||||
public void pushMessagesOut() throws IOException {
|
public void pushMessagesOut() throws IOException {
|
||||||
for(NetworkMessage message : outgoingMessageQueue){
|
for(NetworkMessage message : outgoingMessageQueue){
|
||||||
outgoingMessageQueue.remove(message);
|
outgoingMessageQueue.remove(message);
|
||||||
// System.out.println("Write message of type " + message.getType());
|
|
||||||
outgoingStream.write(message.getRawBytes());
|
outgoingStream.write(message.getRawBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there is a fully parsed incoming message in the queue
|
||||||
|
* @return true if there is message in the queue, false otherwise
|
||||||
|
*/
|
||||||
public boolean hasIncomingMessaage(){
|
public boolean hasIncomingMessaage(){
|
||||||
return incomingMessageQueue.size() > 0;
|
return incomingMessageQueue.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops a fully parsed incoming message from the queue
|
||||||
|
* @return The message
|
||||||
|
*/
|
||||||
public NetworkMessage popIncomingMessage(){
|
public NetworkMessage popIncomingMessage(){
|
||||||
return incomingMessageQueue.remove(0);
|
return incomingMessageQueue.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a message to the outgoing queue
|
||||||
|
* @param message The message
|
||||||
|
*/
|
||||||
public void addOutgoingMessage(NetworkMessage message){
|
public void addOutgoingMessage(NetworkMessage message){
|
||||||
outgoingMessageQueue.add(message);
|
outgoingMessageQueue.add(message);
|
||||||
}
|
}
|
||||||
@ -90,5 +146,13 @@ public class NetworkParser {
|
|||||||
public void copyOutgoingMessages(List<NetworkMessage> messages){
|
public void copyOutgoingMessages(List<NetworkMessage> messages){
|
||||||
messages.addAll(outgoingMessageQueue);
|
messages.addAll(outgoingMessageQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total number of bytes read by this connection
|
||||||
|
* @return The total number of bytes
|
||||||
|
*/
|
||||||
|
public long getNumberOfBytesRead(){
|
||||||
|
return totalBytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package electrosphere.net.parser.util;
|
package electrosphere.net.parser.util;
|
||||||
|
|
||||||
import electrosphere.net.parser.net.raw.CircularByteBuffer;
|
import io.github.studiorailgun.CircularByteBuffer;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@ -67,7 +67,7 @@ public class MessageProtocol {
|
|||||||
* @param message The message
|
* @param message The message
|
||||||
*/
|
*/
|
||||||
public void handleAsyncMessage(NetworkMessage message){
|
public void handleAsyncMessage(NetworkMessage message){
|
||||||
Globals.profiler.beginAggregateCpuSample("MessageProtocol(client).handleAsyncMessage");
|
Globals.profiler.beginAggregateCpuSample("MessageProtocol(server).handleAsyncMessage");
|
||||||
printMessage(message);
|
printMessage(message);
|
||||||
NetworkMessage result = null;
|
NetworkMessage result = null;
|
||||||
switch(message.getType()){
|
switch(message.getType()){
|
||||||
@ -113,7 +113,7 @@ public class MessageProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handleSyncMessages(){
|
public void handleSyncMessages(){
|
||||||
Globals.profiler.beginAggregateCpuSample("MessageProtocol(client).handleSyncMessages");
|
Globals.profiler.beginAggregateCpuSample("MessageProtocol(server).handleSyncMessages");
|
||||||
this.synchronousMessageLock.acquireUninterruptibly();
|
this.synchronousMessageLock.acquireUninterruptibly();
|
||||||
LoggerInterface.loggerNetworking.DEBUG_LOOP("[SERVER] HANDLE SYNC MESSAGE [Sync queue size: " + this.synchronousMessageQueue.size() + "]");
|
LoggerInterface.loggerNetworking.DEBUG_LOOP("[SERVER] HANDLE SYNC MESSAGE [Sync queue size: " + this.synchronousMessageQueue.size() + "]");
|
||||||
for(NetworkMessage message : synchronousMessageQueue){
|
for(NetworkMessage message : synchronousMessageQueue){
|
||||||
|
|||||||
@ -170,8 +170,11 @@ public class Server implements Runnable {
|
|||||||
* @return The first connection
|
* @return The first connection
|
||||||
*/
|
*/
|
||||||
public ServerConnectionHandler getFirstConnection(){
|
public ServerConnectionHandler getFirstConnection(){
|
||||||
|
ServerConnectionHandler firstCon = null;
|
||||||
connectListLock.acquireUninterruptibly();
|
connectListLock.acquireUninterruptibly();
|
||||||
ServerConnectionHandler firstCon = this.activeConnections.get(0);
|
if(this.activeConnections.size() > 0){
|
||||||
|
firstCon = this.activeConnections.get(0);
|
||||||
|
}
|
||||||
connectListLock.release();
|
connectListLock.release();
|
||||||
return firstCon;
|
return firstCon;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import electrosphere.net.parser.net.message.NetworkMessage;
|
|||||||
import electrosphere.net.parser.net.message.ServerMessage;
|
import electrosphere.net.parser.net.message.ServerMessage;
|
||||||
import electrosphere.net.parser.net.raw.NetworkParser;
|
import electrosphere.net.parser.net.raw.NetworkParser;
|
||||||
import electrosphere.net.server.player.Player;
|
import electrosphere.net.server.player.Player;
|
||||||
|
import electrosphere.util.CodeUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -69,7 +70,7 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
|
|
||||||
//thresholds for determining when to send pings and when a client has disconnected
|
//thresholds for determining when to send pings and when a client has disconnected
|
||||||
static final long SEND_PING_THRESHOLD = 3000;
|
static final long SEND_PING_THRESHOLD = 3000;
|
||||||
static final long PING_DISCONNECT_THRESHOLD = 20000;
|
static final long PING_DISCONNECT_THRESHOLD = 60 * 1000;
|
||||||
//used to keep track of ping/pong messages with client
|
//used to keep track of ping/pong messages with client
|
||||||
long lastPingTime = 0;
|
long lastPingTime = 0;
|
||||||
long lastPongTime = 0;
|
long lastPongTime = 0;
|
||||||
@ -191,18 +192,19 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
initialized = true;
|
initialized = true;
|
||||||
while(Globals.threadManager.shouldKeepRunning() && this.isConnected == true && Globals.server != null && Globals.server.isOpen()){
|
while(Globals.threadManager.shouldKeepRunning() && this.isConnected == true && Globals.server != null && Globals.server.isOpen()){
|
||||||
|
|
||||||
|
boolean receivedMessageThisLoop = false;
|
||||||
//
|
//
|
||||||
// Main Loop
|
// Main Loop
|
||||||
//
|
//
|
||||||
//parse messages both incoming and outgoing
|
//parse messages both incoming and outgoing
|
||||||
try {
|
try {
|
||||||
parseMessages();
|
receivedMessageThisLoop = parseMessages();
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
//if we get a SocketException broken pipe (basically the client dc'd without telling us)
|
//if we get a SocketException broken pipe (basically the client dc'd without telling us)
|
||||||
//set flag to disconnect client
|
//set flag to disconnect client
|
||||||
//TODO: fix, this doesn't actually catch the socket exception which is exceedingly obnoxious
|
//TODO: fix, this doesn't actually catch the socket exception which is exceedingly obnoxious
|
||||||
socketException = true;
|
socketException = true;
|
||||||
LoggerInterface.loggerNetworking.DEBUG(e.getLocalizedMessage());
|
LoggerInterface.loggerNetworking.ERROR("Client disconnected", e);
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
break;
|
break;
|
||||||
} catch (IOException e){
|
} catch (IOException e){
|
||||||
@ -210,14 +212,18 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
//set flag to disconnect client
|
//set flag to disconnect client
|
||||||
//TODO: fix, this doesn't actually catch the socket exception which is exceedingly obnoxious
|
//TODO: fix, this doesn't actually catch the socket exception which is exceedingly obnoxious
|
||||||
socketException = true;
|
socketException = true;
|
||||||
LoggerInterface.loggerNetworking.DEBUG(e.getLocalizedMessage());
|
LoggerInterface.loggerNetworking.ERROR("Client disconnected", e);
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pings
|
// Timeout logic
|
||||||
//
|
//
|
||||||
|
//mark as alive if a message was received from client
|
||||||
|
if(receivedMessageThisLoop){
|
||||||
|
this.markReceivedPongMessage();
|
||||||
|
}
|
||||||
//ping logic
|
//ping logic
|
||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
//basically if we haven't sent a ping in a while, send one
|
//basically if we haven't sent a ping in a while, send one
|
||||||
@ -235,7 +241,14 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
//check if we meet disconnection criteria
|
//check if we meet disconnection criteria
|
||||||
//has it been too long since the last ping?
|
//has it been too long since the last ping?
|
||||||
//have we had a socket exception?
|
//have we had a socket exception?
|
||||||
if(lastPingTime - lastPongTime > PING_DISCONNECT_THRESHOLD || this.socketException == true){
|
if(lastPingTime - lastPongTime > PING_DISCONNECT_THRESHOLD){
|
||||||
|
//disconnected from the server
|
||||||
|
LoggerInterface.loggerNetworking.WARNING("Client timeout");
|
||||||
|
//run disconnect routine
|
||||||
|
disconnect();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(this.socketException == true){
|
||||||
//disconnected from the server
|
//disconnected from the server
|
||||||
LoggerInterface.loggerNetworking.WARNING("Client disconnected");
|
LoggerInterface.loggerNetworking.WARNING("Client disconnected");
|
||||||
//run disconnect routine
|
//run disconnect routine
|
||||||
@ -251,13 +264,16 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
* Had to wrap the message parsing block in a function to throw a SocketException
|
* Had to wrap the message parsing block in a function to throw a SocketException
|
||||||
* without my linter freaking out
|
* without my linter freaking out
|
||||||
* @throws SocketException
|
* @throws SocketException
|
||||||
|
* @return true if connection is alive, false otherwise
|
||||||
*/
|
*/
|
||||||
void parseMessages() throws SocketException, IOException {
|
boolean parseMessages() throws SocketException, IOException {
|
||||||
|
boolean rVal = false;
|
||||||
//
|
//
|
||||||
//Read in messages
|
//Read in messages
|
||||||
//
|
//
|
||||||
//attempt poll incoming messages
|
//attempt poll incoming messages
|
||||||
networkParser.readMessagesIn();
|
networkParser.readMessagesIn();
|
||||||
|
rVal = networkParser.hasIncomingMessaage();
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -305,8 +321,9 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
TimeUnit.MILLISECONDS.sleep(1);
|
TimeUnit.MILLISECONDS.sleep(1);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
//silently ignore
|
//silently ignore
|
||||||
// CodeUtils.todo(ex, "Handle sleep interrupt on server connection");
|
CodeUtils.todo(ex, "Handle sleep interrupt on server connection");
|
||||||
}
|
}
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -404,4 +421,15 @@ public class ServerConnectionHandler implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total number of bytes read by this connection
|
||||||
|
* @return The total number of bytes
|
||||||
|
*/
|
||||||
|
public long getNumBytesRead(){
|
||||||
|
if(this.networkParser == null){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return this.networkParser.getNumberOfBytesRead();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,12 @@ package electrosphere.net.server.protocol;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.net.parser.net.message.TerrainMessage;
|
import electrosphere.net.parser.net.message.TerrainMessage;
|
||||||
import electrosphere.net.server.ServerConnectionHandler;
|
import electrosphere.net.server.ServerConnectionHandler;
|
||||||
import electrosphere.net.server.player.Player;
|
import electrosphere.net.server.player.Player;
|
||||||
@ -23,20 +25,32 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TerrainMessage handleAsyncMessage(ServerConnectionHandler connectionHandler, TerrainMessage message) {
|
public TerrainMessage handleAsyncMessage(ServerConnectionHandler connectionHandler, TerrainMessage message) {
|
||||||
|
switch(message.getMessageSubtype()){
|
||||||
|
case REQUESTCHUNKDATA: {
|
||||||
|
sendWorldSubChunkAsync(connectionHandler,
|
||||||
|
message.getworldX(), message.getworldY(), message.getworldZ()
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
} break;
|
||||||
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSyncMessage(ServerConnectionHandler connectionHandler, TerrainMessage message) {
|
public void handleSyncMessage(ServerConnectionHandler connectionHandler, TerrainMessage message) {
|
||||||
switch(message.getMessageSubtype()){
|
switch(message.getMessageSubtype()){
|
||||||
case REQUESTMETADATA:
|
case REQUESTMETADATA: {
|
||||||
sendWorldMetadata(connectionHandler);
|
sendWorldMetadata(connectionHandler);
|
||||||
break;
|
} break;
|
||||||
case REQUESTCHUNKDATA:
|
case REQUESTCHUNKDATA: {
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Server) Received request for terrain " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ());
|
||||||
|
// System.out.println("Received request for terrain " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ());
|
||||||
sendWorldSubChunk(connectionHandler,
|
sendWorldSubChunk(connectionHandler,
|
||||||
message.getworldX(), message.getworldY(), message.getworldZ()
|
message.getworldX(), message.getworldY(), message.getworldZ()
|
||||||
);
|
);
|
||||||
break;
|
} break;
|
||||||
case REQUESTEDITVOXEL: {
|
case REQUESTEDITVOXEL: {
|
||||||
attemptTerrainEdit(connectionHandler, message);
|
attemptTerrainEdit(connectionHandler, message);
|
||||||
} break;
|
} break;
|
||||||
@ -44,6 +58,8 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
|
|||||||
attemptUseTerrainEditPalette(connectionHandler, message);
|
attemptUseTerrainEditPalette(connectionHandler, message);
|
||||||
} break;
|
} break;
|
||||||
case REQUESTFLUIDDATA: {
|
case REQUESTFLUIDDATA: {
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Server) Received request for fluid " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ());
|
||||||
|
// System.out.println("Received request for fluid " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ());
|
||||||
sendWorldFluidSubChunk(connectionHandler,
|
sendWorldFluidSubChunk(connectionHandler,
|
||||||
message.getworldX(), message.getworldY(), message.getworldZ()
|
message.getworldX(), message.getworldY(), message.getworldZ()
|
||||||
);
|
);
|
||||||
@ -70,28 +86,7 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
|
|||||||
* @param worldZ the world z
|
* @param worldZ the world z
|
||||||
*/
|
*/
|
||||||
static void sendWorldSubChunk(ServerConnectionHandler connectionHandler, int worldX, int worldY, int worldZ){
|
static void sendWorldSubChunk(ServerConnectionHandler connectionHandler, int worldX, int worldY, int worldZ){
|
||||||
/*
|
Globals.profiler.beginAggregateCpuSample("TerrainProtocol(server).sendWorldSubChunk");
|
||||||
int locationX,
|
|
||||||
int locationY,
|
|
||||||
float macroValue00,
|
|
||||||
float macroValue01,
|
|
||||||
float macroValue02,
|
|
||||||
float macroValue10,
|
|
||||||
float macroValue11,
|
|
||||||
float macroValue12,
|
|
||||||
float macroValue20,
|
|
||||||
float macroValue21,
|
|
||||||
float macroValue22,
|
|
||||||
long randomizerValue00,
|
|
||||||
long randomizerValue01,
|
|
||||||
long randomizerValue02,
|
|
||||||
long randomizerValue10,
|
|
||||||
long randomizerValue11,
|
|
||||||
long randomizerValue12,
|
|
||||||
long randomizerValue20,
|
|
||||||
long randomizerValue21,
|
|
||||||
long randomizerValue22
|
|
||||||
*/
|
|
||||||
|
|
||||||
// System.out.println("Received request for chunk " + message.getworldX() + " " + message.getworldY());
|
// System.out.println("Received request for chunk " + message.getworldX() + " " + message.getworldY());
|
||||||
Realm realm = Globals.playerManager.getPlayerRealm(connectionHandler.getPlayer());
|
Realm realm = Globals.playerManager.getPlayerRealm(connectionHandler.getPlayer());
|
||||||
@ -99,12 +94,8 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the chunk
|
//request chunk
|
||||||
ServerTerrainChunk chunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldX, worldY, worldZ);
|
ServerTerrainChunk chunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldX, worldY, worldZ);
|
||||||
|
|
||||||
// float[][] macroValues = chunk.getMacroValues();//Globals.serverTerrainManager.getRad5MacroValues(message.getworldX(), message.getworldY());
|
|
||||||
|
|
||||||
// long[][] randomizer = chunk.getRandomizer();//Globals.serverTerrainManager.getRandomizer(message.getworldX(), message.getworldY());
|
|
||||||
|
|
||||||
//The length along each access of the chunk data. Typically, should be at least 17.
|
//The length along each access of the chunk data. Typically, should be at least 17.
|
||||||
//Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate
|
//Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate
|
||||||
@ -135,89 +126,68 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println("(Server) Send terrain at " + worldX + " " + worldY + " " + worldZ);
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Server) Send terrain at " + worldX + " " + worldY + " " + worldZ);
|
||||||
connectionHandler.addMessagetoOutgoingQueue(TerrainMessage.constructsendChunkDataMessage(worldX, worldY, worldZ, buffer.array()));
|
connectionHandler.addMessagetoOutgoingQueue(TerrainMessage.constructsendChunkDataMessage(worldX, worldY, worldZ, buffer.array()));
|
||||||
|
|
||||||
// int numMessages = 2 + chunk.getModifications().size();
|
Globals.profiler.endCpuSample();
|
||||||
|
}
|
||||||
|
|
||||||
// connectionHandler.addMessagetoOutgoingQueue(
|
/**
|
||||||
// TerrainMessage.constructchunkLoadStartMessage(worldX, worldY, numMessages)
|
* Sends a subchunk to the client
|
||||||
// );
|
* @param connectionHandler The connection handler
|
||||||
|
* @param worldX the world x
|
||||||
|
* @param worldY the world y
|
||||||
|
* @param worldZ the world z
|
||||||
|
*/
|
||||||
|
static void sendWorldSubChunkAsync(ServerConnectionHandler connectionHandler, int worldX, int worldY, int worldZ){
|
||||||
|
Globals.profiler.beginAggregateCpuSample("TerrainProtocol(server).sendWorldSubChunk");
|
||||||
|
|
||||||
|
// System.out.println("Received request for chunk " + message.getworldX() + " " + message.getworldY());
|
||||||
|
Realm realm = Globals.playerManager.getPlayerRealm(connectionHandler.getPlayer());
|
||||||
|
if(realm.getServerWorldData().getServerTerrainManager() == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// connectionHandler.addMessagetoOutgoingQueue(
|
Consumer<ServerTerrainChunk> onLoad = (ServerTerrainChunk chunk) -> {
|
||||||
// TerrainMessage.constructMacroValueMessage(
|
//The length along each access of the chunk data. Typically, should be at least 17.
|
||||||
// worldX,
|
//Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate
|
||||||
// worldY,
|
//chunk data that connects seamlessly to the next chunk.
|
||||||
|
int xWidth = chunk.getWeights().length;
|
||||||
|
int yWidth = chunk.getWeights()[0].length;
|
||||||
// macroValues[0][0],
|
int zWidth = chunk.getWeights()[0][0].length;
|
||||||
// macroValues[0][1],
|
|
||||||
// macroValues[0][2],
|
|
||||||
// macroValues[0][3],
|
|
||||||
// macroValues[0][4],
|
|
||||||
// macroValues[1][0],
|
|
||||||
// macroValues[1][1],
|
|
||||||
// macroValues[1][2],
|
|
||||||
// macroValues[1][3],
|
|
||||||
// macroValues[1][4],
|
|
||||||
// macroValues[2][0],
|
|
||||||
// macroValues[2][1],
|
|
||||||
// macroValues[2][2],
|
|
||||||
// macroValues[2][3],
|
|
||||||
// macroValues[2][4],
|
|
||||||
// macroValues[3][0],
|
|
||||||
// macroValues[3][1],
|
|
||||||
// macroValues[3][2],
|
|
||||||
// macroValues[3][3],
|
|
||||||
// macroValues[3][4],
|
|
||||||
// macroValues[4][0],
|
|
||||||
// macroValues[4][1],
|
|
||||||
// macroValues[4][2],
|
|
||||||
// macroValues[4][3],
|
|
||||||
// macroValues[4][4],
|
|
||||||
|
|
||||||
|
|
||||||
// randomizer[0][0],
|
|
||||||
// randomizer[0][1],
|
|
||||||
// randomizer[0][2],
|
|
||||||
// randomizer[0][3],
|
|
||||||
// randomizer[0][4],
|
|
||||||
// randomizer[1][0],
|
|
||||||
// randomizer[1][1],
|
|
||||||
// randomizer[1][2],
|
|
||||||
// randomizer[1][3],
|
|
||||||
// randomizer[1][4],
|
|
||||||
// randomizer[2][0],
|
|
||||||
// randomizer[2][1],
|
|
||||||
// randomizer[2][2],
|
|
||||||
// randomizer[2][3],
|
|
||||||
// randomizer[2][4],
|
|
||||||
// randomizer[3][0],
|
|
||||||
// randomizer[3][1],
|
|
||||||
// randomizer[3][2],
|
|
||||||
// randomizer[3][3],
|
|
||||||
// randomizer[3][4],
|
|
||||||
// randomizer[4][0],
|
|
||||||
// randomizer[4][1],
|
|
||||||
// randomizer[4][2],
|
|
||||||
// randomizer[4][3],
|
|
||||||
// randomizer[4][4]
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
|
|
||||||
// for(TerrainModification modification : chunk.getModifications()){
|
ByteBuffer buffer = ByteBuffer.allocate(xWidth*yWidth*zWidth*(4+4));
|
||||||
// connectionHandler.addMessagetoOutgoingQueue(
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
// TerrainMessage.constructheightMapModificationMessage(
|
|
||||||
// modification.getValue(),
|
for(int x = 0; x < xWidth; x++){
|
||||||
// modification.getWorldX(),
|
for(int y = 0; y < yWidth; y++){
|
||||||
// 0,
|
for(int z = 0; z < zWidth; z++){
|
||||||
// modification.getWorldY(),
|
floatView.put(chunk.getWeights()[x][y][z]);
|
||||||
// modification.getLocationX(),
|
}
|
||||||
// 0,
|
}
|
||||||
// modification.getLocationY()
|
}
|
||||||
// )
|
|
||||||
// );
|
IntBuffer intView = buffer.asIntBuffer();
|
||||||
// }
|
intView.position(floatView.position());
|
||||||
|
|
||||||
|
for(int x = 0; x < xWidth; x++){
|
||||||
|
for(int y = 0; y < yWidth; y++){
|
||||||
|
for(int z = 0; z < zWidth; z++){
|
||||||
|
intView.put(chunk.getValues()[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.out.println("(Server) Send terrain at " + worldX + " " + worldY + " " + worldZ);
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Server) Send terrain at " + worldX + " " + worldY + " " + worldZ);
|
||||||
|
connectionHandler.addMessagetoOutgoingQueue(TerrainMessage.constructsendChunkDataMessage(worldX, worldY, worldZ, buffer.array()));
|
||||||
|
};
|
||||||
|
|
||||||
|
//request chunk
|
||||||
|
realm.getServerWorldData().getServerTerrainManager().getChunkAsync(worldX, worldY, worldZ, onLoad);
|
||||||
|
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,11 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
|||||||
|
|
||||||
public class TerrainChunkModelGeneration {
|
public class TerrainChunkModelGeneration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum iso value
|
||||||
|
*/
|
||||||
|
public static final float MIN_ISO_VALUE = 0.01f;
|
||||||
|
|
||||||
//http://paulbourke.net/geometry/polygonise/
|
//http://paulbourke.net/geometry/polygonise/
|
||||||
|
|
||||||
public static int edgeTable[]={
|
public static int edgeTable[]={
|
||||||
@ -620,7 +625,7 @@ public class TerrainChunkModelGeneration {
|
|||||||
return new Vector3f(x,y,z);
|
return new Vector3f(x,y,z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid, int lod){
|
public static TerrainChunkData generateTerrainChunkData(float[][][] terrainGrid, int[][][] textureGrid){
|
||||||
|
|
||||||
// 5 6
|
// 5 6
|
||||||
// +-------------+ +-----5-------+ ^ Y
|
// +-------------+ +-----5-------+ ^ Y
|
||||||
@ -664,7 +669,7 @@ public class TerrainChunkModelGeneration {
|
|||||||
textureGrid[x+0][y+1][z+0], textureGrid[x+0][y+1][z+1], textureGrid[x+1][y+1][z+1], textureGrid[x+1][y+1][z+0]
|
textureGrid[x+0][y+1][z+0], textureGrid[x+0][y+1][z+1], textureGrid[x+1][y+1][z+1], textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,11 @@ public class TransvoxelModelGeneration {
|
|||||||
//the lower the value, the more of the low resolution chunk we will see
|
//the lower the value, the more of the low resolution chunk we will see
|
||||||
static final float TRANSITION_CELL_WIDTH = 0.5f;
|
static final float TRANSITION_CELL_WIDTH = 0.5f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimension of the array for the face generator. It must be 2 * <size of chunk> + 1. The extra 1 is for the neighbor value
|
||||||
|
*/
|
||||||
|
public static final int FACE_DATA_DIMENSIONS = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE + ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -647,7 +652,7 @@ public class TransvoxelModelGeneration {
|
|||||||
if(firstSample > isolevel){
|
if(firstSample > isolevel){
|
||||||
samplerIndex[i] = getTransvoxelTextureValue(transitionCell.simpleFaceAtlasValues,transitionCell.complexFaceAtlasValues,firstCornerSampleIndex);
|
samplerIndex[i] = getTransvoxelTextureValue(transitionCell.simpleFaceAtlasValues,transitionCell.complexFaceAtlasValues,firstCornerSampleIndex);
|
||||||
} else {
|
} else {
|
||||||
samplerIndex[i] = sampleIndexTable[1][i];
|
samplerIndex[i] = getTransvoxelTextureValue(transitionCell.simpleFaceAtlasValues,transitionCell.complexFaceAtlasValues,secondCornerSampleIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -982,8 +987,7 @@ public class TransvoxelModelGeneration {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates mesh data given chunk data
|
* Generates mesh data given chunk data
|
||||||
* @param terrainGrid The chunk data
|
* @param chunkData The chunk data
|
||||||
* @param textureGrid The chunk texture data
|
|
||||||
* @return The mesh data
|
* @return The mesh data
|
||||||
*/
|
*/
|
||||||
public static TerrainChunkData generateTerrainChunkData(TransvoxelChunkData chunkData){
|
public static TerrainChunkData generateTerrainChunkData(TransvoxelChunkData chunkData){
|
||||||
@ -1019,9 +1023,9 @@ public class TransvoxelModelGeneration {
|
|||||||
List<Vector3f> samplerTriangles = new LinkedList<Vector3f>();
|
List<Vector3f> samplerTriangles = new LinkedList<Vector3f>();
|
||||||
//List of UVs
|
//List of UVs
|
||||||
List<Float> UVs = new LinkedList<Float>();
|
List<Float> UVs = new LinkedList<Float>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the interior of the mesh
|
//Generate the interior of the mesh
|
||||||
for(int x = 1; x < chunkData.terrainGrid.length - 2; x++){
|
for(int x = 1; x < chunkData.terrainGrid.length - 2; x++){
|
||||||
@ -1037,7 +1041,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1059,8 +1063,8 @@ public class TransvoxelModelGeneration {
|
|||||||
//generate the x-positive face
|
//generate the x-positive face
|
||||||
if(chunkData.xPositiveEdgeIso != null){
|
if(chunkData.xPositiveEdgeIso != null){
|
||||||
int x = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 2;
|
int x = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 2;
|
||||||
for(int y = yStartIndex; y < yEndIndex - 1; y++){
|
for(int y = yStartIndex; y < yEndIndex; y++){
|
||||||
for(int z = zStartIndex; z < zEndIndex - 1; z++){
|
for(int z = zStartIndex; z < zEndIndex; z++){
|
||||||
//
|
//
|
||||||
//Generate the transition cell
|
//Generate the transition cell
|
||||||
//
|
//
|
||||||
@ -1087,7 +1091,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.xPositiveEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+0)*2+0],
|
chunkData.xPositiveEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+0)*2+0],
|
||||||
chunkData.xPositiveEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+1)*2+0]
|
chunkData.xPositiveEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+1)*2+0]
|
||||||
);
|
);
|
||||||
polygonizeTransition(currentTransitionCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the normal cell with half width
|
//Generate the normal cell with half width
|
||||||
@ -1101,7 +1105,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+1)*2+0], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+0)*2+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+1)*2+0], chunkData.xPositiveEdgeAtlas[(y+1)*2+0][(z+0)*2+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1118,7 +1122,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1133,8 +1137,8 @@ public class TransvoxelModelGeneration {
|
|||||||
//generate the x-negative face
|
//generate the x-negative face
|
||||||
if(chunkData.xNegativeEdgeIso != null){
|
if(chunkData.xNegativeEdgeIso != null){
|
||||||
int x = 0;
|
int x = 0;
|
||||||
for(int y = yStartIndex; y < yEndIndex - 1; y++){
|
for(int y = yStartIndex; y < yEndIndex; y++){
|
||||||
for(int z = zStartIndex; z < zEndIndex - 1; z++){
|
for(int z = zStartIndex; z < zEndIndex; z++){
|
||||||
//
|
//
|
||||||
//Generate the transition cell
|
//Generate the transition cell
|
||||||
//
|
//
|
||||||
@ -1161,7 +1165,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0],
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0],
|
||||||
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0]
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0]
|
||||||
);
|
);
|
||||||
polygonizeTransition(currentTransitionCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the normal cell with half width
|
//Generate the normal cell with half width
|
||||||
@ -1175,7 +1179,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1192,7 +1196,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1206,8 +1210,8 @@ public class TransvoxelModelGeneration {
|
|||||||
//generate the y-positive face
|
//generate the y-positive face
|
||||||
if(chunkData.yPositiveEdgeIso != null){
|
if(chunkData.yPositiveEdgeIso != null){
|
||||||
int y = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 2;
|
int y = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 2;
|
||||||
for(int x = xStartIndex; x < xEndIndex - 1; x++){
|
for(int x = xStartIndex; x < xEndIndex; x++){
|
||||||
for(int z = zStartIndex; z < zEndIndex - 1; z++){
|
for(int z = zStartIndex; z < zEndIndex; z++){
|
||||||
//
|
//
|
||||||
//Generate the transition cell
|
//Generate the transition cell
|
||||||
//
|
//
|
||||||
@ -1234,7 +1238,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+0)*2+0],
|
chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+0)*2+0],
|
||||||
chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+1)*2+0]
|
chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+1)*2+0]
|
||||||
);
|
);
|
||||||
polygonizeTransition(currentTransitionCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the normal cell with half width
|
//Generate the normal cell with half width
|
||||||
@ -1248,7 +1252,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+1)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+0)*2+0]
|
chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yPositiveEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+1)*2+0], chunkData.yPositiveEdgeAtlas[(x+1)*2+0][(z+0)*2+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1265,7 +1269,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1279,8 +1283,8 @@ public class TransvoxelModelGeneration {
|
|||||||
//generate the y-negative face
|
//generate the y-negative face
|
||||||
if(chunkData.yNegativeEdgeIso != null){
|
if(chunkData.yNegativeEdgeIso != null){
|
||||||
int y = 0;
|
int y = 0;
|
||||||
for(int x = xStartIndex; x < xEndIndex - 1; x++){
|
for(int x = xStartIndex; x < xEndIndex; x++){
|
||||||
for(int z = zStartIndex; z < zEndIndex - 1; z++){
|
for(int z = zStartIndex; z < zEndIndex; z++){
|
||||||
//
|
//
|
||||||
//Generate the transition cell
|
//Generate the transition cell
|
||||||
//
|
//
|
||||||
@ -1307,7 +1311,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+0)*2+0],
|
chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+0)*2+0],
|
||||||
chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+1)*2+0]
|
chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+1)*2+0]
|
||||||
);
|
);
|
||||||
polygonizeTransition(currentTransitionCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the normal cell with half width
|
//Generate the normal cell with half width
|
||||||
@ -1315,13 +1319,13 @@ public class TransvoxelModelGeneration {
|
|||||||
currentCell.setValues(
|
currentCell.setValues(
|
||||||
new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0),
|
new Vector3f(x+0,y+1,z+0), new Vector3f(x+0,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+0),
|
||||||
new Vector3f(x+0,y+TRANSITION_CELL_WIDTH,z+0), new Vector3f(x+0,y+TRANSITION_CELL_WIDTH,z+1), new Vector3f(x+1,y+TRANSITION_CELL_WIDTH,z+1), new Vector3f(x+1,y+TRANSITION_CELL_WIDTH,z+0),
|
new Vector3f(x+0,y+TRANSITION_CELL_WIDTH,z+0), new Vector3f(x+0,y+TRANSITION_CELL_WIDTH,z+1), new Vector3f(x+1,y+TRANSITION_CELL_WIDTH,z+1), new Vector3f(x+1,y+TRANSITION_CELL_WIDTH,z+0),
|
||||||
chunkData.terrainGrid[x+0][y+0][z+0], chunkData.terrainGrid[x+0][y+0][z+1], chunkData.terrainGrid[x+1][y+0][z+1], chunkData.terrainGrid[x+1][y+0][z+0],
|
chunkData.terrainGrid[x+0][y+1][z+0], chunkData.terrainGrid[x+0][y+1][z+1], chunkData.terrainGrid[x+1][y+1][z+1], chunkData.terrainGrid[x+1][y+1][z+0],
|
||||||
chunkData.yNegativeEdgeIso[(x+0)*2+0][(z+0)*2+0], chunkData.yNegativeEdgeIso[(x+0)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeIso[(x+1)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeIso[(x+1)*2+0][(z+0)*2+0],
|
chunkData.yNegativeEdgeIso[(x+0)*2+0][(z+0)*2+0], chunkData.yNegativeEdgeIso[(x+0)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeIso[(x+1)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeIso[(x+1)*2+0][(z+0)*2+0],
|
||||||
chunkData.textureGrid[x+0][y+0][z+0], chunkData.textureGrid[x+0][y+0][z+1], chunkData.textureGrid[x+1][y+0][z+1], chunkData.textureGrid[x+1][y+0][z+0],
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0],
|
||||||
chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+0)*2+0]
|
chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+0)*2+0], chunkData.yNegativeEdgeAtlas[(x+0)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+1)*2+0], chunkData.yNegativeEdgeAtlas[(x+1)*2+0][(z+0)*2+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1338,7 +1342,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1353,8 +1357,8 @@ public class TransvoxelModelGeneration {
|
|||||||
//generate the z-positive face
|
//generate the z-positive face
|
||||||
if(chunkData.zPositiveEdgeIso != null){
|
if(chunkData.zPositiveEdgeIso != null){
|
||||||
int z = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 2;
|
int z = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 2;
|
||||||
for(int x = xStartIndex; x < xEndIndex - 1; x++){
|
for(int x = xStartIndex; x < xEndIndex; x++){
|
||||||
for(int y = yStartIndex; y < yEndIndex - 1; y++){
|
for(int y = yStartIndex; y < yEndIndex; y++){
|
||||||
//
|
//
|
||||||
//Generate the transition cell
|
//Generate the transition cell
|
||||||
//
|
//
|
||||||
@ -1381,7 +1385,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.zPositiveEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zPositiveEdgeAtlas[(x+0)*2+0][(y+1)*2+0],
|
chunkData.zPositiveEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zPositiveEdgeAtlas[(x+0)*2+0][(y+1)*2+0],
|
||||||
chunkData.zPositiveEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.zPositiveEdgeAtlas[(x+1)*2+0][(y+1)*2+0]
|
chunkData.zPositiveEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.zPositiveEdgeAtlas[(x+1)*2+0][(y+1)*2+0]
|
||||||
);
|
);
|
||||||
polygonizeTransition(currentTransitionCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the normal cell with half width
|
//Generate the normal cell with half width
|
||||||
@ -1395,7 +1399,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.zPositiveEdgeAtlas[(x+0)*2+0][(y+1)*2+0], chunkData.zPositiveEdgeAtlas[(x+1)*2+0][(y+1)*2+0], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.zPositiveEdgeAtlas[(x+0)*2+0][(y+1)*2+0], chunkData.zPositiveEdgeAtlas[(x+1)*2+0][(y+1)*2+0], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1412,7 +1416,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1427,16 +1431,16 @@ public class TransvoxelModelGeneration {
|
|||||||
//generate the z-negative face
|
//generate the z-negative face
|
||||||
if(chunkData.zNegativeEdgeIso != null){
|
if(chunkData.zNegativeEdgeIso != null){
|
||||||
int z = 0;
|
int z = 0;
|
||||||
for(int x = xStartIndex; x < xEndIndex - 1; x++){
|
for(int x = xStartIndex; x < xEndIndex; x++){
|
||||||
for(int y = yStartIndex; y < yEndIndex - 1; y++){
|
for(int y = yStartIndex; y < yEndIndex; y++){
|
||||||
//
|
//
|
||||||
//Generate the transition cell
|
//Generate the transition cell
|
||||||
//
|
//
|
||||||
currentTransitionCell.setValues(
|
currentTransitionCell.setValues(
|
||||||
//complex face vertex coordinates
|
//complex face vertex coordinates
|
||||||
new Vector3f(x+0,y,z), new Vector3f(x+0,y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+0,y+1,z),
|
new Vector3f(x+0, y,z), new Vector3f(x+0, y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+0, y+1,z),
|
||||||
new Vector3f(x+TRANSITION_CELL_WIDTH,y,z), new Vector3f(x+TRANSITION_CELL_WIDTH,y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z),
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y,z), new Vector3f(x+TRANSITION_CELL_WIDTH,y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z),
|
||||||
new Vector3f(x+1,y,z), new Vector3f(x+1,y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+1,y+1,z),
|
new Vector3f(x+1, y,z), new Vector3f(x+1, y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+1, y+1,z),
|
||||||
//simple face vertex coordinates
|
//simple face vertex coordinates
|
||||||
new Vector3f(x+0,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+0,y+1,z+TRANSITION_CELL_WIDTH),
|
new Vector3f(x+0,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+0,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
new Vector3f(x+1,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+TRANSITION_CELL_WIDTH),
|
new Vector3f(x+1,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
@ -1455,7 +1459,7 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+1)*2+0],
|
chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+1)*2+0],
|
||||||
chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+1)*2+0]
|
chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+1)*2+0]
|
||||||
);
|
);
|
||||||
polygonizeTransition(currentTransitionCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
//
|
//
|
||||||
//Generate the normal cell with half width
|
//Generate the normal cell with half width
|
||||||
@ -1463,13 +1467,13 @@ public class TransvoxelModelGeneration {
|
|||||||
currentCell.setValues(
|
currentCell.setValues(
|
||||||
new Vector3f(x+0,y+0,z+1), new Vector3f(x+0,y+0,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+0,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+0,z+1),
|
new Vector3f(x+0,y+0,z+1), new Vector3f(x+0,y+0,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+0,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+0,z+1),
|
||||||
new Vector3f(x+0,y+1,z+1), new Vector3f(x+0,y+1,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+1),
|
new Vector3f(x+0,y+1,z+1), new Vector3f(x+0,y+1,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+1),
|
||||||
chunkData.terrainGrid[x+0][y+0][z+0], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+0)*2+0], chunkData.terrainGrid[x+1][y+0][z+0],
|
chunkData.terrainGrid[x+0][y+0][z+1], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+0)*2+0], chunkData.terrainGrid[x+1][y+0][z+1],
|
||||||
chunkData.terrainGrid[x+0][y+1][z+0], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+1)*2+0], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+1)*2+0], chunkData.terrainGrid[x+1][y+1][z+0],
|
chunkData.terrainGrid[x+0][y+1][z+1], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+1)*2+0], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+1)*2+0], chunkData.terrainGrid[x+1][y+1][z+1],
|
||||||
chunkData.textureGrid[x+0][y+0][z+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.textureGrid[x+1][y+0][z+0],
|
chunkData.textureGrid[x+0][y+0][z+1], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.textureGrid[x+1][y+0][z+1],
|
||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+1)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+1)*2+0], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+1], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+1)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+1)*2+0], chunkData.textureGrid[x+1][y+1][z+1]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1486,11 +1490,92 @@ public class TransvoxelModelGeneration {
|
|||||||
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
chunkData.textureGrid[x+0][y+1][z+0], chunkData.textureGrid[x+0][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
);
|
);
|
||||||
//polygonize the current gridcell
|
//polygonize the current gridcell
|
||||||
polygonize(currentCell, 0.01f, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//xn-zn edge
|
||||||
|
if(chunkData.xNegativeEdgeIso != null && chunkData.zNegativeEdgeIso != null){
|
||||||
|
int x = 0;
|
||||||
|
int z = 0;
|
||||||
|
int edgeLength = chunkWidth - (chunkData.yNegativeEdgeIso != null ? 1 : 0) - (chunkData.yPositiveEdgeIso != null ? 1 : 0);
|
||||||
|
int startIndex = 0 + (chunkData.yNegativeEdgeIso != null ? 1 : 0);
|
||||||
|
for(int i = startIndex; i < edgeLength - 1; i++){
|
||||||
|
int y = i;
|
||||||
|
//
|
||||||
|
//Generate the x-side transition cell
|
||||||
|
//
|
||||||
|
currentTransitionCell.setValues(
|
||||||
|
//complex face vertex coordinates
|
||||||
|
new Vector3f(x,y,z), new Vector3f(x,y+TRANSITION_CELL_WIDTH,z), new Vector3f(x,y+1,z),
|
||||||
|
new Vector3f(x,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x,y+TRANSITION_CELL_WIDTH,z+TRANSITION_CELL_WIDTH), new Vector3f(x,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
|
new Vector3f(x,y,z+1), new Vector3f(x,y+TRANSITION_CELL_WIDTH,z+1), new Vector3f(x,y+1,z+1),
|
||||||
|
//simple face vertex coordinates
|
||||||
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y,z+1), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z+1),
|
||||||
|
//complex face iso values
|
||||||
|
chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeIso[(y+0)*2+1][(z+0)*2+0], chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+0)*2+0],
|
||||||
|
chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+0)*2+1], chunkData.xNegativeEdgeIso[(y+0)*2+1][(z+0)*2+1], chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+0)*2+1],
|
||||||
|
chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+1)*2+0], chunkData.xNegativeEdgeIso[(y+0)*2+1][(z+1)*2+0], chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+1)*2+0],
|
||||||
|
//simple face iso values
|
||||||
|
chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+0)*2+0],
|
||||||
|
chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+1)*2+0], chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+1)*2+0],
|
||||||
|
//complex face texture atlas values
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+0)*2+1][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0],
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+0)*2+1], chunkData.xNegativeEdgeAtlas[(y+0)*2+1][(z+0)*2+1], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+1],
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.xNegativeEdgeAtlas[(y+0)*2+1][(z+1)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0],
|
||||||
|
//simple face texture atlas values
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0],
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0]
|
||||||
|
);
|
||||||
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
|
//
|
||||||
|
//Generate the z-side transition cell
|
||||||
|
//
|
||||||
|
currentTransitionCell.setValues(
|
||||||
|
//complex face vertex coordinates
|
||||||
|
new Vector3f(x+0, y,z), new Vector3f(x+0, y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+0, y+1,z),
|
||||||
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y,z), new Vector3f(x+TRANSITION_CELL_WIDTH,y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z),
|
||||||
|
new Vector3f(x+1, y,z), new Vector3f(x+1, y+TRANSITION_CELL_WIDTH,z), new Vector3f(x+1, y+1,z),
|
||||||
|
//simple face vertex coordinates
|
||||||
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
|
new Vector3f(x+1,y,z+TRANSITION_CELL_WIDTH), new Vector3f(x+1,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
|
//complex face iso values
|
||||||
|
chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+0)*2+1], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+1)*2+0],
|
||||||
|
chunkData.zNegativeEdgeIso[(x+0)*2+1][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+0)*2+1][(y+0)*2+1], chunkData.zNegativeEdgeIso[(x+0)*2+1][(y+1)*2+0],
|
||||||
|
chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+0)*2+1], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+1)*2+0],
|
||||||
|
//simple face iso values
|
||||||
|
chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+0)*2+0][(y+1)*2+0],
|
||||||
|
chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeIso[(x+1)*2+0][(y+1)*2+0],
|
||||||
|
//complex face texture atlas values
|
||||||
|
chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+1], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+1)*2+0],
|
||||||
|
chunkData.zNegativeEdgeAtlas[(x+0)*2+1][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+1][(y+0)*2+1], chunkData.zNegativeEdgeAtlas[(x+0)*2+1][(y+1)*2+0],
|
||||||
|
chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+1], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+1)*2+0],
|
||||||
|
//simple face texture atlas values
|
||||||
|
chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+0)*2+0][(y+1)*2+0],
|
||||||
|
chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+0)*2+0], chunkData.zNegativeEdgeAtlas[(x+1)*2+0][(y+1)*2+0]
|
||||||
|
);
|
||||||
|
polygonizeTransition(currentTransitionCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
|
||||||
|
//
|
||||||
|
//Generate the normal cell with half width
|
||||||
|
//
|
||||||
|
currentCell.setValues(
|
||||||
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y+0,z+TRANSITION_CELL_WIDTH), new Vector3f(x+TRANSITION_CELL_WIDTH,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+TRANSITION_CELL_WIDTH),
|
||||||
|
new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z+TRANSITION_CELL_WIDTH), new Vector3f(x+TRANSITION_CELL_WIDTH,y+1,z+1), new Vector3f(x+1,y+1,z+1), new Vector3f(x+1,y+1,z+TRANSITION_CELL_WIDTH),
|
||||||
|
chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeIso[(y+0)*2+0][(z+1)*2+0], chunkData.terrainGrid[x+1][y+0][z+1], chunkData.terrainGrid[x+1][y+0][z+0],
|
||||||
|
chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeIso[(y+1)*2+0][(z+1)*2+0], chunkData.terrainGrid[x+1][y+1][z+1], chunkData.terrainGrid[x+1][y+1][z+0],
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+0)*2+0][(z+1)*2+0], chunkData.textureGrid[x+1][y+0][z+1], chunkData.textureGrid[x+1][y+0][z+0],
|
||||||
|
chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+0)*2+0], chunkData.xNegativeEdgeAtlas[(y+1)*2+0][(z+1)*2+0], chunkData.textureGrid[x+1][y+1][z+1], chunkData.textureGrid[x+1][y+1][z+0]
|
||||||
|
);
|
||||||
|
//polygonize the current gridcell
|
||||||
|
polygonize(currentCell, TerrainChunkModelGeneration.MIN_ISO_VALUE, triangles, samplerTriangles, vertMap, verts, normals, trianglesSharingVert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,11 @@ public class ImGuiLinePlot implements ImGuiElement {
|
|||||||
//the data sets to draw
|
//the data sets to draw
|
||||||
List<ImGuiLinePlotDataset> dataSets = new LinkedList<ImGuiLinePlotDataset>();
|
List<ImGuiLinePlotDataset> dataSets = new LinkedList<ImGuiLinePlotDataset>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the plot
|
||||||
|
*/
|
||||||
|
ImVec2 size = new ImVec2(-1,-1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an im gui line plot
|
* Creates an im gui line plot
|
||||||
*/
|
*/
|
||||||
@ -25,9 +30,18 @@ public class ImGuiLinePlot implements ImGuiElement {
|
|||||||
this.plotTitle = plotTitle;
|
this.plotTitle = plotTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an im gui line plot
|
||||||
|
*/
|
||||||
|
public ImGuiLinePlot(String plotTitle, int sizeX, int sizeY){
|
||||||
|
this.plotTitle = plotTitle;
|
||||||
|
this.size.x = sizeX;
|
||||||
|
this.size.y = sizeY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw() {
|
public void draw() {
|
||||||
if(ImPlot.beginPlot(plotTitle,"","",new ImVec2(-1,-1),0,ImPlotAxisFlags.AutoFit,ImPlotAxisFlags.AutoFit)){
|
if(ImPlot.beginPlot(plotTitle,"","",size,0,ImPlotAxisFlags.AutoFit,ImPlotAxisFlags.AutoFit)){
|
||||||
for(ImGuiLinePlotDataset dataSet : dataSets){
|
for(ImGuiLinePlotDataset dataSet : dataSets){
|
||||||
double[] xs = dataSet.xData.stream().mapToDouble(Double::doubleValue).toArray();//(Double[])dataSet.xData.toArray(new Double[dataSet.xData.size()]);
|
double[] xs = dataSet.xData.stream().mapToDouble(Double::doubleValue).toArray();//(Double[])dataSet.xData.toArray(new Double[dataSet.xData.size()]);
|
||||||
double[] ys = dataSet.yData.stream().mapToDouble(Double::doubleValue).toArray();//(Double[])dataSet.yData.toArray(new Double[dataSet.yData.size()]);
|
double[] ys = dataSet.yData.stream().mapToDouble(Double::doubleValue).toArray();//(Double[])dataSet.yData.toArray(new Double[dataSet.yData.size()]);
|
||||||
@ -102,6 +116,15 @@ public class ImGuiLinePlot implements ImGuiElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeroes out the dataset
|
||||||
|
*/
|
||||||
|
public void zeroOut(){
|
||||||
|
for(int i = 0; i < limit; i++){
|
||||||
|
this.addPoint(i, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,8 @@ public class MainServerFunctions {
|
|||||||
if(Globals.server != null){
|
if(Globals.server != null){
|
||||||
Globals.server.synchronousPacketHandling();
|
Globals.server.synchronousPacketHandling();
|
||||||
}
|
}
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
Globals.profiler.beginCpuSample("Server process synchronization messages");
|
||||||
if(Globals.serverSynchronizationManager != null){
|
if(Globals.serverSynchronizationManager != null){
|
||||||
Globals.serverSynchronizationManager.processMessages();
|
Globals.serverSynchronizationManager.processMessages();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
/**
|
/**
|
||||||
* The max grid size allowed
|
* The max grid size allowed
|
||||||
*/
|
*/
|
||||||
public static final int MAX_GRID_SIZE = 10;
|
public static final int MAX_GRID_SIZE = 2000 * 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks whether this manager has been flagged to unload cells or not
|
* Tracks whether this manager has been flagged to unload cells or not
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package electrosphere.server.datacell.physics;
|
|||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.renderer.shader.ShaderProgram;
|
import electrosphere.renderer.shader.ShaderProgram;
|
||||||
import electrosphere.server.datacell.Realm;
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -65,7 +66,7 @@ public class DataCellPhysicsManager {
|
|||||||
* @param discreteY The initial discrete position Y coordinate
|
* @param discreteY The initial discrete position Y coordinate
|
||||||
*/
|
*/
|
||||||
public DataCellPhysicsManager(Realm realm, int discreteX, int discreteY, int discreteZ){
|
public DataCellPhysicsManager(Realm realm, int discreteX, int discreteY, int discreteZ){
|
||||||
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
|
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / ServerTerrainChunk.CHUNK_DIMENSION * 1.0f);
|
||||||
cells = new HashSet<PhysicsDataCell>();
|
cells = new HashSet<PhysicsDataCell>();
|
||||||
invalid = new HashSet<String>();
|
invalid = new HashSet<String>();
|
||||||
updateable = new HashSet<String>();
|
updateable = new HashSet<String>();
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import java.nio.FloatBuffer;
|
|||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DeflaterOutputStream;
|
||||||
import java.util.zip.InflaterOutputStream;
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import electrosphere.engine.Globals;
|
|||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
|
import electrosphere.util.annotation.Exclude;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for accessing the disk map of chunk information
|
* An interface for accessing the disk map of chunk information
|
||||||
@ -23,6 +25,12 @@ public class ChunkDiskMap {
|
|||||||
//The map of world position+chunk type to the file that actually houses that information
|
//The map of world position+chunk type to the file that actually houses that information
|
||||||
Map<String,String> worldPosFileMap = new HashMap<String,String>();
|
Map<String,String> worldPosFileMap = new HashMap<String,String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the chunk disk map for thread safety
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
Semaphore lock = new Semaphore(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
@ -81,7 +89,10 @@ public class ChunkDiskMap {
|
|||||||
* @return True if the map contains the chunk, false otherwise
|
* @return True if the map contains the chunk, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean containsTerrainAtPosition(int worldX, int worldY, int worldZ){
|
public boolean containsTerrainAtPosition(int worldX, int worldY, int worldZ){
|
||||||
return worldPosFileMap.containsKey(getTerrainChunkKey(worldX, worldY, worldZ));
|
lock.acquireUninterruptibly();
|
||||||
|
boolean rVal = worldPosFileMap.containsKey(getTerrainChunkKey(worldX, worldY, worldZ));
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +103,10 @@ public class ChunkDiskMap {
|
|||||||
* @return True if the map contains the chunk, false otherwise
|
* @return True if the map contains the chunk, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){
|
public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){
|
||||||
return worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ));
|
lock.acquireUninterruptibly();
|
||||||
|
boolean rVal = worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ));
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,6 +117,7 @@ public class ChunkDiskMap {
|
|||||||
* @return The server terrain chunk if it exists, null otherwise
|
* @return The server terrain chunk if it exists, null otherwise
|
||||||
*/
|
*/
|
||||||
public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){
|
public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ);
|
LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ);
|
||||||
ServerTerrainChunk rVal = null;
|
ServerTerrainChunk rVal = null;
|
||||||
if(containsTerrainAtPosition(worldX, worldY, worldZ)){
|
if(containsTerrainAtPosition(worldX, worldY, worldZ)){
|
||||||
@ -148,6 +163,7 @@ public class ChunkDiskMap {
|
|||||||
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock.release();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +172,7 @@ public class ChunkDiskMap {
|
|||||||
* @param terrainChunk The terrain chunk
|
* @param terrainChunk The terrain chunk
|
||||||
*/
|
*/
|
||||||
public void saveToDisk(ServerTerrainChunk terrainChunk){
|
public void saveToDisk(ServerTerrainChunk terrainChunk){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
LoggerInterface.loggerEngine.DEBUG("Save to disk: " + terrainChunk.getWorldX() + " " + terrainChunk.getWorldY() + " " + terrainChunk.getWorldZ());
|
LoggerInterface.loggerEngine.DEBUG("Save to disk: " + terrainChunk.getWorldX() + " " + terrainChunk.getWorldY() + " " + terrainChunk.getWorldZ());
|
||||||
//get the file name for this chunk
|
//get the file name for this chunk
|
||||||
String fileName = null;
|
String fileName = null;
|
||||||
@ -202,6 +219,7 @@ public class ChunkDiskMap {
|
|||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import java.util.Arrays;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.game.data.biome.BiomeData;
|
import electrosphere.game.data.biome.BiomeData;
|
||||||
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
|
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
|
||||||
import electrosphere.game.server.world.ServerWorldData;
|
import electrosphere.game.server.world.ServerWorldData;
|
||||||
@ -65,6 +66,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ) {
|
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ) {
|
||||||
|
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator.generateChunk");
|
||||||
ServerTerrainChunk rVal = null;
|
ServerTerrainChunk rVal = null;
|
||||||
float[][][] weights;
|
float[][][] weights;
|
||||||
int[][][] values;
|
int[][][] values;
|
||||||
@ -95,19 +97,37 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
|||||||
values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||||
|
|
||||||
//biome of the current chunk
|
//biome of the current chunk
|
||||||
BiomeData biome = this.terrainModel.getSurfaceBiome(worldX, worldY, worldZ);
|
BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldY, worldZ);
|
||||||
|
|
||||||
|
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
||||||
|
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
||||||
|
if(heightmapGen == null){
|
||||||
|
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
//presolve heightfield
|
||||||
|
float[][] heightfield = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||||
|
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
||||||
|
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
|
||||||
|
heightfield[x][z] = heightmapGen.getHeight(this.terrainModel.getSeed(), this.serverWorldData.convertVoxelToRealSpace(x, worldX), this.serverWorldData.convertVoxelToRealSpace(z, worldZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
||||||
|
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||||
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
|
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
|
||||||
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
|
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
|
||||||
weights[x][y][z] = this.getChunkWeight(worldX, worldY, worldZ, x, y, z, this.terrainModel, biome);
|
GeneratedVoxel voxel = this.getVoxel(worldX, worldY, worldZ, x, y, z, heightfield, this.terrainModel, surfaceBiome);
|
||||||
values[x][y][z] = this.getChunkValue(worldX, worldY, worldZ, x, y, z, this.terrainModel, biome);
|
weights[x][y][z] = voxel.weight;
|
||||||
|
values[x][y][z] = voxel.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +136,6 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
|||||||
this.terrainModel = model;
|
this.terrainModel = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value for a chunk
|
* Gets the value for a chunk
|
||||||
* @param worldX The world x pos
|
* @param worldX The world x pos
|
||||||
@ -125,71 +144,133 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
|||||||
* @param chunkX The chunk x pos
|
* @param chunkX The chunk x pos
|
||||||
* @param chunkY The chunk y pos
|
* @param chunkY The chunk y pos
|
||||||
* @param chunkZ The chunk z pos
|
* @param chunkZ The chunk z pos
|
||||||
|
* @param heightfield The precomputed heightfield
|
||||||
* @param terrainModel The terrain model
|
* @param terrainModel The terrain model
|
||||||
* @param surfaceBiome The surface biome of the chunk
|
* @param surfaceBiome The surface biome of the chunk
|
||||||
* @return The value of the chunk
|
* @return The value of the chunk
|
||||||
*/
|
*/
|
||||||
private int getChunkValue(
|
private GeneratedVoxel getVoxel(
|
||||||
int worldX, int worldY, int worldZ,
|
int worldX, int worldY, int worldZ,
|
||||||
int chunkX, int chunkY, int chunkZ,
|
int chunkX, int chunkY, int chunkZ,
|
||||||
|
float[][] heightfield,
|
||||||
TerrainModel terrainModel,
|
TerrainModel terrainModel,
|
||||||
BiomeData surfaceBiome
|
BiomeData surfaceBiome
|
||||||
){
|
){
|
||||||
|
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator.getChunkValue");
|
||||||
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
||||||
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
||||||
if(heightmapGen == null){
|
if(heightmapGen == null){
|
||||||
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
double realX = this.serverWorldData.convertVoxelToRealSpace(chunkX,worldX);
|
double realX = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldX);
|
||||||
double realY = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldY);
|
double realY = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldY);
|
||||||
double realZ = this.serverWorldData.convertVoxelToRealSpace(chunkZ,worldZ);
|
double realZ = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldZ);
|
||||||
|
|
||||||
float surfaceHeight = heightmapGen.getHeight(terrainModel.getSeed(), realX, realZ);
|
float surfaceHeight = heightfield[chunkX][chunkZ];
|
||||||
if(realY <= surfaceHeight){
|
double flooredSurfaceHeight = Math.floor(surfaceHeight);
|
||||||
return 1;
|
Globals.profiler.endCpuSample();
|
||||||
|
if(realY < surfaceHeight - 1){
|
||||||
|
return getSubsurfaceVoxel(
|
||||||
|
worldX,worldY, worldZ,
|
||||||
|
chunkX, chunkY, chunkZ,
|
||||||
|
realX, realY, realZ,
|
||||||
|
surfaceHeight, flooredSurfaceHeight,
|
||||||
|
terrainModel,
|
||||||
|
surfaceBiome
|
||||||
|
);
|
||||||
|
} else if(realY > flooredSurfaceHeight) {
|
||||||
|
return getOverSurfaceVoxel(
|
||||||
|
worldX,worldY, worldZ,
|
||||||
|
chunkX, chunkY, chunkZ,
|
||||||
|
realX, realY, realZ,
|
||||||
|
surfaceHeight, flooredSurfaceHeight,
|
||||||
|
terrainModel,
|
||||||
|
surfaceBiome
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return getSurfaceVoxel(
|
||||||
|
worldX,worldY, worldZ,
|
||||||
|
chunkX, chunkY, chunkZ,
|
||||||
|
realX, realY, realZ,
|
||||||
|
surfaceHeight, flooredSurfaceHeight,
|
||||||
|
terrainModel,
|
||||||
|
surfaceBiome
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the weight for a chunk
|
* Gets the voxel on the surface
|
||||||
* @param worldX The world x pos
|
* @return The voxel
|
||||||
* @param worldY The world y pos
|
|
||||||
* @param worldZ The world z pos
|
|
||||||
* @param chunkX The chunk x pos
|
|
||||||
* @param chunkY The chunk y pos
|
|
||||||
* @param chunkZ The chunk z pos
|
|
||||||
* @param terrainModel The terrain model
|
|
||||||
* @param surfaceBiome The surface biome of the chunk
|
|
||||||
* @return The weight of the chunk
|
|
||||||
*/
|
*/
|
||||||
private float getChunkWeight(
|
private GeneratedVoxel getSurfaceVoxel(
|
||||||
int worldX, int worldY, int worldZ,
|
int worldX, int worldY, int worldZ,
|
||||||
int chunkX, int chunkY, int chunkZ,
|
int chunkX, int chunkY, int chunkZ,
|
||||||
|
double realX, double realY, double realZ,
|
||||||
|
float surfaceHeight, double flooredSurfaceHeight,
|
||||||
TerrainModel terrainModel,
|
TerrainModel terrainModel,
|
||||||
BiomeData surfaceBiome
|
BiomeData surfaceBiome
|
||||||
){
|
){
|
||||||
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
GeneratedVoxel voxel = new GeneratedVoxel();
|
||||||
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
voxel.weight = (float)(surfaceHeight - flooredSurfaceHeight) * 2 - 1;
|
||||||
if(heightmapGen == null){
|
voxel.type = 1;
|
||||||
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
return voxel;
|
||||||
}
|
}
|
||||||
|
|
||||||
double realX = this.serverWorldData.convertVoxelToRealSpace(chunkX,worldX);
|
/**
|
||||||
double realY = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldY);
|
* Gets the voxel below the surface
|
||||||
double realZ = this.serverWorldData.convertVoxelToRealSpace(chunkZ,worldZ);
|
* @return The voxel
|
||||||
|
*/
|
||||||
float surfaceHeight = heightmapGen.getHeight(terrainModel.getSeed(), realX, realZ);
|
private GeneratedVoxel getSubsurfaceVoxel(
|
||||||
double flooredSurfaceHeight = Math.floor(surfaceHeight);
|
int worldX, int worldY, int worldZ,
|
||||||
if(realY < flooredSurfaceHeight){
|
int chunkX, int chunkY, int chunkZ,
|
||||||
return 1;
|
double realX, double realY, double realZ,
|
||||||
} else if(realY > flooredSurfaceHeight) {
|
float surfaceHeight, double flooredSurfaceHeight,
|
||||||
return -1;
|
TerrainModel terrainModel,
|
||||||
|
BiomeData surfaceBiome
|
||||||
|
){
|
||||||
|
GeneratedVoxel voxel = new GeneratedVoxel();
|
||||||
|
if(realY < surfaceHeight - 5){
|
||||||
|
voxel.weight = 1;
|
||||||
|
voxel.type = 6;
|
||||||
} else {
|
} else {
|
||||||
return (float)(surfaceHeight - flooredSurfaceHeight) * 2 - 1;
|
voxel.weight = 1;
|
||||||
|
voxel.type = 1;
|
||||||
}
|
}
|
||||||
|
return voxel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the voxel above the service
|
||||||
|
* @return The voxel
|
||||||
|
*/
|
||||||
|
private GeneratedVoxel getOverSurfaceVoxel(
|
||||||
|
int worldX, int worldY, int worldZ,
|
||||||
|
int chunkX, int chunkY, int chunkZ,
|
||||||
|
double realX, double realY, double realZ,
|
||||||
|
float surfaceHeight, double flooredSurfaceHeight,
|
||||||
|
TerrainModel terrainModel,
|
||||||
|
BiomeData surfaceBiome
|
||||||
|
){
|
||||||
|
GeneratedVoxel voxel = new GeneratedVoxel();
|
||||||
|
voxel.weight = -1;
|
||||||
|
voxel.type = 0;
|
||||||
|
return voxel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A voxel that was generated
|
||||||
|
*/
|
||||||
|
static class GeneratedVoxel {
|
||||||
|
/**
|
||||||
|
* The type of the voxel
|
||||||
|
*/
|
||||||
|
int type;
|
||||||
|
/**
|
||||||
|
* The weight of the voxel
|
||||||
|
*/
|
||||||
|
float weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package electrosphere.server.terrain.generation.heightmap;
|
package electrosphere.server.terrain.generation.heightmap;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.util.noise.OpenSimplex2S;
|
import electrosphere.util.noise.OpenSimplex2S;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,9 +49,12 @@ public class HillsGen implements HeightmapGenerator {
|
|||||||
* @return The height
|
* @return The height
|
||||||
*/
|
*/
|
||||||
public float getHeight(long SEED, double x, double y){
|
public float getHeight(long SEED, double x, double y){
|
||||||
|
Globals.profiler.beginAggregateCpuSample("HillsGen.getHeight");
|
||||||
double scaledX = x * POSITION_SCALE;
|
double scaledX = x * POSITION_SCALE;
|
||||||
double scaledY = y * POSITION_SCALE;
|
double scaledY = y * POSITION_SCALE;
|
||||||
return gradientHeight(SEED, scaledX, scaledY) * VERTICAL_SCALE + HEIGHT_OFFSET;
|
float rVal = gradientHeight(SEED, scaledX, scaledY) * VERTICAL_SCALE + HEIGHT_OFFSET;
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,123 @@
|
|||||||
|
package electrosphere.server.terrain.manager;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.server.terrain.diskmap.ChunkDiskMap;
|
||||||
|
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A job that fetches a chunk, either by generating it or by reading it from disk
|
||||||
|
*/
|
||||||
|
public class ChunkGenerationThread implements Runnable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of milliseconds to wait per iteration
|
||||||
|
*/
|
||||||
|
static final int WAIT_TIME_MS = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of iterations to wait before failing
|
||||||
|
*/
|
||||||
|
static final int MAX_TIME_TO_WAIT = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chunk disk map
|
||||||
|
*/
|
||||||
|
ChunkDiskMap chunkDiskMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chunk cache on the server
|
||||||
|
*/
|
||||||
|
ServerChunkCache chunkCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chunk generator
|
||||||
|
*/
|
||||||
|
ChunkGenerator chunkGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The world x coordinate
|
||||||
|
*/
|
||||||
|
int worldX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The world y coordinate
|
||||||
|
*/
|
||||||
|
int worldY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The world z coordinate
|
||||||
|
*/
|
||||||
|
int worldZ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The work to do once the chunk is available
|
||||||
|
*/
|
||||||
|
Consumer<ServerTerrainChunk> onLoad;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the chunk generation job
|
||||||
|
* @param chunkDiskMap The chunk disk map
|
||||||
|
* @param chunkCache The chunk cache on the server
|
||||||
|
* @param chunkGenerator The chunk generator
|
||||||
|
* @param worldX The world x coordinate
|
||||||
|
* @param worldY The world y coordinate
|
||||||
|
* @param worldZ The world z coordinate
|
||||||
|
* @param onLoad The work to do once the chunk is available
|
||||||
|
*/
|
||||||
|
public ChunkGenerationThread(
|
||||||
|
ChunkDiskMap chunkDiskMap,
|
||||||
|
ServerChunkCache chunkCache,
|
||||||
|
ChunkGenerator chunkGenerator,
|
||||||
|
int worldX, int worldY, int worldZ,
|
||||||
|
Consumer<ServerTerrainChunk> onLoad
|
||||||
|
){
|
||||||
|
this.chunkDiskMap = chunkDiskMap;
|
||||||
|
this.chunkCache = chunkCache;
|
||||||
|
this.chunkGenerator = chunkGenerator;
|
||||||
|
this.worldX = worldX;
|
||||||
|
this.worldY = worldY;
|
||||||
|
this.worldZ = worldZ;
|
||||||
|
this.onLoad = onLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ServerTerrainChunk chunk = null;
|
||||||
|
int i = 0;
|
||||||
|
while(chunk == null && i < MAX_TIME_TO_WAIT && Globals.threadManager.shouldKeepRunning()){
|
||||||
|
if(chunkCache.containsChunk(worldX,worldY,worldZ)){
|
||||||
|
chunk = chunkCache.get(worldX,worldY,worldZ);
|
||||||
|
} else {
|
||||||
|
//pull from disk if it exists
|
||||||
|
if(chunkDiskMap != null){
|
||||||
|
if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ)){
|
||||||
|
chunk = chunkDiskMap.getTerrainChunk(worldX, worldY, worldZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//generate if it does not exist
|
||||||
|
if(chunk == null){
|
||||||
|
chunk = chunkGenerator.generateChunk(worldX, worldY, worldZ);
|
||||||
|
}
|
||||||
|
if(chunk != null){
|
||||||
|
chunkCache.add(worldX, worldY, worldZ, chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(chunk == null){
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(i >= MAX_TIME_TO_WAIT){
|
||||||
|
throw new Error("Failed to resolve chunk!");
|
||||||
|
}
|
||||||
|
this.onLoad.accept(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,166 @@
|
|||||||
|
package electrosphere.server.terrain.manager;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caches chunk data on the server
|
||||||
|
*/
|
||||||
|
public class ServerChunkCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of chunks to cache
|
||||||
|
*/
|
||||||
|
static final int CACHE_SIZE = 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the cache
|
||||||
|
*/
|
||||||
|
int cacheSize = CACHE_SIZE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cached data
|
||||||
|
*/
|
||||||
|
Map<String, ServerTerrainChunk> chunkCache = new HashMap<String,ServerTerrainChunk>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks how recently a chunk has been queries for (used for evicting old chunks from cache)
|
||||||
|
*/
|
||||||
|
List<String> queryRecencyQueue = new LinkedList<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks what chunks are already queued to be asynchronously loaded. Used so we don't have two threads generating/fetching the same chunk
|
||||||
|
*/
|
||||||
|
Map<String, Boolean> queuedChunkMap = new HashMap<String,Boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lock for thread safety
|
||||||
|
*/
|
||||||
|
Semaphore lock = new Semaphore(1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the collection of server terrain chunks that are cached
|
||||||
|
* @return The collection of chunks
|
||||||
|
*/
|
||||||
|
public Collection<ServerTerrainChunk> getContents(){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
Collection<ServerTerrainChunk> rVal = Collections.unmodifiableCollection(chunkCache.values());
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evicts all chunks in the cache
|
||||||
|
*/
|
||||||
|
public void clear(){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
chunkCache.clear();
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the chunk at a given world position
|
||||||
|
* @param worldX The world x coordinate
|
||||||
|
* @param worldY The world y coordinate
|
||||||
|
* @param worldZ The world z coordinate
|
||||||
|
* @return The chunk
|
||||||
|
*/
|
||||||
|
public ServerTerrainChunk get(int worldX, int worldY, int worldZ){
|
||||||
|
ServerTerrainChunk rVal = null;
|
||||||
|
String key = this.getKey(worldX, worldY, worldZ);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
queryRecencyQueue.remove(key);
|
||||||
|
queryRecencyQueue.add(0, key);
|
||||||
|
rVal = this.chunkCache.get(key);
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a chunk to the cache
|
||||||
|
* @param worldX The world x coordinate of the chunk
|
||||||
|
* @param worldY The world y coordinate of the chunk
|
||||||
|
* @param worldZ The world z coordinate of the chunk
|
||||||
|
* @param chunk The chunk itself
|
||||||
|
*/
|
||||||
|
public void add(int worldX, int worldY, int worldZ, ServerTerrainChunk chunk){
|
||||||
|
String key = this.getKey(worldX, worldY, worldZ);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
queryRecencyQueue.add(0, key);
|
||||||
|
this.chunkCache.put(key, chunk);
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the cache contains the chunk at a given world position
|
||||||
|
* @param worldX The world x coordinate
|
||||||
|
* @param worldY The world y coordinate
|
||||||
|
* @param worldZ The world z coordinate
|
||||||
|
* @return true if the cache contains this chunk, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean containsChunk(int worldX, int worldY, int worldZ){
|
||||||
|
String key = this.getKey(worldX,worldY,worldZ);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
boolean rVal = this.chunkCache.containsKey(key);
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the key for a given world position
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
public String getKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the chunk is already queued or not
|
||||||
|
* @param worldX The world x position of the chunk
|
||||||
|
* @param worldY The world y position of the chunk
|
||||||
|
* @param worldZ The world z position of the chunk
|
||||||
|
* @return true if the chunk is already queued, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean chunkIsQueued(int worldX, int worldY, int worldZ){
|
||||||
|
String key = this.getKey(worldX,worldY,worldZ);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
boolean rVal = this.queuedChunkMap.containsKey(key);
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags a chunk as queued
|
||||||
|
* @param worldX The world x position of the chunk
|
||||||
|
* @param worldY The world y position of the chunk
|
||||||
|
* @param worldZ The world z position of the chunk
|
||||||
|
*/
|
||||||
|
public void queueChunk(int worldX, int worldY, int worldZ){
|
||||||
|
String key = this.getKey(worldX,worldY,worldZ);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
this.queuedChunkMap.put(key,true);
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unflags a chunk as queued
|
||||||
|
* @param worldX The world x position of the chunk
|
||||||
|
* @param worldY The world y position of the chunk
|
||||||
|
* @param worldZ The world z position of the chunk
|
||||||
|
*/
|
||||||
|
public void unqueueChunk(int worldX, int worldY, int worldZ){
|
||||||
|
String key = this.getKey(worldX,worldY,worldZ);
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
|
this.queuedChunkMap.remove(key);
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package electrosphere.server.terrain.manager;
|
package electrosphere.server.terrain.manager;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.game.server.world.ServerWorldData;
|
import electrosphere.game.server.world.ServerWorldData;
|
||||||
import electrosphere.server.terrain.diskmap.ChunkDiskMap;
|
import electrosphere.server.terrain.diskmap.ChunkDiskMap;
|
||||||
import electrosphere.server.terrain.generation.TestGenerationChunkGenerator;
|
import electrosphere.server.terrain.generation.TestGenerationChunkGenerator;
|
||||||
@ -8,12 +9,13 @@ import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
|||||||
import electrosphere.server.terrain.models.TerrainModel;
|
import electrosphere.server.terrain.models.TerrainModel;
|
||||||
import electrosphere.server.terrain.models.TerrainModification;
|
import electrosphere.server.terrain.models.TerrainModification;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
|
import electrosphere.util.annotation.Exclude;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.util.List;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.Map;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.function.Consumer;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
@ -22,6 +24,11 @@ import org.joml.Vector3i;
|
|||||||
*/
|
*/
|
||||||
public class ServerTerrainManager {
|
public class ServerTerrainManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of threads for chunk generation
|
||||||
|
*/
|
||||||
|
public static final int GENERATION_THREAD_POOL_SIZE = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full world discrete size
|
* Full world discrete size
|
||||||
*/
|
*/
|
||||||
@ -51,21 +58,24 @@ public class ServerTerrainManager {
|
|||||||
//The model of the terrain this manager is managing
|
//The model of the terrain this manager is managing
|
||||||
TerrainModel model;
|
TerrainModel model;
|
||||||
|
|
||||||
|
/**
|
||||||
//In memory cache of chunk data
|
* The cache of chunks
|
||||||
//Basic idea is we associate string that contains chunk x&y&z with elevation
|
*/
|
||||||
//While we incur a penalty with converting ints -> string, think this will
|
@Exclude
|
||||||
//offset regenerating the array every time we want a new one
|
ServerChunkCache chunkCache = new ServerChunkCache();
|
||||||
int cacheSize = 500;
|
|
||||||
Map<String, ServerTerrainChunk> chunkCache;
|
|
||||||
List<String> chunkCacheContents;
|
|
||||||
|
|
||||||
//The map of chunk position <-> file on disk containing chunk data
|
//The map of chunk position <-> file on disk containing chunk data
|
||||||
ChunkDiskMap chunkDiskMap = null;
|
ChunkDiskMap chunkDiskMap = null;
|
||||||
|
|
||||||
//The generation algorithm for this terrain manager
|
//The generation algorithm for this terrain manager
|
||||||
|
@Exclude
|
||||||
ChunkGenerator chunkGenerator;
|
ChunkGenerator chunkGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The threadpool for chunk generation
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
ExecutorService chunkExecutorService = Executors.newFixedThreadPool(GENERATION_THREAD_POOL_SIZE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -76,8 +86,6 @@ public class ServerTerrainManager {
|
|||||||
ChunkGenerator chunkGenerator
|
ChunkGenerator chunkGenerator
|
||||||
){
|
){
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
|
|
||||||
this.chunkCacheContents = new CopyOnWriteArrayList<String>();
|
|
||||||
this.seed = seed;
|
this.seed = seed;
|
||||||
this.chunkGenerator = chunkGenerator;
|
this.chunkGenerator = chunkGenerator;
|
||||||
}
|
}
|
||||||
@ -118,8 +126,7 @@ public class ServerTerrainManager {
|
|||||||
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array());
|
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array());
|
||||||
}
|
}
|
||||||
//for each chunk, save via disk map
|
//for each chunk, save via disk map
|
||||||
for(String chunkKey : chunkCacheContents){
|
for(ServerTerrainChunk chunk : this.chunkCache.getContents()){
|
||||||
ServerTerrainChunk chunk = chunkCache.get(chunkKey);
|
|
||||||
chunkDiskMap.saveToDisk(chunk);
|
chunkDiskMap.saveToDisk(chunk);
|
||||||
}
|
}
|
||||||
//save disk map itself
|
//save disk map itself
|
||||||
@ -167,7 +174,6 @@ public class ServerTerrainManager {
|
|||||||
*/
|
*/
|
||||||
public void evictAll(){
|
public void evictAll(){
|
||||||
this.chunkCache.clear();
|
this.chunkCache.clear();
|
||||||
this.chunkCacheContents.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[][] getTerrainAtChunk(int x, int y){
|
public float[][] getTerrainAtChunk(int x, int y){
|
||||||
@ -215,37 +221,19 @@ public class ServerTerrainManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the key for a given world position
|
* Performs logic once a server chunk is available
|
||||||
* @param worldX The x component
|
|
||||||
* @param worldY The y component
|
|
||||||
* @param worldZ The z component
|
|
||||||
* @return The key
|
|
||||||
*/
|
|
||||||
public String getKey(int worldX, int worldY, int worldZ){
|
|
||||||
return worldX + "_" + worldY + "_" + worldZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a server terrain chunk
|
|
||||||
* @param worldX The world x position
|
* @param worldX The world x position
|
||||||
* @param worldY The world y position
|
* @param worldY The world y position
|
||||||
* @param worldZ The world z position
|
* @param worldZ The world z position
|
||||||
* @return The ServerTerrainChunk
|
* @return The ServerTerrainChunk
|
||||||
*/
|
*/
|
||||||
public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ){
|
public ServerTerrainChunk getChunk(int worldX, int worldY, int worldZ){
|
||||||
|
Globals.profiler.beginCpuSample("ServerTerrainManager.getChunk");
|
||||||
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
||||||
String key = getKey(worldX,worldY,worldZ);
|
|
||||||
ServerTerrainChunk returnedChunk = null;
|
ServerTerrainChunk returnedChunk = null;
|
||||||
if(chunkCache.containsKey(key)){
|
if(chunkCache.containsChunk(worldX,worldY,worldZ)){
|
||||||
chunkCacheContents.remove(key);
|
returnedChunk = chunkCache.get(worldX,worldY,worldZ);
|
||||||
chunkCacheContents.add(0, key);
|
|
||||||
returnedChunk = chunkCache.get(key);
|
|
||||||
return returnedChunk;
|
|
||||||
} else {
|
} else {
|
||||||
if(chunkCacheContents.size() >= cacheSize){
|
|
||||||
String oldChunk = chunkCacheContents.remove(chunkCacheContents.size() - 1);
|
|
||||||
chunkCache.remove(oldChunk);
|
|
||||||
}
|
|
||||||
//pull from disk if it exists
|
//pull from disk if it exists
|
||||||
if(chunkDiskMap != null){
|
if(chunkDiskMap != null){
|
||||||
if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ)){
|
if(chunkDiskMap.containsTerrainAtPosition(worldX, worldY, worldZ)){
|
||||||
@ -256,10 +244,23 @@ public class ServerTerrainManager {
|
|||||||
if(returnedChunk == null){
|
if(returnedChunk == null){
|
||||||
returnedChunk = chunkGenerator.generateChunk(worldX, worldY, worldZ);
|
returnedChunk = chunkGenerator.generateChunk(worldX, worldY, worldZ);
|
||||||
}
|
}
|
||||||
chunkCache.put(key, returnedChunk);
|
this.chunkCache.add(worldX, worldY, worldZ, returnedChunk);
|
||||||
chunkCacheContents.add(key);
|
|
||||||
return returnedChunk;
|
|
||||||
}
|
}
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
|
return returnedChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs logic once a server chunk is available
|
||||||
|
* @param worldX The world x position
|
||||||
|
* @param worldY The world y position
|
||||||
|
* @param worldZ The world z position
|
||||||
|
* @param onLoad The logic to run once the chunk is available
|
||||||
|
*/
|
||||||
|
public void getChunkAsync(int worldX, int worldY, int worldZ, Consumer<ServerTerrainChunk> onLoad){
|
||||||
|
Globals.profiler.beginCpuSample("ServerTerrainManager.getChunkAsync");
|
||||||
|
this.chunkExecutorService.submit(new ChunkGenerationThread(chunkDiskMap, chunkCache, chunkGenerator, worldX, worldY, worldZ, onLoad));
|
||||||
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -286,9 +287,8 @@ public class ServerTerrainManager {
|
|||||||
if(model != null){
|
if(model != null){
|
||||||
model.addModification(modification);
|
model.addModification(modification);
|
||||||
}
|
}
|
||||||
String key = getKey(worldPos.x,worldPos.y,worldPos.z);
|
if(chunkCache.containsChunk(worldPos.x,worldPos.y,worldPos.z)){
|
||||||
if(chunkCache.containsKey(key)){
|
ServerTerrainChunk chunk = chunkCache.get(worldPos.x,worldPos.y,worldPos.z);
|
||||||
ServerTerrainChunk chunk = chunkCache.get(key);
|
|
||||||
chunk.addModification(modification);
|
chunk.addModification(modification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,4 +309,11 @@ public class ServerTerrainManager {
|
|||||||
return chunkGenerator;
|
return chunkGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the generation threadpool
|
||||||
|
*/
|
||||||
|
public void closeThreads(){
|
||||||
|
this.chunkExecutorService.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
435
src/main/java/electrosphere/util/ds/octree/WorldOctTree.java
Normal file
435
src/main/java/electrosphere/util/ds/octree/WorldOctTree.java
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
package electrosphere.util.ds.octree;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import io.github.studiorailgun.MathUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A power of two oct tree that supports arbitrary world size (not fixed)
|
||||||
|
*/
|
||||||
|
public class WorldOctTree <T> {
|
||||||
|
/**
|
||||||
|
* The maximum level of the chunk tree
|
||||||
|
*/
|
||||||
|
int maxLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root node
|
||||||
|
*/
|
||||||
|
private FloatingChunkTreeNode<T> root = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of all nodes in the tree
|
||||||
|
*/
|
||||||
|
List<FloatingChunkTreeNode<T>> nodes = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum position
|
||||||
|
*/
|
||||||
|
Vector3i min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum position
|
||||||
|
*/
|
||||||
|
Vector3i max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param min The minimum position of the world
|
||||||
|
* @param max The maximum position of the world
|
||||||
|
*/
|
||||||
|
public WorldOctTree(Vector3i min, Vector3i max){
|
||||||
|
//check that dimensions are a multiple of 2
|
||||||
|
if(
|
||||||
|
((max.x - min.x) & (max.x - min.x - 1)) != 0 ||
|
||||||
|
((max.y - min.y) & (max.y - min.y - 1)) != 0 ||
|
||||||
|
((max.z - min.z) & (max.z - min.z - 1)) != 0
|
||||||
|
){
|
||||||
|
throw new Error("Invalid dimensions! Must be a power of two! " + min + " " + max);
|
||||||
|
}
|
||||||
|
if(max.x - min.x != max.y - min.y || max.x - min.x != max.z - min.z){
|
||||||
|
throw new Error("Invalid dimensions! Must be the same size along all three axis! " + min + " " + max);
|
||||||
|
}
|
||||||
|
this.min = new Vector3i(min);
|
||||||
|
this.max = new Vector3i(max);
|
||||||
|
//calculate max level
|
||||||
|
int dimRaw = max.x - min.x;
|
||||||
|
this.maxLevel = (int)MathUtils.log2(dimRaw);
|
||||||
|
this.nodes = new ArrayList<FloatingChunkTreeNode<T>>();
|
||||||
|
this.root = new FloatingChunkTreeNode<T>(this, 0, new Vector3i(min), new Vector3i(max));
|
||||||
|
this.root.isLeaf = true;
|
||||||
|
this.nodes.add(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits a parent into child nodes
|
||||||
|
* @param parent The parent
|
||||||
|
* @return The new non-leaf node
|
||||||
|
*/
|
||||||
|
public FloatingChunkTreeNode<T> split(FloatingChunkTreeNode<T> existing){
|
||||||
|
if(!existing.isLeaf()){
|
||||||
|
throw new IllegalArgumentException("Tried to split non-leaf!");
|
||||||
|
}
|
||||||
|
Vector3i min = existing.getMinBound();
|
||||||
|
Vector3i max = existing.getMaxBound();
|
||||||
|
int midX = (max.x - min.x) / 2 + min.x;
|
||||||
|
int midY = (max.y - min.y) / 2 + min.y;
|
||||||
|
int midZ = (max.z - min.z) / 2 + min.z;
|
||||||
|
int currentLevel = existing.getLevel();
|
||||||
|
FloatingChunkTreeNode<T> newContainer = new FloatingChunkTreeNode<>(this, currentLevel, min, max);
|
||||||
|
//add children
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,min.y,min.z), new Vector3i(midX,midY,midZ)));
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,min.y,min.z), new Vector3i(max.x,midY,midZ)));
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,midY,min.z), new Vector3i(midX,max.y,midZ)));
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,midY,min.z), new Vector3i(max.x,max.y,midZ)));
|
||||||
|
//
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,min.y,midZ), new Vector3i(midX,midY,max.z)));
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,min.y,midZ), new Vector3i(max.x,midY,max.z)));
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(min.x,midY,midZ), new Vector3i(midX,max.y,max.z)));
|
||||||
|
newContainer.addChild(new FloatingChunkTreeNode<T>(this, currentLevel + 1, new Vector3i(midX,midY,midZ), new Vector3i(max.x,max.y,max.z)));
|
||||||
|
|
||||||
|
boolean foundMin = false;
|
||||||
|
for(FloatingChunkTreeNode<T> child : newContainer.getChildren()){
|
||||||
|
if(child.getMinBound().distance(newContainer.getMinBound()) == 0){
|
||||||
|
foundMin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!foundMin){
|
||||||
|
String message = "Failed to sanity check!\n";
|
||||||
|
message = message + min + " " + max + "\n";
|
||||||
|
message = message + midX + " " + midY + " " + midZ + "\n";
|
||||||
|
message = message + "container mid: " + newContainer.getMinBound();
|
||||||
|
for(FloatingChunkTreeNode<T> child : newContainer.getChildren()){
|
||||||
|
message = message + "child min: " + child.getMinBound() + "\n";
|
||||||
|
}
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
//replace existing node
|
||||||
|
replaceNode(existing,newContainer);
|
||||||
|
|
||||||
|
//update tracking
|
||||||
|
this.nodes.remove(existing);
|
||||||
|
this.nodes.add(newContainer);
|
||||||
|
this.nodes.addAll(newContainer.getChildren());
|
||||||
|
|
||||||
|
return newContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins a non-leaf node's children into a single node
|
||||||
|
* @param parent The non-leaf
|
||||||
|
* @return The new leaf node
|
||||||
|
*/
|
||||||
|
public FloatingChunkTreeNode<T> join(FloatingChunkTreeNode<T> existing){
|
||||||
|
if(existing.isLeaf()){
|
||||||
|
throw new IllegalArgumentException("Tried to split non-leaf!");
|
||||||
|
}
|
||||||
|
Vector3i min = existing.getMinBound();
|
||||||
|
Vector3i max = existing.getMaxBound();
|
||||||
|
int currentLevel = existing.getLevel();
|
||||||
|
FloatingChunkTreeNode<T> newContainer = new FloatingChunkTreeNode<>(this, currentLevel, min, max);
|
||||||
|
|
||||||
|
//replace existing node
|
||||||
|
replaceNode(existing,newContainer);
|
||||||
|
|
||||||
|
//update tracking
|
||||||
|
this.nodes.remove(existing);
|
||||||
|
this.nodes.removeAll(existing.getChildren());
|
||||||
|
this.nodes.add(newContainer);
|
||||||
|
|
||||||
|
return newContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces an existing node with a new node
|
||||||
|
* @param existing the existing node
|
||||||
|
* @param newNode the new node
|
||||||
|
*/
|
||||||
|
private void replaceNode(FloatingChunkTreeNode<T> existing, FloatingChunkTreeNode<T> newNode){
|
||||||
|
if(existing == this.root){
|
||||||
|
this.root = newNode;
|
||||||
|
} else {
|
||||||
|
FloatingChunkTreeNode<T> parent = existing.getParent();
|
||||||
|
parent.removeChild(existing);
|
||||||
|
parent.addChild(newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the root node of the tree
|
||||||
|
*/
|
||||||
|
public FloatingChunkTreeNode<T> getRoot() {
|
||||||
|
return this.root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the max level of the tree
|
||||||
|
* @param maxLevel The max level
|
||||||
|
*/
|
||||||
|
public void setMaxLevel(int maxLevel){
|
||||||
|
this.maxLevel = maxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the max level allowed for the tree
|
||||||
|
* @return The max level
|
||||||
|
*/
|
||||||
|
public int getMaxLevel(){
|
||||||
|
return maxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the tree
|
||||||
|
*/
|
||||||
|
public void clear(){
|
||||||
|
this.nodes.clear();
|
||||||
|
this.root = new FloatingChunkTreeNode<T>(this, 0, new Vector3i(min), new Vector3i(max));
|
||||||
|
this.root.isLeaf = true;
|
||||||
|
this.nodes.add(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the node at a given position
|
||||||
|
* @param position The position
|
||||||
|
* @param returnNonLeaf If true, the function can return non-leaf nodes, otherwise will only return leaf nodes
|
||||||
|
* @return The leaf if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public FloatingChunkTreeNode<T> search(Vector3i position, boolean returnNonLeaf){
|
||||||
|
return this.search(position,returnNonLeaf,this.maxLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the node at a given position
|
||||||
|
* @param position The position
|
||||||
|
* @param returnNonLeaf If true, the function can return non-leaf nodes, otherwise will only return leaf nodes
|
||||||
|
* @param maxLevel The maximum level to search for
|
||||||
|
* @return The leaf if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public FloatingChunkTreeNode<T> search(Vector3i position, boolean returnNonLeaf, int maxLevel){
|
||||||
|
//out of bounds check
|
||||||
|
if(
|
||||||
|
position.x < min.x || position.x > max.x ||
|
||||||
|
position.y < min.y || position.y > max.y ||
|
||||||
|
position.z < min.z || position.z > max.z
|
||||||
|
){
|
||||||
|
throw new Error("Trying to search for node outside tree range!");
|
||||||
|
}
|
||||||
|
FloatingChunkTreeNode<T> searchResult = recursiveSearchUnsafe(root,position,maxLevel);
|
||||||
|
if(!returnNonLeaf && !searchResult.isLeaf()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return searchResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively searches for the node at the position. Unsafe because it does not bounds check.
|
||||||
|
* @param currentNode The current node searching from
|
||||||
|
* @param position The position to search at
|
||||||
|
* @param maxLevel The maximum level to search for
|
||||||
|
* @return The found node
|
||||||
|
*/
|
||||||
|
private FloatingChunkTreeNode<T> recursiveSearchUnsafe(FloatingChunkTreeNode<T> currentNode, Vector3i position, int maxLevel){
|
||||||
|
if(maxLevel < 0){
|
||||||
|
throw new Error("Provided invalid max level! Must be created than 0! " + maxLevel);
|
||||||
|
}
|
||||||
|
if(currentNode.level > maxLevel){
|
||||||
|
throw new Error("Failed to stop before max level!");
|
||||||
|
}
|
||||||
|
if(currentNode.level == maxLevel){
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
if(currentNode.getChildren().size() > 0){
|
||||||
|
for(FloatingChunkTreeNode<T> child : currentNode.getChildren()){
|
||||||
|
if(
|
||||||
|
position.x < child.getMaxBound().x && position.x >= child.getMinBound().x &&
|
||||||
|
position.y < child.getMaxBound().y && position.y >= child.getMinBound().y &&
|
||||||
|
position.z < child.getMaxBound().z && position.z >= child.getMinBound().z
|
||||||
|
){
|
||||||
|
return recursiveSearchUnsafe(child, position, maxLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String message = "Current node is within range, but no children are! This does not make any sense.\n";
|
||||||
|
|
||||||
|
message = message + " current pos: " + currentNode.getMinBound() + " " + currentNode.getMaxBound() + "\n";
|
||||||
|
for(FloatingChunkTreeNode<T> child : currentNode.getChildren()){
|
||||||
|
message = message + " child " + child + " pos: " + child.getMinBound() + " " + child.getMaxBound() + "\n";
|
||||||
|
}
|
||||||
|
message = message + "position to search: " + position + "\n";
|
||||||
|
throw new Error(message);
|
||||||
|
} else {
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node in a chunk tree
|
||||||
|
*/
|
||||||
|
public static class FloatingChunkTreeNode<T> {
|
||||||
|
|
||||||
|
//True if this is a leaf node, false otherwise
|
||||||
|
private boolean isLeaf;
|
||||||
|
|
||||||
|
//the parent node
|
||||||
|
private FloatingChunkTreeNode<T> parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tree containing this node
|
||||||
|
*/
|
||||||
|
private WorldOctTree<T> containingTree;
|
||||||
|
|
||||||
|
//the children of this node
|
||||||
|
private List<FloatingChunkTreeNode<T>> children = new LinkedList<FloatingChunkTreeNode<T>>();
|
||||||
|
|
||||||
|
//The data at the node
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The min bound
|
||||||
|
*/
|
||||||
|
private Vector3i min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The max bound.
|
||||||
|
* !!NOTE!! max is exclusive, not inclusive
|
||||||
|
*/
|
||||||
|
private Vector3i max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level of the chunk tree node
|
||||||
|
*/
|
||||||
|
int level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for non-leaf node
|
||||||
|
* @param tree The parent tree
|
||||||
|
* @param level The level of the node
|
||||||
|
* @param min The minimum position of the node
|
||||||
|
* @param max The maximum position of then ode
|
||||||
|
*/
|
||||||
|
private FloatingChunkTreeNode(WorldOctTree<T> tree, int level, Vector3i min, Vector3i max){
|
||||||
|
if(tree == null){
|
||||||
|
throw new Error("Invalid tree provided " + tree);
|
||||||
|
}
|
||||||
|
int maxPos = (int)Math.pow(2,tree.getMaxLevel());
|
||||||
|
if(min.x == maxPos || min.y == maxPos || min.z == maxPos){
|
||||||
|
throw new IllegalArgumentException("Invalid minimum! " + min);
|
||||||
|
}
|
||||||
|
if(level < 0 || level > tree.getMaxLevel()){
|
||||||
|
throw new IllegalArgumentException("Invalid level! " + level);
|
||||||
|
}
|
||||||
|
this.containingTree = tree;
|
||||||
|
this.isLeaf = false;
|
||||||
|
this.level = level;
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for use in tests
|
||||||
|
* @param tree The Tree
|
||||||
|
* @param level The level
|
||||||
|
* @param min The min point
|
||||||
|
* @param max The max point
|
||||||
|
* @return The node
|
||||||
|
*/
|
||||||
|
public static <T> FloatingChunkTreeNode<T> constructorForTests(WorldOctTree<T> tree, int level, Vector3i min, Vector3i max){
|
||||||
|
return new FloatingChunkTreeNode<T>(tree, level, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this node to a leaf
|
||||||
|
* @param data The data to put in the leaf
|
||||||
|
*/
|
||||||
|
public void convertToLeaf(T data){
|
||||||
|
this.isLeaf = true;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data associated with this node
|
||||||
|
*/
|
||||||
|
public T getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent of this node
|
||||||
|
*/
|
||||||
|
public FloatingChunkTreeNode<T> getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the children of this node
|
||||||
|
*/
|
||||||
|
public List<FloatingChunkTreeNode<T>> getChildren() {
|
||||||
|
return Collections.unmodifiableList(this.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this node is a leaf
|
||||||
|
* @return true if it is a leaf, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return isLeaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the node can split
|
||||||
|
* @return true if can split, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean canSplit(){
|
||||||
|
return isLeaf && level < containingTree.getMaxLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the level of the node
|
||||||
|
* @return The level of the node
|
||||||
|
*/
|
||||||
|
public int getLevel(){
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the min bound of this node
|
||||||
|
* @return The min bound
|
||||||
|
*/
|
||||||
|
public Vector3i getMinBound(){
|
||||||
|
return new Vector3i(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the max bound of this node
|
||||||
|
* @return The max bound
|
||||||
|
*/
|
||||||
|
public Vector3i getMaxBound(){
|
||||||
|
return new Vector3i(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a child to this node
|
||||||
|
* @param child The child
|
||||||
|
*/
|
||||||
|
private void addChild(FloatingChunkTreeNode<T> child){
|
||||||
|
this.children.add(child);
|
||||||
|
child.parent = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a child node
|
||||||
|
* @param child the child
|
||||||
|
*/
|
||||||
|
private void removeChild(FloatingChunkTreeNode<T> child){
|
||||||
|
this.children.remove(child);
|
||||||
|
child.parent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package electrosphere.client.terrain.cells;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.engine.Main;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.test.annotations.UnitTest;
|
||||||
|
import electrosphere.test.template.extensions.StateCleanupCheckerExtension;
|
||||||
|
import electrosphere.util.ds.octree.WorldOctTree.FloatingChunkTreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the client draw cell manager
|
||||||
|
*/
|
||||||
|
@ExtendWith(StateCleanupCheckerExtension.class)
|
||||||
|
public class ClientDrawCellManagerTests {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test creating a manager
|
||||||
|
*/
|
||||||
|
@UnitTest
|
||||||
|
public void testCreation(){
|
||||||
|
assertDoesNotThrow(() -> {
|
||||||
|
new ClientDrawCellManager(null, 64);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void testJoinCase(){
|
||||||
|
|
||||||
|
int worldDiscreteSize = 64;
|
||||||
|
Globals.clientWorldData = new ClientWorldData(new Vector3f(0), new Vector3f(worldDiscreteSize * ServerTerrainChunk.CHUNK_DIMENSION), 0, worldDiscreteSize);
|
||||||
|
ClientDrawCellManager manager = new ClientDrawCellManager(null, 64);
|
||||||
|
Vector3d playerPos = new Vector3d(0,0,0);
|
||||||
|
FloatingChunkTreeNode<DrawCell> node = FloatingChunkTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));
|
||||||
|
node.convertToLeaf(DrawCell.generateTerrainCell(new Vector3i(0,0,0)));
|
||||||
|
|
||||||
|
assertFalse(manager.shouldSplit(playerPos, node));
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
Main.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -30,6 +30,7 @@ public class StateCleanupCheckerExtension implements AfterEachCallback {
|
|||||||
Globals.playerManager,
|
Globals.playerManager,
|
||||||
LoggerInterface.loggerEngine,
|
LoggerInterface.loggerEngine,
|
||||||
RenderingEngine.screenFramebuffer,
|
RenderingEngine.screenFramebuffer,
|
||||||
|
Globals.clientWorldData,
|
||||||
};
|
};
|
||||||
for(Object object : objectsToCheck){
|
for(Object object : objectsToCheck){
|
||||||
if(object != null){
|
if(object != null){
|
||||||
|
|||||||
@ -2,9 +2,20 @@ package electrosphere.util.ds.octree;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import electrosphere.test.annotations.UnitTest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit testing for the chunk octree implementation
|
* Unit testing for the chunk octree implementation
|
||||||
*/
|
*/
|
||||||
public class ChunkTreeTests {
|
public class ChunkTreeTests {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a chunk tree
|
||||||
|
*/
|
||||||
|
@UnitTest
|
||||||
|
public void testCreateChunkTree(){
|
||||||
|
ChunkTree<String> tree = new ChunkTree<String>();
|
||||||
|
assertNotNull(tree);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,54 @@
|
|||||||
|
package electrosphere.util.ds.octree;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.test.annotations.UnitTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the floating position chunk tree implementation
|
||||||
|
*/
|
||||||
|
public class WorldOctTreeTests {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a chunk tree
|
||||||
|
*/
|
||||||
|
@UnitTest
|
||||||
|
public void testCreateFloatingChunkTree(){
|
||||||
|
WorldOctTree<String> tree = new WorldOctTree<String>(new Vector3i(0,0,0), new Vector3i(64,64,64));
|
||||||
|
assertNotNull(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test changing the centered point of the floating tree
|
||||||
|
*/
|
||||||
|
@UnitTest
|
||||||
|
public void testMaxLevelSetting(){
|
||||||
|
WorldOctTree<String> tree = new WorldOctTree<String>(new Vector3i(0,0,0), new Vector3i(64,64,64));
|
||||||
|
assertEquals(6,tree.getMaxLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert non-power-of-two dims fail
|
||||||
|
*/
|
||||||
|
@UnitTest
|
||||||
|
public void testFailOnNonPowTwoDim(){
|
||||||
|
assertThrows(Error.class, () -> {
|
||||||
|
new WorldOctTree<String>(new Vector3i(0,0,0), new Vector3i(63,63,63));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert unequal dims fail
|
||||||
|
*/
|
||||||
|
@UnitTest
|
||||||
|
public void testFailOnUnequalDim(){
|
||||||
|
assertThrows(Error.class, () -> {
|
||||||
|
new WorldOctTree<String>(new Vector3i(0,0,0), new Vector3i(64,1,64));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -10,7 +10,6 @@
|
|||||||
"./net/lore.json",
|
"./net/lore.json",
|
||||||
"./net/player.json",
|
"./net/player.json",
|
||||||
"./net/terrain.json",
|
"./net/terrain.json",
|
||||||
"./net/world.json",
|
|
||||||
"./net/server.json",
|
"./net/server.json",
|
||||||
"./net/character.json",
|
"./net/character.json",
|
||||||
"./net/inventory.json",
|
"./net/inventory.json",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user