netparser message pooling + multithread chunk io
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
deea49ba64
commit
c7dc9ef07d
26
docs/src/ideas/optimizationideas.md
Normal file
26
docs/src/ideas/optimizationideas.md
Normal 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
|
||||
|
||||
@ -5,3 +5,4 @@
|
||||
- @subpage toolsindex
|
||||
- @subpage highleveldesignindex
|
||||
- @subpage progress
|
||||
- @subpage optimizationideas
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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)){
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,16 +1,16 @@
|
||||
package electrosphere.net.parser.net.message;
|
||||
|
||||
import io.github.studiorailgun.CircularByteBuffer;
|
||||
|
||||
/**
|
||||
* A network message
|
||||
*/
|
||||
public abstract class NetworkMessage {
|
||||
|
||||
/**
|
||||
* The different categories of network messages
|
||||
*/
|
||||
public enum MessageType {
|
||||
import io.github.studiorailgun.CircularByteBuffer;
|
||||
|
||||
/**
|
||||
* A network message
|
||||
*/
|
||||
public abstract class NetworkMessage {
|
||||
|
||||
/**
|
||||
* The different categories of network messages
|
||||
*/
|
||||
public enum MessageType {
|
||||
ENTITY_MESSAGE,
|
||||
LORE_MESSAGE,
|
||||
PLAYER_MESSAGE,
|
||||
@ -21,102 +21,103 @@ public abstract class NetworkMessage {
|
||||
INVENTORY_MESSAGE,
|
||||
SYNCHRONIZATION_MESSAGE,
|
||||
COMBAT_MESSAGE,
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of this message
|
||||
*/
|
||||
MessageType type;
|
||||
|
||||
/**
|
||||
* Tracks whether the message has been serialized to bytes or not
|
||||
*/
|
||||
boolean serialized;
|
||||
|
||||
/**
|
||||
* The raw bytes contained in the message
|
||||
*/
|
||||
byte[] rawBytes;
|
||||
|
||||
/**
|
||||
* Gets the type of the message
|
||||
* @return The type of the message
|
||||
*/
|
||||
public MessageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw bytes of the message
|
||||
* @return The raw bytes
|
||||
*/
|
||||
public byte[] getRawBytes() {
|
||||
return rawBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the byte stream for the next message
|
||||
* @param byteBuffer The byte buffer
|
||||
* @return The message if one is at the front of the byte stream, null otherwise
|
||||
*/
|
||||
public static NetworkMessage parseBytestreamForMessage(CircularByteBuffer byteBuffer){
|
||||
NetworkMessage rVal = null;
|
||||
byte firstByte;
|
||||
byte secondByte;
|
||||
if(byteBuffer.getRemaining() > 1){
|
||||
firstByte = byteBuffer.peek();
|
||||
switch(firstByte){
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of this message
|
||||
*/
|
||||
MessageType type;
|
||||
|
||||
/**
|
||||
* Tracks whether the message has been serialized to bytes or not
|
||||
*/
|
||||
boolean serialized;
|
||||
|
||||
/**
|
||||
* The raw bytes contained in the message
|
||||
*/
|
||||
byte[] rawBytes;
|
||||
|
||||
/**
|
||||
* Gets the type of the message
|
||||
* @return The type of the message
|
||||
*/
|
||||
public MessageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw bytes of the message
|
||||
* @return The raw bytes
|
||||
*/
|
||||
public byte[] getRawBytes() {
|
||||
return rawBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, MessagePool pool){
|
||||
NetworkMessage rVal = null;
|
||||
byte firstByte;
|
||||
byte secondByte;
|
||||
if(byteBuffer.getRemaining() > 1){
|
||||
firstByte = byteBuffer.peek();
|
||||
switch(firstByte){
|
||||
case TypeBytes.MESSAGE_TYPE_ENTITY:
|
||||
secondByte = byteBuffer.peek(1);
|
||||
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;
|
||||
}
|
||||
@ -456,23 +457,23 @@ public abstract class NetworkMessage {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this message is serialized or not
|
||||
* @return true if it is serialized, false otherwise
|
||||
*/
|
||||
public boolean isSerialized(){
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message
|
||||
*/
|
||||
abstract void serialize();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this message is serialized or not
|
||||
* @return true if it is serialized, false otherwise
|
||||
*/
|
||||
public boolean isSerialized(){
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message
|
||||
*/
|
||||
abstract void serialize();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package electrosphere.net.parser.net.raw;
|
||||
|
||||
import electrosphere.net.parser.net.message.NetworkMessage;
|
||||
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;
|
||||
import java.io.InputStream;
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,5 +161,13 @@ public class NetworkParser {
|
||||
public long getNumberOfBytesRead(){
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a network message object back into the pool
|
||||
* @param message The message
|
||||
*/
|
||||
public void release(NetworkMessage message){
|
||||
this.pool.release(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -231,5 +227,23 @@ public class PhysicsDataCell {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user