netparser message pooling + multithread chunk io
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-03-29 16:08:37 -04:00
parent deea49ba64
commit c7dc9ef07d
24 changed files with 665 additions and 221 deletions

View File

@ -0,0 +1,26 @@
@page optimizationideas Optimization Ideas
Automatically transition between instanced actors and non-instanced actors for non-animated models
- Need to keep track of number of entities drawing a model, once that total passes a threshold convert them all to instanced actors
- name it something fun like "HybridActor" or "ShapeshiftActor"
Merge all kinematic bodies in a scene into one
- Need to keep track of individual entities' shapes after the merge
- When an individual entity dies, remove its shape from the main body
Second frustum full on shadow map pipeline
- only draw what is both in front of camera AND visible from sky (currently ignores sky's view)
Move hitbox position updates to behavior tree
- If an entity is not moving (ie a tree), don't have to update the hitbox's position
On client, only colide hitboxes closest to the player
- Currently collide all hitboxes and it's costly
Simplify collidable logic
- IE trees don't need to worry about gravity
In GriddedDataCellManager, skip ServerDataCells if they aren't doing anything interesting
In GriddedDataCellManager, run unload logic at the same time we're iterating through all cells to simulate the

View File

@ -5,3 +5,4 @@
- @subpage toolsindex
- @subpage highleveldesignindex
- @subpage progress
- @subpage optimizationideas

View File

@ -1375,6 +1375,14 @@ Disable kinematic colliders on creation
MainContentPipeline reduce allocations
Move AI simulation to server level from chunk level
(03/29/2025)
Optimize ray casting near callback
Chunk file operation threadsafing
Multithread entity creation on server cell creation
Network message object pooling
Threadsafe EntityDataCellMapper
Code cleanup
Small ServerAttackTree fix (for when not holding an item)

View File

@ -10,21 +10,35 @@ import electrosphere.renderer.texture.Texture;
*/
public class VoxelTextureAtlas {
//A map of voxel id -> coordinates in the atlas texture for its texture
/**
* A map of voxel id -> coordinates in the atlas texture for its texture
*/
Map<Integer,Integer> typeCoordMap = new HashMap<Integer,Integer>();
//the actual texture
/**
* The actual texture
*/
Texture specular;
//the normal texture
/**
* The normal texture
*/
Texture normal;
//the width in pixels of a single texture in the atlas
/**
* The width in pixels of a single texture in the atlas
*/
public static final int ATLAS_ELEMENT_DIM = 256;
//the width in pixels of the whole atlas texture
/**
* The width in pixels of the whole atlas texture
*/
public static final int ATLAS_DIM = 8192;
//number of textures per row in the atlas
/**
* Number of textures per row in the atlas
*/
public static final int ELEMENTS_PER_ROW = ATLAS_DIM / ATLAS_ELEMENT_DIM;
/**

View File

@ -1,8 +1,5 @@
package electrosphere.collision;
import static org.ode4j.ode.OdeConstants.dContactBounce;
import static org.ode4j.ode.OdeConstants.dContactSoftCFM;
import static org.ode4j.ode.OdeConstants.dInfinity;
import static org.ode4j.ode.OdeHelper.areConnectedExcluding;
import java.util.List;
@ -28,7 +25,7 @@ public class RayCastCallback implements DNearCallback {
/**
* Maximum number of contacts allowed
*/
static final int MAX_CONTACTS = 5;
static final int MAX_CONTACTS = 2;
/**
* Really far away from the ray origin point
@ -63,6 +60,7 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
public void call(Object data, DGeom o1, DGeom o2) {
// if (o1->body && o2->body) return;
RayCastCallbackData rayCastData = (RayCastCallbackData)data;
//null out potentially previous results
// rayCastData.collisionPosition = null;
// rayCastData.collidedEntity = null;
@ -71,33 +69,25 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
DBody b2 = o2.getBody();
if (b1!=null && b2!=null && areConnectedExcluding (b1,b2,DContactJoint.class)) return;
//creates a buffer to store potential collisions
DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); // up to MAX_CONTACTS contacts per box-box
for (int i=0; i<MAX_CONTACTS; i++) {
DContact contact = contacts.get(i);
contact.surface.mode = dContactBounce | dContactSoftCFM;
contact.surface.mu = dInfinity;
contact.surface.mu2 = 0;
contact.surface.bounce = 0.1;
contact.surface.bounce_vel = 0.1;
contact.surface.soft_cfm = 0.01;
}
Collidable collidable1 = rayCastData.bodyEntityMap.get(b1);
Collidable collidable2 = rayCastData.bodyEntityMap.get(b2);
//don't self cast -- should work on both server and client
if(collidable1 != null && collidable1.getParent() == Globals.playerEntity){
return;
}
if(collidable2 != null && collidable2.getParent() == Globals.playerEntity){
return;
}
Globals.profiler.beginAggregateCpuSample("RayCastCallback - try collisions");
if(
(
rayCastData.collidableTypeMask == null ||
(
rayCastData.collidableTypeMask != null &&
(
(o1 instanceof DRay && rayCastData.collidableTypeMask.contains(collidable2.getType())) ||
(o2 instanceof DRay && rayCastData.collidableTypeMask.contains(collidable1.getType()))
)
)
) &&
(collidable1 == null || collidable1 != null && collidable1.getParent() != Globals.playerEntity) && //don't self cast -- should work on both server and client
(collidable2 == null || collidable2 != null && collidable2.getParent() != Globals.playerEntity) //don't self cast -- should work on both server and client
rayCastData.collidableTypeMask == null ||
(o1 instanceof DRay && rayCastData.collidableTypeMask.contains(collidable2.getType())) ||
(o2 instanceof DRay && rayCastData.collidableTypeMask.contains(collidable1.getType()))
){
//creates a buffer to store potential collisions
DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); // up to MAX_CONTACTS contacts per box-box
//calculate collisions
int numc = OdeHelper.collide(o1,o2,MAX_CONTACTS,contacts.getGeomBuffer());
//create DContacts based on each collision that occurs
@ -132,6 +122,7 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
}
}
}
Globals.profiler.endCpuSample();
}
/**

View File

@ -479,6 +479,9 @@ public class ServerAttackTree implements BehaviorTree {
if(ServerToolbarState.getServerToolbarState(parent) != null){
ServerToolbarState serverToolbarState = ServerToolbarState.getServerToolbarState(parent);
Entity item = serverToolbarState.getRealWorldItem();
if(item == null){
return EntityDataStrings.ATTACK_MOVE_UNARMED;
}
if(ItemUtils.isWeapon(item)){
currentWeapon = item;
switch(ItemUtils.getWeaponClass(item)){

View File

@ -28,11 +28,18 @@ public class AuthMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
AuthMessage(AuthMessageType messageType){
private AuthMessage(AuthMessageType messageType){
this.type = MessageType.AUTH_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected AuthMessage(){
this.type = MessageType.AUTH_MESSAGE;
}
public AuthMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -31,11 +31,18 @@ public class CharacterMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
CharacterMessage(CharacterMessageType messageType){
private CharacterMessage(CharacterMessageType messageType){
this.type = MessageType.CHARACTER_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected CharacterMessage(){
this.type = MessageType.CHARACTER_MESSAGE;
}
public CharacterMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -35,11 +35,18 @@ public class CombatMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
CombatMessage(CombatMessageType messageType){
private CombatMessage(CombatMessageType messageType){
this.type = MessageType.COMBAT_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected CombatMessage(){
this.type = MessageType.COMBAT_MESSAGE;
}
public CombatMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -66,11 +66,18 @@ public class EntityMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
EntityMessage(EntityMessageType messageType){
private EntityMessage(EntityMessageType messageType){
this.type = MessageType.ENTITY_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected EntityMessage(){
this.type = MessageType.ENTITY_MESSAGE;
}
public EntityMessageType getMessageSubtype(){
return this.messageType;
}
@ -688,8 +695,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type Create
*/
public static EntityMessage parseCreateMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.CREATE);
public static EntityMessage parseCreateMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.CREATE;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setentityCategory(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -728,8 +736,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type moveUpdate
*/
public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.MOVEUPDATE;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
@ -770,8 +779,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type attackUpdate
*/
public static EntityMessage parseattackUpdateMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACKUPDATE);
public static EntityMessage parseattackUpdateMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.ATTACKUPDATE;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
@ -808,8 +818,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type startAttack
*/
public static EntityMessage parsestartAttackMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.STARTATTACK);
public static EntityMessage parsestartAttackMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.STARTATTACK;
stripPacketHeader(byteBuffer);
return rVal;
}
@ -826,8 +837,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type Kill
*/
public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.KILL);
public static EntityMessage parseKillMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.KILL;
stripPacketHeader(byteBuffer);
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -848,8 +860,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type Destroy
*/
public static EntityMessage parseDestroyMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.DESTROY);
public static EntityMessage parseDestroyMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.DESTROY;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
@ -868,8 +881,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type setProperty
*/
public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPROPERTY);
public static EntityMessage parsesetPropertyMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.SETPROPERTY;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
@ -922,8 +936,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type attachEntityToEntity
*/
public static EntityMessage parseattachEntityToEntityMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.ATTACHENTITYTOENTITY);
public static EntityMessage parseattachEntityToEntityMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.ATTACHENTITYTOENTITY;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setbone(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
@ -946,8 +961,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type updateEntityViewDir
*/
public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.UPDATEENTITYVIEWDIR;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
@ -974,8 +990,9 @@ public class EntityMessage extends NetworkMessage {
/**
* Parses a message of type syncPhysics
*/
public static EntityMessage parsesyncPhysicsMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
public static EntityMessage parsesyncPhysicsMessage(CircularByteBuffer byteBuffer, MessagePool pool){
EntityMessage rVal = (EntityMessage)pool.get(MessageType.ENTITY_MESSAGE);
rVal.messageType = EntityMessageType.SYNCPHYSICS;
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));

View File

@ -47,11 +47,18 @@ public class InventoryMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
InventoryMessage(InventoryMessageType messageType){
private InventoryMessage(InventoryMessageType messageType){
this.type = MessageType.INVENTORY_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected InventoryMessage(){
this.type = MessageType.INVENTORY_MESSAGE;
}
public InventoryMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -25,11 +25,18 @@ public class LoreMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
LoreMessage(LoreMessageType messageType){
private LoreMessage(LoreMessageType messageType){
this.type = MessageType.LORE_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected LoreMessage(){
this.type = MessageType.LORE_MESSAGE;
}
public LoreMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -0,0 +1,176 @@
package electrosphere.net.parser.net.message;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import electrosphere.net.parser.net.message.NetworkMessage.MessageType;
/**
* Pools message objects to reduce allocations
*/
public class MessagePool {
/**
* Pools auth messages
*/
List<NetworkMessage> authMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools character messages
*/
List<NetworkMessage> characterMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools combat messages
*/
List<NetworkMessage> combatMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools entity messages
*/
List<NetworkMessage> entityMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools inventory messages
*/
List<NetworkMessage> inventoryMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools lore messages
*/
List<NetworkMessage> loreMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools player messages
*/
List<NetworkMessage> playerMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools server messages
*/
List<NetworkMessage> serverMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools synchronization messages
*/
List<NetworkMessage> synchronizationMessagePool = new LinkedList<NetworkMessage>();
/**
* Pools terrain messages
*/
List<NetworkMessage> terrainMessagePool = new LinkedList<NetworkMessage>();
/**
* Lock for thread-safeing operations
*/
ReentrantLock lock = new ReentrantLock();
/**
* Gets a network message from the pool. Allocates if no free one is available
* @param type The type of the message
* @return
*/
public NetworkMessage get(MessageType type){
NetworkMessage rVal = null;
lock.lock();
if(type == MessageType.AUTH_MESSAGE){
if(authMessagePool.size() > 0){
rVal = authMessagePool.remove(0);
} else {
rVal = new AuthMessage();
}
} else if(type == MessageType.CHARACTER_MESSAGE){
if(characterMessagePool.size() > 0){
rVal = characterMessagePool.remove(0);
} else {
rVal = new CharacterMessage();
}
} else if(type == MessageType.COMBAT_MESSAGE){
if(combatMessagePool.size() > 0){
rVal = combatMessagePool.remove(0);
} else {
rVal = new CombatMessage();
}
} else if(type == MessageType.ENTITY_MESSAGE){
if(entityMessagePool.size() > 0){
rVal = entityMessagePool.remove(0);
} else {
rVal = new EntityMessage();
}
} else if(type == MessageType.INVENTORY_MESSAGE){
if(inventoryMessagePool.size() > 0){
rVal = inventoryMessagePool.remove(0);
} else {
rVal = new InventoryMessage();
}
} else if(type == MessageType.LORE_MESSAGE){
if(loreMessagePool.size() > 0){
rVal = loreMessagePool.remove(0);
} else {
rVal = new LoreMessage();
}
} else if(type == MessageType.PLAYER_MESSAGE){
if(playerMessagePool.size() > 0){
rVal = playerMessagePool.remove(0);
} else {
rVal = new PlayerMessage();
}
} else if(type == MessageType.SERVER_MESSAGE){
if(serverMessagePool.size() > 0){
rVal = serverMessagePool.remove(0);
} else {
rVal = new ServerMessage();
}
} else if(type == MessageType.SYNCHRONIZATION_MESSAGE){
if(synchronizationMessagePool.size() > 0){
rVal = synchronizationMessagePool.remove(0);
} else {
rVal = new SynchronizationMessage();
}
} else if(type == MessageType.TERRAIN_MESSAGE){
if(terrainMessagePool.size() > 0){
rVal = terrainMessagePool.remove(0);
} else {
rVal = new TerrainMessage();
}
} else {
throw new Error("Unsupported message type! " + type);
}
lock.unlock();
return rVal;
}
/**
* Releases a message back into the pool
* @param message The message
*/
public void release(NetworkMessage message){
lock.lock();
if(message instanceof AuthMessage){
authMessagePool.add(message);
} else if(message instanceof CharacterMessage){
characterMessagePool.add(message);
} else if(message instanceof CombatMessage){
combatMessagePool.add(message);
} else if(message instanceof EntityMessage){
entityMessagePool.add(message);
} else if(message instanceof InventoryMessage){
inventoryMessagePool.add(message);
} else if(message instanceof LoreMessage){
loreMessagePool.add(message);
} else if(message instanceof PlayerMessage){
playerMessagePool.add(message);
} else if(message instanceof ServerMessage){
serverMessagePool.add(message);
} else if(message instanceof SynchronizationMessage){
synchronizationMessagePool.add(message);
} else if(message instanceof TerrainMessage){
terrainMessagePool.add(message);
} else {
throw new Error("Unsupported message type! " + message.getClass());
}
lock.unlock();
}
}

View File

@ -57,9 +57,10 @@ public abstract class NetworkMessage {
/**
* Parses the byte stream for the next message
* @param byteBuffer The byte buffer
* @param pool The message pool
* @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, MessagePool pool){
NetworkMessage rVal = null;
byte firstByte;
byte secondByte;
@ -71,52 +72,52 @@ public abstract class NetworkMessage {
switch(secondByte){
case TypeBytes.ENTITY_MESSAGE_TYPE_CREATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseCreateMessage(byteBuffer);
rVal = EntityMessage.parseCreateMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer);
rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACKUPDATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseattackUpdateMessage(byteBuffer);
rVal = EntityMessage.parseattackUpdateMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsestartAttackMessage(byteBuffer);
rVal = EntityMessage.parsestartAttackMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_KILL:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseKillMessage(byteBuffer);
rVal = EntityMessage.parseKillMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_DESTROY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseDestroyMessage(byteBuffer);
rVal = EntityMessage.parseDestroyMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetPropertyMessage(byteBuffer);
rVal = EntityMessage.parsesetPropertyMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer);
rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer);
rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer,pool);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesyncPhysicsMessage(byteBuffer);
rVal = EntityMessage.parsesyncPhysicsMessage(byteBuffer,pool);
}
break;
}
@ -156,82 +157,82 @@ public abstract class NetworkMessage {
switch(secondByte){
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTMETADATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestMetadataMessage(byteBuffer);
rVal = TerrainMessage.parseRequestMetadataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseResponseMetadataMessage(byteBuffer);
rVal = TerrainMessage.parseResponseMetadataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer);
rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseUpdateVoxelMessage(byteBuffer);
rVal = TerrainMessage.parseUpdateVoxelMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestUseTerrainPaletteMessage(byteBuffer);
rVal = TerrainMessage.parseRequestUseTerrainPaletteMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SPAWNPOSITION:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSpawnPositionMessage(byteBuffer);
rVal = TerrainMessage.parseSpawnPositionMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestChunkDataMessage(byteBuffer);
rVal = TerrainMessage.parseRequestChunkDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer);
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestReducedChunkDataMessage(byteBuffer);
rVal = TerrainMessage.parseRequestReducedChunkDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSendReducedChunkDataMessage(byteBuffer);
rVal = TerrainMessage.parseSendReducedChunkDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDBLOCKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestReducedBlockDataMessage(byteBuffer);
rVal = TerrainMessage.parseRequestReducedBlockDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDBLOCKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSendReducedBlockDataMessage(byteBuffer);
rVal = TerrainMessage.parseSendReducedBlockDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseUpdateBlockMessage(byteBuffer);
rVal = TerrainMessage.parseUpdateBlockMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer);
rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer);
rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer,pool);
}
break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseupdateFluidDataMessage(byteBuffer);
rVal = TerrainMessage.parseupdateFluidDataMessage(byteBuffer,pool);
}
break;
}

View File

@ -25,11 +25,18 @@ public class PlayerMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
PlayerMessage(PlayerMessageType messageType){
private PlayerMessage(PlayerMessageType messageType){
this.type = MessageType.PLAYER_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected PlayerMessage(){
this.type = MessageType.PLAYER_MESSAGE;
}
public PlayerMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -20,11 +20,18 @@ public class ServerMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
ServerMessage(ServerMessageType messageType){
private ServerMessage(ServerMessageType messageType){
this.type = MessageType.SERVER_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected ServerMessage(){
this.type = MessageType.SERVER_MESSAGE;
}
public ServerMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -42,11 +42,18 @@ public class SynchronizationMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
SynchronizationMessage(SynchronizationMessageType messageType){
private SynchronizationMessage(SynchronizationMessageType messageType){
this.type = MessageType.SYNCHRONIZATION_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected SynchronizationMessage(){
this.type = MessageType.SYNCHRONIZATION_MESSAGE;
}
public SynchronizationMessageType getMessageSubtype(){
return this.messageType;
}

View File

@ -64,11 +64,18 @@ public class TerrainMessage extends NetworkMessage {
* Constructor
* @param messageType The type of this message
*/
TerrainMessage(TerrainMessageType messageType){
private TerrainMessage(TerrainMessageType messageType){
this.type = MessageType.TERRAIN_MESSAGE;
this.messageType = messageType;
}
/**
* Constructor
*/
protected TerrainMessage(){
this.type = MessageType.TERRAIN_MESSAGE;
}
public TerrainMessageType getMessageSubtype(){
return this.messageType;
}
@ -536,8 +543,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestMetadata
*/
public static TerrainMessage parseRequestMetadataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTMETADATA);
public static TerrainMessage parseRequestMetadataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTMETADATA;
stripPacketHeader(byteBuffer);
return rVal;
}
@ -554,8 +562,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type ResponseMetadata
*/
public static TerrainMessage parseResponseMetadataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.RESPONSEMETADATA);
public static TerrainMessage parseResponseMetadataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.RESPONSEMETADATA;
stripPacketHeader(byteBuffer);
rVal.setworldSizeDiscrete(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldMinX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -586,8 +595,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestEditVoxel
*/
public static TerrainMessage parseRequestEditVoxelMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITVOXEL);
public static TerrainMessage parseRequestEditVoxelMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTEDITVOXEL;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -620,8 +630,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type UpdateVoxel
*/
public static TerrainMessage parseUpdateVoxelMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEVOXEL);
public static TerrainMessage parseUpdateVoxelMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.UPDATEVOXEL;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -654,8 +665,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestUseTerrainPalette
*/
public static TerrainMessage parseRequestUseTerrainPaletteMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTUSETERRAINPALETTE);
public static TerrainMessage parseRequestUseTerrainPaletteMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTUSETERRAINPALETTE;
stripPacketHeader(byteBuffer);
rVal.setrealLocationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrealLocationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
@ -684,8 +696,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type SpawnPosition
*/
public static TerrainMessage parseSpawnPositionMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SPAWNPOSITION);
public static TerrainMessage parseSpawnPositionMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.SPAWNPOSITION;
stripPacketHeader(byteBuffer);
rVal.setrealLocationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setrealLocationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
@ -708,8 +721,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestChunkData
*/
public static TerrainMessage parseRequestChunkDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTCHUNKDATA);
public static TerrainMessage parseRequestChunkDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTCHUNKDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -763,8 +777,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type sendChunkData
*/
public static TerrainMessage parsesendChunkDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDCHUNKDATA);
public static TerrainMessage parsesendChunkDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.SENDCHUNKDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -789,8 +804,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestReducedChunkData
*/
public static TerrainMessage parseRequestReducedChunkDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDCHUNKDATA);
public static TerrainMessage parseRequestReducedChunkDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTREDUCEDCHUNKDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -852,8 +868,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type SendReducedChunkData
*/
public static TerrainMessage parseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDCHUNKDATA);
public static TerrainMessage parseSendReducedChunkDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.SENDREDUCEDCHUNKDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -882,8 +899,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestReducedBlockData
*/
public static TerrainMessage parseRequestReducedBlockDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTREDUCEDBLOCKDATA);
public static TerrainMessage parseRequestReducedBlockDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTREDUCEDBLOCKDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -945,8 +963,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type SendReducedBlockData
*/
public static TerrainMessage parseSendReducedBlockDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDREDUCEDBLOCKDATA);
public static TerrainMessage parseSendReducedBlockDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.SENDREDUCEDBLOCKDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -975,8 +994,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type UpdateBlock
*/
public static TerrainMessage parseUpdateBlockMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEBLOCK);
public static TerrainMessage parseUpdateBlockMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.UPDATEBLOCK;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -1009,8 +1029,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type RequestFluidData
*/
public static TerrainMessage parseRequestFluidDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
public static TerrainMessage parseRequestFluidDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTFLUIDDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -1064,8 +1085,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type sendFluidData
*/
public static TerrainMessage parsesendFluidDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
public static TerrainMessage parsesendFluidDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.SENDFLUIDDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
@ -1121,8 +1143,9 @@ public class TerrainMessage extends NetworkMessage {
/**
* Parses a message of type updateFluidData
*/
public static TerrainMessage parseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
public static TerrainMessage parseupdateFluidDataMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.UPDATEFLUIDDATA;
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));

View File

@ -1,5 +1,6 @@
package electrosphere.net.parser.net.raw;
import electrosphere.net.parser.net.message.MessagePool;
import electrosphere.net.parser.net.message.NetworkMessage;
import io.github.studiorailgun.CircularByteBuffer;
import java.io.IOException;
@ -48,6 +49,11 @@ public class NetworkParser {
*/
CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(CIRCULAR_BUFFER_SIZE);
/**
* Message object pool
*/
MessagePool pool = new MessagePool();
/**
* The block array used to read blocks of bytes in
*/
@ -91,7 +97,7 @@ public class NetworkParser {
//parse byte queue for messages
//for each message, append to clientIncomingMessageQueue
NetworkMessage newMessage;
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer))!=null){
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer,this.pool))!=null){
incomingMessageQueue.add(newMessage);
}
}
@ -104,6 +110,7 @@ public class NetworkParser {
for(NetworkMessage message : outgoingMessageQueue){
outgoingMessageQueue.remove(message);
outgoingStream.write(message.getRawBytes());
pool.release(message);
}
}
@ -155,4 +162,12 @@ public class NetworkParser {
return totalBytesRead;
}
/**
* Releases a network message object back into the pool
* @param message The message
*/
public void release(NetworkMessage message){
this.pool.release(message);
}
}

View File

@ -84,5 +84,16 @@ public class ServerContentManager {
FileUtils.serializeObjectToFilePath(fullPath, serialization);
}
/**
* Saves a collection of serialized entities to disk
* @param locationKey The location key to save under
* @param serialization The collection of entities to save
*/
public void saveSerializationToDisk(Long locationKey, ContentSerialization serialization){
String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSave.getName());
String fullPath = dirPath + "/content/" + locationKey + ".dat";
FileUtils.serializeObjectToFilePath(fullPath, serialization);
}
}

View File

@ -2,6 +2,7 @@ package electrosphere.server.datacell;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import electrosphere.entity.Entity;
@ -10,19 +11,28 @@ import electrosphere.entity.Entity;
*/
public class EntityDataCellMapper {
// The map of entity -> server data cell
/**
* The map of entity -> server data cell
*/
Map<Entity,ServerDataCell> entityDataCellMap = new HashMap<Entity,ServerDataCell>();
/**
* Lock for thread safe-ing the mapper
*/
ReentrantLock lock = new ReentrantLock();
/**
* Registers an entity into the map. Should be called every time any entity is created on the server.
* @param entity The entity that was just created
* @param serverDataCell The server data cell to register this entity to
*/
public void registerEntity(Entity entity, ServerDataCell serverDataCell){
lock.lock();
if(serverDataCell == null){
throw new Error("Mapping entity to null!");
}
entityDataCellMap.put(entity, serverDataCell);
lock.unlock();
}
/**
@ -31,7 +41,10 @@ public class EntityDataCellMapper {
* @return The server data cell that the entity is inside of
*/
public ServerDataCell getEntityDataCell(Entity entity){
return entityDataCellMap.get(entity);
lock.lock();
ServerDataCell rVal = entityDataCellMap.get(entity);
lock.unlock();
return rVal;
}
/**
@ -40,10 +53,12 @@ public class EntityDataCellMapper {
* @param serverDataCell The new server data cell for the entity
*/
public void updateEntityCell(Entity entity, ServerDataCell serverDataCell){
lock.lock();
if(serverDataCell == null){
throw new Error("Passing null to cell mapper update! " + entity + " " + serverDataCell);
}
entityDataCellMap.put(entity, serverDataCell);
lock.unlock();
}
/**
@ -51,7 +66,9 @@ public class EntityDataCellMapper {
* @param entity The entity to eject
*/
public void ejectEntity(Entity entity){
lock.lock();
entityDataCellMap.remove(entity);
lock.unlock();
}
}

View File

@ -2,6 +2,7 @@ package electrosphere.server.datacell.gridded;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@ -30,6 +31,62 @@ public class GriddedDataCellLoaderService {
*/
private static final Map<Long,Future<?>> queuedWorkLock = new HashMap<Long,Future<?>>();
/**
* Map of a job to its corresponding work
*/
private static final Map<Long,Runnable> jobOperationMap = new HashMap<Long,Runnable>();
/**
* Queues an operation that requires a read or write of a location's file data.
* Guarantees that all operations will be run in order without losing any work.
* @param key The key for the cell
* @param operation The operation to perform
*/
protected static void queueLocationBasedOperation(long key, Runnable operation){
lock.lock();
//if there is a job queued and we couldn't cancel it, wait
Future<?> job = queuedWorkLock.get(key);
Runnable opCallback = () -> {
//work here
operation.run();
//let the service know we've finished this job
lock.lock();
queuedWorkLock.remove(key);
lock.unlock();
};
if(job != null){
if(!job.cancel(false)){
try {
Globals.profiler.beginCpuSample("Waiting for cell io job to finish");
job.get();
Globals.profiler.endCpuSample();
} catch (InterruptedException e) {
LoggerInterface.loggerEngine.ERROR("Failed to wait for previous job for cell!", e);
} catch (ExecutionException e) {
LoggerInterface.loggerEngine.ERROR("Previous job for cell threw an error!", e);
}
}
if(job.isCancelled()){
Runnable oldOp = jobOperationMap.remove(key);
//queue job to run the old operation first, then the new one
opCallback = () -> {
oldOp.run();
//load here
operation.run();
//let the service know we've finished this job
lock.lock();
queuedWorkLock.remove(key);
lock.unlock();
};
}
}
//queue job to do the operation
Future<?> newJob = ioThreadService.submit(opCallback);
queuedWorkLock.put(key, newJob);
jobOperationMap.put(key,operation);
lock.unlock();
}
/**
* Loads a cell
* @param key The key for the cell
@ -48,7 +105,7 @@ public class GriddedDataCellLoaderService {
}
}
//queue job to load the cell
ioThreadService.submit(() -> {
Future<?> newJob = ioThreadService.submit(() -> {
//load here
loadLogic.run();
//let the service know we've finished this job
@ -56,6 +113,7 @@ public class GriddedDataCellLoaderService {
queuedWorkLock.remove(key);
lock.unlock();
});
queuedWorkLock.put(key, newJob);
lock.unlock();
}

View File

@ -32,6 +32,7 @@ import electrosphere.net.server.player.Player;
import electrosphere.net.server.protocol.TerrainProtocol;
import electrosphere.server.block.manager.ServerBlockManager;
import electrosphere.server.content.ServerContentManager;
import electrosphere.server.content.serialization.ContentSerialization;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.interfaces.DataCellManager;
@ -320,7 +321,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//the server will not be able to synchronize it properly.
ServerEntityUtils.initiallyPositionEntity(parent,blockEntity,realPos);
ServerEntityUtils.initiallyPositionEntity(parent,terrainEntity,realPos);
PhysicsDataCell cell = PhysicsDataCell.createPhysicsCell(worldPos, terrainEntity, blockEntity, terrainChunk, blockChunkData);
PhysicsDataCell cell = PhysicsDataCell.createPhysicsCell(worldPos, terrainEntity, blockEntity);
cell.setTerrainChunk(terrainChunk);
cell.setBlockChunk(blockChunkData);
cell.generatePhysics();
posPhysicsMap.put(key, cell);
}
@ -449,11 +452,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
Vector3i worldPos = this.getCellWorldPosition(cell);
Long key = this.getServerDataCellKey(worldPos);
//offload all entities in cell to chunk file
//entities are saved before tracking is removed. This makes sure that any side effects from calling destroyEntity (ie if it looks up the chunk that we're deleting)
//entities are serialized before tracking is removed. This makes sure that any side effects from calling destroyEntity (ie if it looks up the chunk that we're deleting)
//don't trigger the chunk to be re-created
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Serialize entities");
ContentSerialization serializedEntities = ContentSerialization.constructContentSerialization(cell.getScene().getEntityList());
Globals.profiler.endCpuSample();
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Destroy entities");
serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList());
for(Entity entity : cell.getScene().getEntityList()){
ServerEntityUtils.destroyEntity(entity);
}
@ -462,8 +468,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//save terrain to disk
//terrain is saved before tracking is removed. This makes sure that any side effects from calling savePositionToDisk (ie if it looks up the chunk that we're deleting)
//don't trigger the chunk to be re-created
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Store terrain");
serverTerrainManager.savePositionToDisk(worldPos);
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Store data");
GriddedDataCellLoaderService.queueLocationBasedOperation(key, () -> {
serverContentManager.saveSerializationToDisk(key, serializedEntities);
serverTerrainManager.savePositionToDisk(worldPos);
});
Globals.profiler.endCpuSample();
//deregister from all tracking structures
@ -662,8 +671,6 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
worldPos.y * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET,
worldPos.z * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET
);
BlockChunkData blockChunkData = realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z);
ServerTerrainChunk terrainChunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldPos.x, worldPos.y, worldPos.z);
ServerDataCell dataCell = groundDataCells.get(key);
//create entities
@ -678,7 +685,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
ServerEntityUtils.initiallyPositionEntity(realm,blockEntity,realPos);
ServerEntityUtils.initiallyPositionEntity(realm,terrainEntity,realPos);
PhysicsDataCell targetCell = PhysicsDataCell.createPhysicsCell(worldPos, terrainEntity, blockEntity, terrainChunk, blockChunkData);
PhysicsDataCell targetCell = PhysicsDataCell.createPhysicsCell(worldPos, terrainEntity, blockEntity);
if(cell == null){
posPhysicsMap.put(key, targetCell);
} else {
@ -687,6 +694,10 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
}
generationService.submit(() -> {
BlockChunkData blockChunkData = realm.getServerWorldData().getServerBlockManager().getChunk(worldPos.x, worldPos.y, worldPos.z);
ServerTerrainChunk terrainChunk = realm.getServerWorldData().getServerTerrainManager().getChunk(worldPos.x, worldPos.y, worldPos.z);
targetCell.setTerrainChunk(terrainChunk);
targetCell.setBlockChunk(blockChunkData);
//create physics entities
if(cell != null){
cell.retireCell();
@ -725,10 +736,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
cellPositionMap.put(rVal,new Vector3i(worldPos));
loadedCellsLock.unlock();
//generate content
serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey);
//generates physics for the cell in a dedicated thread then finally registers
Long key = this.getServerDataCellKey(worldPos);
//generate content
GriddedDataCellLoaderService.queueLocationBasedOperation(key, () -> {
serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey);
});
//generates physics for the cell in a dedicated thread then finally registers
PhysicsDataCell cell = posPhysicsMap.get(key);
GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent);

View File

@ -48,17 +48,13 @@ public class PhysicsDataCell {
public static PhysicsDataCell createPhysicsCell(
Vector3i worldPos,
Entity physicsEntity,
Entity blockPhysicsEntity,
ServerTerrainChunk currentChunk,
BlockChunkData blockChunk
Entity blockPhysicsEntity
){
PhysicsDataCell rVal = new PhysicsDataCell();
rVal.physicsEntity = physicsEntity;
rVal.blockPhysicsEntity = blockPhysicsEntity;
rVal.worldPos = worldPos;
rVal.blockChunk = blockChunk;
rVal.terrainChunk = currentChunk;
return rVal;
}
@ -232,4 +228,22 @@ public class PhysicsDataCell {
// }
}
/**
* Sets the terrain chunk data for the physics cell
* @param terrainChunk The terrain chunk data
*/
public void setTerrainChunk(ServerTerrainChunk terrainChunk) {
this.terrainChunk = terrainChunk;
}
/**
* Sets the block chunk data for the physics cell
* @param blockChunk The block chunk data
*/
public void setBlockChunk(BlockChunkData blockChunk) {
this.blockChunk = blockChunk;
}
}