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 toolsindex
- @subpage highleveldesignindex - @subpage highleveldesignindex
- @subpage progress - @subpage progress
- @subpage optimizationideas

View File

@ -1375,6 +1375,14 @@ Disable kinematic colliders on creation
MainContentPipeline reduce allocations MainContentPipeline reduce allocations
Move AI simulation to server level from chunk level 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 { 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>(); Map<Integer,Integer> typeCoordMap = new HashMap<Integer,Integer>();
//the actual texture /**
* The actual texture
*/
Texture specular; Texture specular;
//the normal texture /**
* The normal texture
*/
Texture normal; 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; 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; 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; public static final int ELEMENTS_PER_ROW = ATLAS_DIM / ATLAS_ELEMENT_DIM;
/** /**

View File

@ -1,8 +1,5 @@
package electrosphere.collision; 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 static org.ode4j.ode.OdeHelper.areConnectedExcluding;
import java.util.List; import java.util.List;
@ -28,7 +25,7 @@ public class RayCastCallback implements DNearCallback {
/** /**
* Maximum number of contacts allowed * 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 * 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) { public void call(Object data, DGeom o1, DGeom o2) {
// if (o1->body && o2->body) return; // if (o1->body && o2->body) return;
RayCastCallbackData rayCastData = (RayCastCallbackData)data; RayCastCallbackData rayCastData = (RayCastCallbackData)data;
//null out potentially previous results //null out potentially previous results
// rayCastData.collisionPosition = null; // rayCastData.collisionPosition = null;
// rayCastData.collidedEntity = null; // rayCastData.collidedEntity = null;
@ -71,33 +69,25 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
DBody b2 = o2.getBody(); DBody b2 = o2.getBody();
if (b1!=null && b2!=null && areConnectedExcluding (b1,b2,DContactJoint.class)) return; 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 collidable1 = rayCastData.bodyEntityMap.get(b1);
Collidable collidable2 = rayCastData.bodyEntityMap.get(b2); 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( if(
( rayCastData.collidableTypeMask == null ||
rayCastData.collidableTypeMask == null || (o1 instanceof DRay && rayCastData.collidableTypeMask.contains(collidable2.getType())) ||
( (o2 instanceof DRay && rayCastData.collidableTypeMask.contains(collidable1.getType()))
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
){ ){
//creates a buffer to store potential collisions
DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); // up to MAX_CONTACTS contacts per box-box
//calculate collisions //calculate collisions
int numc = OdeHelper.collide(o1,o2,MAX_CONTACTS,contacts.getGeomBuffer()); int numc = OdeHelper.collide(o1,o2,MAX_CONTACTS,contacts.getGeomBuffer());
//create DContacts based on each collision that occurs //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){ if(ServerToolbarState.getServerToolbarState(parent) != null){
ServerToolbarState serverToolbarState = ServerToolbarState.getServerToolbarState(parent); ServerToolbarState serverToolbarState = ServerToolbarState.getServerToolbarState(parent);
Entity item = serverToolbarState.getRealWorldItem(); Entity item = serverToolbarState.getRealWorldItem();
if(item == null){
return EntityDataStrings.ATTACK_MOVE_UNARMED;
}
if(ItemUtils.isWeapon(item)){ if(ItemUtils.isWeapon(item)){
currentWeapon = item; currentWeapon = item;
switch(ItemUtils.getWeaponClass(item)){ switch(ItemUtils.getWeaponClass(item)){

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@ -1,16 +1,16 @@
package electrosphere.net.parser.net.message; package electrosphere.net.parser.net.message;
import io.github.studiorailgun.CircularByteBuffer; import io.github.studiorailgun.CircularByteBuffer;
/** /**
* A network message * A network message
*/ */
public abstract class NetworkMessage { public abstract class NetworkMessage {
/** /**
* The different categories of network messages * The different categories of network messages
*/ */
public enum MessageType { public enum MessageType {
ENTITY_MESSAGE, ENTITY_MESSAGE,
LORE_MESSAGE, LORE_MESSAGE,
PLAYER_MESSAGE, PLAYER_MESSAGE,
@ -21,102 +21,103 @@ public abstract class NetworkMessage {
INVENTORY_MESSAGE, INVENTORY_MESSAGE,
SYNCHRONIZATION_MESSAGE, SYNCHRONIZATION_MESSAGE,
COMBAT_MESSAGE, COMBAT_MESSAGE,
} }
/** /**
* The type of this message * The type of this message
*/ */
MessageType type; MessageType type;
/** /**
* Tracks whether the message has been serialized to bytes or not * Tracks whether the message has been serialized to bytes or not
*/ */
boolean serialized; boolean serialized;
/** /**
* The raw bytes contained in the message * The raw bytes contained in the message
*/ */
byte[] rawBytes; byte[] rawBytes;
/** /**
* Gets the type of the message * Gets the type of the message
* @return 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 * Gets the raw bytes of the message
* @return The raw bytes * @return The raw bytes
*/ */
public byte[] getRawBytes() { public byte[] getRawBytes() {
return rawBytes; return rawBytes;
} }
/** /**
* Parses the byte stream for the next message * Parses the byte stream for the next message
* @param byteBuffer The byte buffer * @param byteBuffer The byte buffer
* @return The message if one is at the front of the byte stream, null otherwise * @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){ */
NetworkMessage rVal = null; public static NetworkMessage parseBytestreamForMessage(CircularByteBuffer byteBuffer, MessagePool pool){
byte firstByte; NetworkMessage rVal = null;
byte secondByte; byte firstByte;
if(byteBuffer.getRemaining() > 1){ byte secondByte;
firstByte = byteBuffer.peek(); if(byteBuffer.getRemaining() > 1){
switch(firstByte){ firstByte = byteBuffer.peek();
switch(firstByte){
case TypeBytes.MESSAGE_TYPE_ENTITY: case TypeBytes.MESSAGE_TYPE_ENTITY:
secondByte = byteBuffer.peek(1); secondByte = byteBuffer.peek(1);
switch(secondByte){ switch(secondByte){
case TypeBytes.ENTITY_MESSAGE_TYPE_CREATE: case TypeBytes.ENTITY_MESSAGE_TYPE_CREATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseCreateMessage(byteBuffer); rVal = EntityMessage.parseCreateMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE: case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer); rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACKUPDATE: case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACKUPDATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseattackUpdateMessage(byteBuffer); rVal = EntityMessage.parseattackUpdateMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK: case TypeBytes.ENTITY_MESSAGE_TYPE_STARTATTACK:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsestartAttackMessage(byteBuffer); rVal = EntityMessage.parsestartAttackMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_KILL: case TypeBytes.ENTITY_MESSAGE_TYPE_KILL:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseKillMessage(byteBuffer); rVal = EntityMessage.parseKillMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_DESTROY: case TypeBytes.ENTITY_MESSAGE_TYPE_DESTROY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseDestroyMessage(byteBuffer); rVal = EntityMessage.parseDestroyMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY: case TypeBytes.ENTITY_MESSAGE_TYPE_SETPROPERTY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesetPropertyMessage(byteBuffer); rVal = EntityMessage.parsesetPropertyMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY: case TypeBytes.ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer); rVal = EntityMessage.parseattachEntityToEntityMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR: case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer); rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS: case TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){ if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsesyncPhysicsMessage(byteBuffer); rVal = EntityMessage.parsesyncPhysicsMessage(byteBuffer,pool);
} }
break; break;
} }
@ -156,82 +157,82 @@ public abstract class NetworkMessage {
switch(secondByte){ switch(secondByte){
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTMETADATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTMETADATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestMetadataMessage(byteBuffer); rVal = TerrainMessage.parseRequestMetadataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseResponseMetadataMessage(byteBuffer); rVal = TerrainMessage.parseResponseMetadataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer); rVal = TerrainMessage.parseRequestEditVoxelMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL: case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEVOXEL:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseUpdateVoxelMessage(byteBuffer); rVal = TerrainMessage.parseUpdateVoxelMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestUseTerrainPaletteMessage(byteBuffer); rVal = TerrainMessage.parseRequestUseTerrainPaletteMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SPAWNPOSITION: case TypeBytes.TERRAIN_MESSAGE_TYPE_SPAWNPOSITION:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSpawnPositionMessage(byteBuffer); rVal = TerrainMessage.parseSpawnPositionMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestChunkDataMessage(byteBuffer); rVal = TerrainMessage.parseRequestChunkDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer); rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestReducedChunkDataMessage(byteBuffer); rVal = TerrainMessage.parseRequestReducedChunkDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSendReducedChunkDataMessage(byteBuffer); rVal = TerrainMessage.parseSendReducedChunkDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDBLOCKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDBLOCKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestReducedBlockDataMessage(byteBuffer); rVal = TerrainMessage.parseRequestReducedBlockDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDBLOCKDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDBLOCKDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseSendReducedBlockDataMessage(byteBuffer); rVal = TerrainMessage.parseSendReducedBlockDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK: case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEBLOCK:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseUpdateBlockMessage(byteBuffer); rVal = TerrainMessage.parseUpdateBlockMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer); rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer); rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){ if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseupdateFluidDataMessage(byteBuffer); rVal = TerrainMessage.parseupdateFluidDataMessage(byteBuffer,pool);
} }
break; break;
} }
@ -456,23 +457,23 @@ public abstract class NetworkMessage {
break; break;
} }
break; break;
} }
} }
return rVal; return rVal;
} }
/** /**
* Checks if this message is serialized or not * Checks if this message is serialized or not
* @return true if it is serialized, false otherwise * @return true if it is serialized, false otherwise
*/ */
public boolean isSerialized(){ public boolean isSerialized(){
return serialized; return serialized;
} }
/** /**
* Serializes the message * Serializes the message
*/ */
abstract void serialize(); abstract void serialize();
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
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.MessagePool;
import electrosphere.net.parser.net.message.NetworkMessage;
import io.github.studiorailgun.CircularByteBuffer; import io.github.studiorailgun.CircularByteBuffer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -48,6 +49,11 @@ public class NetworkParser {
*/ */
CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(CIRCULAR_BUFFER_SIZE); CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(CIRCULAR_BUFFER_SIZE);
/**
* Message object pool
*/
MessagePool pool = new MessagePool();
/** /**
* The block array used to read blocks of bytes in * The block array used to read blocks of bytes in
*/ */
@ -91,7 +97,7 @@ public class NetworkParser {
//parse byte queue for messages //parse byte queue for messages
//for each message, append to clientIncomingMessageQueue //for each message, append to clientIncomingMessageQueue
NetworkMessage newMessage; NetworkMessage newMessage;
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer))!=null){ while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer,this.pool))!=null){
incomingMessageQueue.add(newMessage); incomingMessageQueue.add(newMessage);
} }
} }
@ -104,6 +110,7 @@ public class NetworkParser {
for(NetworkMessage message : outgoingMessageQueue){ for(NetworkMessage message : outgoingMessageQueue){
outgoingMessageQueue.remove(message); outgoingMessageQueue.remove(message);
outgoingStream.write(message.getRawBytes()); outgoingStream.write(message.getRawBytes());
pool.release(message);
} }
} }
@ -154,5 +161,13 @@ public class NetworkParser {
public long getNumberOfBytesRead(){ public long getNumberOfBytesRead(){
return totalBytesRead; 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); 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.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
@ -10,19 +11,28 @@ import electrosphere.entity.Entity;
*/ */
public class EntityDataCellMapper { 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>(); 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. * 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 entity The entity that was just created
* @param serverDataCell The server data cell to register this entity to * @param serverDataCell The server data cell to register this entity to
*/ */
public void registerEntity(Entity entity, ServerDataCell serverDataCell){ public void registerEntity(Entity entity, ServerDataCell serverDataCell){
lock.lock();
if(serverDataCell == null){ if(serverDataCell == null){
throw new Error("Mapping entity to null!"); throw new Error("Mapping entity to null!");
} }
entityDataCellMap.put(entity, serverDataCell); entityDataCellMap.put(entity, serverDataCell);
lock.unlock();
} }
/** /**
@ -31,7 +41,10 @@ public class EntityDataCellMapper {
* @return The server data cell that the entity is inside of * @return The server data cell that the entity is inside of
*/ */
public ServerDataCell getEntityDataCell(Entity entity){ 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 * @param serverDataCell The new server data cell for the entity
*/ */
public void updateEntityCell(Entity entity, ServerDataCell serverDataCell){ public void updateEntityCell(Entity entity, ServerDataCell serverDataCell){
lock.lock();
if(serverDataCell == null){ if(serverDataCell == null){
throw new Error("Passing null to cell mapper update! " + entity + " " + serverDataCell); throw new Error("Passing null to cell mapper update! " + entity + " " + serverDataCell);
} }
entityDataCellMap.put(entity, serverDataCell); entityDataCellMap.put(entity, serverDataCell);
lock.unlock();
} }
/** /**
@ -51,7 +66,9 @@ public class EntityDataCellMapper {
* @param entity The entity to eject * @param entity The entity to eject
*/ */
public void ejectEntity(Entity entity){ public void ejectEntity(Entity entity){
lock.lock();
entityDataCellMap.remove(entity); entityDataCellMap.remove(entity);
lock.unlock();
} }
} }

View File

@ -2,6 +2,7 @@ package electrosphere.server.datacell.gridded;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -30,6 +31,62 @@ public class GriddedDataCellLoaderService {
*/ */
private static final Map<Long,Future<?>> queuedWorkLock = new HashMap<Long,Future<?>>(); 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 * Loads a cell
* @param key The key for the cell * @param key The key for the cell
@ -48,7 +105,7 @@ public class GriddedDataCellLoaderService {
} }
} }
//queue job to load the cell //queue job to load the cell
ioThreadService.submit(() -> { Future<?> newJob = ioThreadService.submit(() -> {
//load here //load here
loadLogic.run(); loadLogic.run();
//let the service know we've finished this job //let the service know we've finished this job
@ -56,6 +113,7 @@ public class GriddedDataCellLoaderService {
queuedWorkLock.remove(key); queuedWorkLock.remove(key);
lock.unlock(); lock.unlock();
}); });
queuedWorkLock.put(key, newJob);
lock.unlock(); lock.unlock();
} }

View File

@ -32,6 +32,7 @@ import electrosphere.net.server.player.Player;
import electrosphere.net.server.protocol.TerrainProtocol; import electrosphere.net.server.protocol.TerrainProtocol;
import electrosphere.server.block.manager.ServerBlockManager; import electrosphere.server.block.manager.ServerBlockManager;
import electrosphere.server.content.ServerContentManager; import electrosphere.server.content.ServerContentManager;
import electrosphere.server.content.serialization.ContentSerialization;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.interfaces.DataCellManager; 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. //the server will not be able to synchronize it properly.
ServerEntityUtils.initiallyPositionEntity(parent,blockEntity,realPos); ServerEntityUtils.initiallyPositionEntity(parent,blockEntity,realPos);
ServerEntityUtils.initiallyPositionEntity(parent,terrainEntity,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(); cell.generatePhysics();
posPhysicsMap.put(key, cell); posPhysicsMap.put(key, cell);
} }
@ -449,11 +452,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
Vector3i worldPos = this.getCellWorldPosition(cell); Vector3i worldPos = this.getCellWorldPosition(cell);
Long key = this.getServerDataCellKey(worldPos); Long key = this.getServerDataCellKey(worldPos);
//offload all entities in cell to chunk file //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)
//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)
//don't trigger the chunk to be re-created //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"); Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Destroy entities");
serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList());
for(Entity entity : cell.getScene().getEntityList()){ for(Entity entity : cell.getScene().getEntityList()){
ServerEntityUtils.destroyEntity(entity); ServerEntityUtils.destroyEntity(entity);
} }
@ -462,8 +468,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//save terrain to disk //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) //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 //don't trigger the chunk to be re-created
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Store terrain"); Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Store data");
serverTerrainManager.savePositionToDisk(worldPos); GriddedDataCellLoaderService.queueLocationBasedOperation(key, () -> {
serverContentManager.saveSerializationToDisk(key, serializedEntities);
serverTerrainManager.savePositionToDisk(worldPos);
});
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//deregister from all tracking structures //deregister from all tracking structures
@ -662,8 +671,6 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
worldPos.y * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET, worldPos.y * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET,
worldPos.z * 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); ServerDataCell dataCell = groundDataCells.get(key);
//create entities //create entities
@ -678,7 +685,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
ServerEntityUtils.initiallyPositionEntity(realm,blockEntity,realPos); ServerEntityUtils.initiallyPositionEntity(realm,blockEntity,realPos);
ServerEntityUtils.initiallyPositionEntity(realm,terrainEntity,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){ if(cell == null){
posPhysicsMap.put(key, targetCell); posPhysicsMap.put(key, targetCell);
} else { } else {
@ -687,6 +694,10 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
} }
generationService.submit(() -> { 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 //create physics entities
if(cell != null){ if(cell != null){
cell.retireCell(); cell.retireCell();
@ -725,10 +736,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
cellPositionMap.put(rVal,new Vector3i(worldPos)); cellPositionMap.put(rVal,new Vector3i(worldPos));
loadedCellsLock.unlock(); 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); 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); PhysicsDataCell cell = posPhysicsMap.get(key);
GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent); GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent);

View File

@ -48,17 +48,13 @@ public class PhysicsDataCell {
public static PhysicsDataCell createPhysicsCell( public static PhysicsDataCell createPhysicsCell(
Vector3i worldPos, Vector3i worldPos,
Entity physicsEntity, Entity physicsEntity,
Entity blockPhysicsEntity, Entity blockPhysicsEntity
ServerTerrainChunk currentChunk,
BlockChunkData blockChunk
){ ){
PhysicsDataCell rVal = new PhysicsDataCell(); PhysicsDataCell rVal = new PhysicsDataCell();
rVal.physicsEntity = physicsEntity; rVal.physicsEntity = physicsEntity;
rVal.blockPhysicsEntity = blockPhysicsEntity; rVal.blockPhysicsEntity = blockPhysicsEntity;
rVal.worldPos = worldPos; rVal.worldPos = worldPos;
rVal.blockChunk = blockChunk;
rVal.terrainChunk = currentChunk;
return rVal; return rVal;
} }
@ -231,5 +227,23 @@ public class PhysicsDataCell {
// types[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = 0; // types[ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE][ChunkData.CHUNK_SIZE] = 0;
// } // }
} }
/**
* 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;
}
} }