synchronizing object entities
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-07-27 00:15:50 -04:00
parent 1df8a89b3e
commit 161f40ee04
25 changed files with 311 additions and 85 deletions

View File

@ -27,6 +27,7 @@
"files" : [
"Data/objects/floatingisland.json",
"Data/objects/testscene1objects.json",
"Data/objects/debug_objects.json"
"Data/objects/debug_objects.json",
"Data/objects/game_objects.json"
]
}

View File

@ -0,0 +1,14 @@
{
"objects" : [
{
"objectId" : "spawnPoint",
"modelPath" : "Models/basic/geometry/unitcylinder.fbx",
"tokens": [
"SPAWNPOINT"
]
}
],
"files" : []
}

View File

@ -454,11 +454,11 @@ Devtools for updating first person attachment rotations
(07/26/2024)
Viewmodel equipped item rotates inverted to bone rotation
Visually block
Utility object for reducing boilerplate when writing btree transitions that just play an animation then transition
First animations flickering in first person (enforce animation priority requirement)
Debug third person animations flickering (attachments not reflecting animations that were played that frame)
Small data fix
Refactor spawn point to not be global
# TODO

View File

@ -149,6 +149,17 @@
"positionZ"
]
},
{
"messageName" : "SpawnObject",
"description" : "Spawns a generic object",
"data" : [
"entityID",
"creatureTemplate",
"positionX",
"positionY",
"positionZ"
]
},
{
"messageName" : "moveUpdate",
"description" : "Updates a client on the move state of an entity",

View File

@ -101,7 +101,12 @@ public class ClientSceneWrapper {
* @return The entity in question
*/
public Entity getEntityFromServerId(int id){
return scene.getEntityFromId(mapServerToClientId(id));
if(serverToClientIdMap.containsKey(id)){
int clientId = mapServerToClientId(id);
return scene.getEntityFromId(clientId);
} else {
return null;
}
}
/**
@ -119,6 +124,7 @@ public class ClientSceneWrapper {
* @param id The id
*/
public void dumpIdData(int id){
LoggerInterface.loggerNetworking.WARNING("Offending ID " + id);
LoggerInterface.loggerNetworking.WARNING("Client->Server Map contains? " + clientToServerIdMap.containsKey(id));
LoggerInterface.loggerNetworking.WARNING("Server->Client Map contains? " + serverToClientIdMap.containsKey(id));
if(clientToServerIdMap.containsKey(id)){

View File

@ -5,7 +5,6 @@ import java.util.LinkedList;
import java.util.List;
import org.joml.Matrix4f;
import org.joml.Vector3d;
import org.joml.Vector3f;
import electrosphere.audio.AudioEngine;
@ -273,9 +272,6 @@ public class Globals {
//Engine - Main managers/variables
//
//spawn point
public static Vector3d spawnPoint = new Vector3d(0,0,0);
//manages all models loaded into memory
public static AssetManager assetManager;

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
@ -171,10 +172,11 @@ public class LoadingUtils {
//set player world-space coordinates
Player playerObject = Globals.playerManager.getPlayerFromId(0);
Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d spawnPoint = realm.getSpawnPoint();
playerObject.setWorldPos(new Vector3i(
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.z)
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
));
}

View File

@ -22,6 +22,7 @@ public class EntityTags {
public static final String POSEABLE = "poseable"; //is it poseable on server
public static final String LIGHT = "light";
public static final String ITEM = "item";
public static final String OBJECT = "object";
public static final String GRAVITY = "gravity";
public static final String PARTICLE = "particle";

View File

@ -665,12 +665,13 @@ public class CreatureUtils {
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.LIFE_STATE);
//idle tree & generic stuff all creatures have
ServerIdleTree.attachTree(rVal);
CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
//required for synchronization manager
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.CREATURE);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE);
EntityUtils.setEntitySubtype(rVal, type);
CreatureUtils.setFacingVector(rVal, MathUtils.getOriginVector());
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
//position entity
//this needs to be called at the end of this function.

View File

@ -186,14 +186,16 @@ public class ItemUtils {
}
}
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_ITEM);
rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, false);
EntityUtils.setEntitySubtype(rVal, name);
// rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(0.005f,0.005f,0.005f));
// rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity().rotateY((float)(-Math.PI/2)).rotateZ(-(float)(Math.PI/2)));
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.ITEM);
//required for synchronization manager
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.ITEM);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_ITEM);
EntityUtils.setEntitySubtype(rVal, name);
//position entity
//this needs to be called at the end of this function.

View File

@ -26,7 +26,9 @@ import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.object.type.ObjectData;
import electrosphere.renderer.actor.ActorUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.datacell.utils.ServerEntityTagUtils;
@ -48,12 +50,8 @@ public class ObjectUtils {
EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath());
}
//forward-searching tokens
boolean collisionMakeDynamic = true;
for(String token : rawType.getTokens()){
switch(token){
case "DISABLE_COLLISION_REACTION": {
collisionMakeDynamic = false;
} break;
case "GENERATE_COLLISION_OBJECT": {
Globals.assetManager.addCollisionMeshToQueue(new PhysicsMeshQueueItem(Globals.clientSceneWrapper.getCollisionEngine(),rawType.getModelPath()));
Globals.clientSceneWrapper.getScene().registerBehaviorTree(new BehaviorTree() {public void simulate(float deltaTime) {
@ -86,9 +84,6 @@ public class ObjectUtils {
//tokens
for(String token : rawType.getTokens()){
switch(token){
case "BLENDER_TRANSFORM":
ActorUtils.applyBlenderTransformer(rVal);
break;
case "GRAVITY":
Collidable collidable = (Collidable)rVal.getData(EntityDataStrings.PHYSICS_COLLIDABLE);
DBody collisionObject = (DBody)rVal.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
@ -108,6 +103,9 @@ public class ObjectUtils {
case "TERRAIN_COLLISION": {
CollisionObjUtils.getCollidable(rVal).overrideType(Collidable.TYPE_TERRAIN);
} break;
case "SPAWNPOINT": {
//ignore on client
} break;
}
}
if(rawType.getHitboxData() != null){
@ -139,12 +137,8 @@ public class ObjectUtils {
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath());
}
//forward-searching tokens
boolean collisionMakeDynamic = true;
for(String token : rawType.getTokens()){
switch(token){
case "DISABLE_COLLISION_REACTION": {
collisionMakeDynamic = false;
} break;
case "GENERATE_COLLISION_OBJECT": {
Globals.assetManager.addCollisionMeshToQueue(new PhysicsMeshQueueItem(realm.getCollisionEngine(),rawType.getModelPath()));
ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, new BehaviorTree() {public void simulate(float deltaTime) {
@ -177,9 +171,6 @@ public class ObjectUtils {
//tokens
for(String token : rawType.getTokens()){
switch(token){
case "BLENDER_TRANSFORM":
ActorUtils.applyBlenderTransformer(rVal);
break;
case "GRAVITY":
Collidable collidable = (Collidable)rVal.getData(EntityDataStrings.PHYSICS_COLLIDABLE);
DBody collisionObject = (DBody)rVal.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
@ -199,6 +190,9 @@ public class ObjectUtils {
case "TERRAIN_COLLISION": {
CollisionObjUtils.getCollidable(rVal).overrideType(Collidable.TYPE_TERRAIN);
} break;
case "SPAWNPOINT": {
realm.registerSpawnPoint(position);
} break;
}
}
if(rawType.getHitboxData() != null){
@ -208,6 +202,12 @@ public class ObjectUtils {
ServerIdleTree.attachTree(rVal);
//required for synchronization manager
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.OBJECT);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_OBJECT);
EntityUtils.setEntitySubtype(rVal, type);
//position entity
//this needs to be called at the end of this function.
//Burried underneath this is function call to initialize a server side entity.
@ -239,4 +239,24 @@ public class ObjectUtils {
return (String)EntityUtils.getEntitySubtype(e);
}
/**
* Sets the object to a given player
* @param player The player
* @param item The object entity
*/
public static void sendEntityToPlayer(Player player, Entity object){
int id = object.getId();
String type = ObjectUtils.getType(object);
Vector3d position = EntityUtils.getPosition(object);
//construct the spawn message and attach to player
NetworkMessage message = EntityMessage.constructSpawnObjectMessage(
id,
type,
position.x,
position.y,
position.z
);
player.addMessage(message);
}
}

View File

@ -7,7 +7,6 @@ import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
@ -16,6 +15,7 @@ import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.game.data.creature.type.CreatureType;
import electrosphere.game.data.creature.type.ViewModelData;
import electrosphere.logger.LoggerInterface;
@ -86,6 +86,15 @@ public class EntityProtocol {
ClientEntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()));
Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
} break;
case SPAWNOBJECT: {
LoggerInterface.loggerNetworking.DEBUG("Spawn object " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
//spawn item
String objectType = message.getcreatureTemplate();
newlySpawnedEntity = ObjectUtils.clientSpawnBasicObject(objectType);
//position
ClientEntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()));
Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
} break;

View File

@ -28,7 +28,7 @@ public class TerrainProtocol {
Globals.clientConnection.getClientProtocol().setHasReceivedWorld(true);
break;
case SPAWNPOSITION:
Globals.spawnPoint.set(message.getrealLocationX(),0.25,message.getrealLocationZ());
LoggerInterface.loggerNetworking.WARNING("Received spawnPosition packet on client. This is deprecated!");
break;
case SENDCHUNKDATA:
Globals.clientTerrainManager.attachTerrainMessage(message);

View File

@ -11,6 +11,7 @@ public class EntityMessage extends NetworkMessage {
CREATE,
SPAWNCREATURE,
SPAWNITEM,
SPAWNOBJECT,
MOVEUPDATE,
ATTACKUPDATE,
STARTATTACK,
@ -288,6 +289,8 @@ public class EntityMessage extends NetworkMessage {
return EntityMessage.canParseSpawnCreatureMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNITEM:
return EntityMessage.canParseSpawnItemMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNOBJECT:
return EntityMessage.canParseSpawnObjectMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE_SIZE){
return true;
@ -502,6 +505,59 @@ public class EntityMessage extends NetworkMessage {
return rVal;
}
public static boolean canParseSpawnObjectMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
if(currentStreamLength < 6){
return false;
}
int creatureTemplateSize = 0;
if(currentStreamLength < 10){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(6 + 0));
temporaryByteQueue.add(byteBuffer.peek(6 + 1));
temporaryByteQueue.add(byteBuffer.peek(6 + 2));
temporaryByteQueue.add(byteBuffer.peek(6 + 3));
creatureTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 10 + creatureTemplateSize){
return false;
}
if(currentStreamLength < 18 + creatureTemplateSize){
return false;
}
if(currentStreamLength < 26 + creatureTemplateSize){
return false;
}
if(currentStreamLength < 34 + creatureTemplateSize){
return false;
}
return true;
}
public static EntityMessage parseSpawnObjectMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.SPAWNOBJECT);
stripPacketHeader(byteBuffer);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setcreatureTemplate(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
return rVal;
}
public static EntityMessage constructSpawnObjectMessage(int entityID,String creatureTemplate,double positionX,double positionY,double positionZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.SPAWNOBJECT);
rVal.setentityID(entityID);
rVal.setcreatureTemplate(creatureTemplate);
rVal.setpositionX(positionX);
rVal.setpositionY(positionY);
rVal.setpositionZ(positionZ);
rVal.serialize();
return rVal;
}
public static EntityMessage parsemoveUpdateMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.MOVEUPDATE);
stripPacketHeader(byteBuffer);
@ -857,6 +913,37 @@ public class EntityMessage extends NetworkMessage {
rawBytes[26+creatureTemplate.length()+i] = intValues[i];
}
break;
case SPAWNOBJECT:
rawBytes = new byte[2+4+4+creatureTemplate.length()+8+8+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNOBJECT;
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(creatureTemplate.length());
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
stringBytes = creatureTemplate.getBytes();
for(int i = 0; i < creatureTemplate.length(); i++){
rawBytes[10+i] = stringBytes[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
for(int i = 0; i < 8; i++){
rawBytes[10+creatureTemplate.length()+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
for(int i = 0; i < 8; i++){
rawBytes[18+creatureTemplate.length()+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
for(int i = 0; i < 8; i++){
rawBytes[26+creatureTemplate.length()+i] = intValues[i];
}
break;
case MOVEUPDATE:
rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+8+4+4];
//message header

View File

@ -56,6 +56,11 @@ SYNCHRONIZATION_MESSAGE,
rVal = EntityMessage.parseSpawnItemMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNOBJECT:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseSpawnObjectMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_MOVEUPDATE:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parsemoveUpdateMessage(byteBuffer);

View File

@ -20,15 +20,16 @@ Message categories
public static final byte ENTITY_MESSAGE_TYPE_CREATE = 0;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNCREATURE = 1;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNITEM = 2;
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE = 3;
public static final byte ENTITY_MESSAGE_TYPE_ATTACKUPDATE = 4;
public static final byte ENTITY_MESSAGE_TYPE_STARTATTACK = 5;
public static final byte ENTITY_MESSAGE_TYPE_KILL = 6;
public static final byte ENTITY_MESSAGE_TYPE_DESTROY = 7;
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY = 8;
public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 9;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED = 10;
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR = 11;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNOBJECT = 3;
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE = 4;
public static final byte ENTITY_MESSAGE_TYPE_ATTACKUPDATE = 5;
public static final byte ENTITY_MESSAGE_TYPE_STARTATTACK = 6;
public static final byte ENTITY_MESSAGE_TYPE_KILL = 7;
public static final byte ENTITY_MESSAGE_TYPE_DESTROY = 8;
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY = 9;
public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 10;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED = 11;
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR = 12;
/*
Entity packet sizes
*/

View File

@ -1,5 +1,7 @@
package electrosphere.net.server.protocol;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.net.parser.net.message.CharacterMessage;
@ -64,17 +66,18 @@ public class CharacterProtocol {
static void spawnEntityForClient(ServerConnectionHandler connectionHandler){
PlayerCharacterCreation.spawnPlayerCharacter(connectionHandler);
Realm realm = Globals.playerManager.getPlayerRealm(connectionHandler.getPlayer());
Vector3d spawnPoint = realm.getSpawnPoint();
//set client initial discrete position
connectionHandler.addMessagetoOutgoingQueue(
PlayerMessage.constructSetInitialDiscretePositionMessage(
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.z)
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
)
);
//send spawn point
connectionHandler.addMessagetoOutgoingQueue(
TerrainMessage.constructSpawnPositionMessage(Globals.spawnPoint.x, Globals.spawnPoint.y, Globals.spawnPoint.z)
TerrainMessage.constructSpawnPositionMessage(spawnPoint.x, spawnPoint.y, spawnPoint.z)
);
}

View File

@ -48,6 +48,7 @@ public class EntityProtocol {
case SETPROPERTY:
case SPAWNFOLIAGESEED:
case SPAWNITEM:
case SPAWNOBJECT:
//silently ignore
break;
}
@ -72,6 +73,7 @@ public class EntityProtocol {
case SETPROPERTY:
case SPAWNFOLIAGESEED:
case SPAWNITEM:
case SPAWNOBJECT:
//silently ignore
break;
}

View File

@ -3,21 +3,17 @@ package electrosphere.net.synchronization;
import electrosphere.net.synchronization.FieldIdEnums;
import electrosphere.entity.state.block.ClientBlockTree;
import electrosphere.entity.state.block.ServerBlockTree;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree;
import electrosphere.logger.LoggerInterface;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.attack.ServerAttackTree;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.idle.ServerIdleTree;
import electrosphere.entity.state.idle.ClientIdleTree;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import electrosphere.engine.Globals;
@ -32,6 +28,12 @@ public class ClientSynchronizationManager {
//The list of messages to loop through
List<SynchronizationMessage> messages = new CopyOnWriteArrayList<SynchronizationMessage>();
//Map that tracks the number of times a network message bounces
Map<SynchronizationMessage,Integer> messageBounceCount = new HashMap<SynchronizationMessage,Integer>();
//the count at which to warn about a message bouncing
static final int MESSAGE_BOUNCE_WARNING_COUNT = 10;
/**
* Pushes a message into the queue to be processed
* @param message The message
@ -46,8 +48,18 @@ public class ClientSynchronizationManager {
public void processMessages(){
List<SynchronizationMessage> messagesToClear = new LinkedList<SynchronizationMessage>();
for(SynchronizationMessage message : messages){
//track number of times this message has bounced
if(messageBounceCount.containsKey(message)){
messageBounceCount.put(message, messageBounceCount.get(message) + 1);
} else {
messageBounceCount.put(message, 0);
}
//attempt to handle the message
if(Globals.clientSceneWrapper.containsServerId(message.getentityId()) && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()) != null){
messagesToClear.add(message);
messageBounceCount.remove(message);
switch(message.getMessageSubtype()){
case UPDATECLIENTSTATE:{
int bTreeId = message.getbTreeId();
@ -71,15 +83,23 @@ public class ClientSynchronizationManager {
int entityId = message.getentityId();
} break;
}
} else if(Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()) == null){
} else if(Globals.clientSceneWrapper.containsServerId(message.getentityId()) && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()) == null){
String errorMessage =
"Client received synchronization packet for entity that does not exists on client!\n" +
"Specifically, the synchronization manager thinks this id is registered, but there is no entity at that key\n" +
"Entity id in network message: " + message.getentityId()
;
Globals.clientSceneWrapper.dumpTranslationLayerStatus();
Globals.clientSceneWrapper.dumpIdData(message.getentityId());
throw new IllegalStateException(errorMessage);
}
//warn if a message has bounced a certain number of times
if(messageBounceCount.containsKey(message) && messageBounceCount.get(message) > MESSAGE_BOUNCE_WARNING_COUNT){
String warningMessage =
"A synchronization message has bounced at least " + MESSAGE_BOUNCE_WARNING_COUNT + "times!";
LoggerInterface.loggerNetworking.WARNING(warningMessage);
}
}
for(SynchronizationMessage message : messagesToClear){
messages.remove(message);

View File

@ -28,7 +28,8 @@ public class PlayerCharacterCreation {
String raceName = template.getCreatureType();
//spawn entity in world
Realm realm = Globals.realmManager.getRealms().iterator().next();
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z),raceName,template);
Vector3d spawnPoint = realm.getSpawnPoint();
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(spawnPoint.x,spawnPoint.y,spawnPoint.z),raceName,template);
int playerCharacterId = newPlayerEntity.getId();
connectionHandler.setPlayerEntityId(playerCharacterId);
CreatureUtils.setControllerPlayerId(newPlayerEntity, connectionHandler.getPlayerId());
@ -37,9 +38,9 @@ public class PlayerCharacterCreation {
//attach player object to player character
playerObject.setPlayerEntity(newPlayerEntity);
playerObject.setWorldPos(new Vector3i(
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(Globals.spawnPoint.z)
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
));
realm.getDataCellManager().addPlayerToRealm(playerObject);
//parse network messages on client if running

View File

@ -6,11 +6,7 @@ import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.server.content.serialization.ContentSerialization;
import electrosphere.server.content.serialization.EntitySerialization;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.saves.SaveUtils;
@ -49,7 +45,7 @@ public class ServerContentManager {
if(FileUtils.checkSavePathExists(Globals.currentSave.getName(), fullPath)){
//if on disk (has already been generated)
ContentSerialization contentRaw = FileUtils.loadObjectFromSavePath(Globals.currentSave.getName(), fullPath, ContentSerialization.class);
hydrateRawContent(realm,cell,contentRaw);
contentRaw.hydrateRawContent(realm,cell);
} else {
//else create from scratch
//UNCOMMENT THIS WHEN YOU WANT CONTENT GENERATED FOR WORLDS AGAIN
@ -60,7 +56,7 @@ public class ServerContentManager {
if(FileUtils.checkSavePathExists(Globals.currentSave.getName(), fullPath)){
//if on disk (has already been generated)
ContentSerialization contentRaw = FileUtils.loadObjectFromSavePath(Globals.currentSave.getName(), fullPath, ContentSerialization.class);
hydrateRawContent(realm,cell,contentRaw);
contentRaw.hydrateRawContent(realm,cell);
}
}
//TODO: generate navmesh
@ -86,24 +82,5 @@ public class ServerContentManager {
FileUtils.serializeObjectToFilePath(fullPath, serialization);
}
/**
* Actually creates the entities from a content serialization
* @param contentRaw The content serialization
*/
public void hydrateRawContent(Realm realm, ServerDataCell serverDataCell, ContentSerialization contentRaw){
List<EntitySerialization> serializedEntities = contentRaw.getSerializedEntities();
for(EntitySerialization serializedEntity : serializedEntities){
switch(serializedEntity.getType()){
case CreatureUtils.ENTITY_TYPE_CREATURE: {
Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), null);
EntityUtils.getRotation(creature).set(serializedEntity.getRotation());
} break;
case ItemUtils.ENTITY_TYPE_ITEM: {
Entity item = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), serializedEntity.getSubtype());
} break;
}
}
}
}

View File

@ -10,6 +10,8 @@ import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.entity.types.structure.StructureUtils;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
/**
* Contains all content for a given cell
@ -46,7 +48,12 @@ public class ContentSerialization {
rVal.serializedEntities.add(serializedEntity);
}
if(ObjectUtils.isObject(entity)){
throw new UnsupportedOperationException();
EntitySerialization serializedEntity = new EntitySerialization();
serializedEntity.setPosition(EntityUtils.getPosition(entity));
serializedEntity.setRotation(EntityUtils.getRotation(entity));
serializedEntity.setType(ObjectUtils.ENTITY_TYPE_OBJECT);
serializedEntity.setSubtype(ObjectUtils.getType(entity));
rVal.serializedEntities.add(serializedEntity);
}
if(StructureUtils.isStructure(entity)){
throw new UnsupportedOperationException();
@ -59,6 +66,30 @@ public class ContentSerialization {
return rVal;
}
/**
* Actually creates the entities from a content serialization
* @param contentRaw The content serialization
*/
public void hydrateRawContent(Realm realm, ServerDataCell serverDataCell){
List<EntitySerialization> serializedEntities = this.getSerializedEntities();
for(EntitySerialization serializedEntity : serializedEntities){
switch(serializedEntity.getType()){
case CreatureUtils.ENTITY_TYPE_CREATURE: {
Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), null);
EntityUtils.getRotation(creature).set(serializedEntity.getRotation());
} break;
case ItemUtils.ENTITY_TYPE_ITEM: {
Entity item = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), serializedEntity.getSubtype());
EntityUtils.getRotation(item).set(serializedEntity.getRotation());
} break;
case ObjectUtils.ENTITY_TYPE_OBJECT: {
Entity object = ObjectUtils.serverSpawnBasicObject(realm, serializedEntity.getPosition(), serializedEntity.getSubtype());
EntityUtils.getRotation(object).set(serializedEntity.getRotation());
} break;
}
}
}
/**
* Gets all serialized entities
* @return the list of serialized entities

View File

@ -12,8 +12,12 @@ import electrosphere.server.content.ServerContentManager;
import electrosphere.server.datacell.interfaces.DataCellManager;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.joml.Vector3d;
/**
* Manages data cells on the server side
@ -57,6 +61,11 @@ public class Realm {
* The instanceId of the scene that was loaded with this realm
*/
int sceneInstanceId = NO_SCENE_INSTANCE;
/**
* The list of available spawnpoints
*/
List<Vector3d> spawnPoints = new LinkedList<Vector3d>();
/**
* Realm constructor
@ -229,6 +238,26 @@ public class Realm {
return this.serverContentManager;
}
/**
* Gets the spawn point for the realm
* @return The spawn point
*/
public Vector3d getSpawnPoint(){
if(this.spawnPoints.size() > 0){
return this.spawnPoints.get(0);
} else {
return new Vector3d(0,0,0);
}
}
/**
* Registers a spawn point
* @param point The spawn point location
*/
public void registerSpawnPoint(Vector3d point){
this.spawnPoints.add(point);
}
/**
* Sets the script-engine side instance id for the scene that was loaded with this realm
* @param sceneInstanceId The instance id

View File

@ -6,6 +6,7 @@ import electrosphere.entity.Scene;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.entity.types.structure.StructureUtils;
import electrosphere.game.server.character.Character;
import electrosphere.net.parser.net.message.EntityMessage;
@ -149,6 +150,9 @@ public class ServerDataCell {
if(ItemUtils.isItem(entity)){
ItemUtils.sendEntityToPlayer(player, entity);
}
if(ObjectUtils.isObject(entity)){
ObjectUtils.sendEntityToPlayer(player,entity);
}
if(StructureUtils.isStructure(entity)){
StructureUtils.sendStructureToPlayer(player, entity);
}

View File

@ -17,6 +17,7 @@ import electrosphere.entity.state.movement.ProjectileTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.server.datacell.Realm;
/**
* Callback for managing collisions on the server
@ -64,7 +65,8 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
LifeUtils.getLifeState(receiverParent).damage(damage);
if(!LifeUtils.getLifeState(receiverParent).isIsAlive()){
System.out.println("ServerHitboxResolutionCallback - Unimplemented!!");
EntityUtils.getPosition(receiverParent).set(Globals.spawnPoint);
Realm entityRealm = Globals.realmManager.getEntityRealm(receiverParent);
EntityUtils.getPosition(receiverParent).set(entityRealm.getSpawnPoint());
LifeUtils.getLifeState(receiverParent).revive();
}
}
@ -82,7 +84,8 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba
LifeUtils.getLifeState(receiverParent).damage(damage);
if(!LifeUtils.getLifeState(receiverParent).isIsAlive()){
System.out.println("ServerHitboxResolutionCallback - Unimplemented!!");
EntityUtils.getPosition(receiverParent).set(Globals.spawnPoint);
Realm entityRealm = Globals.realmManager.getEntityRealm(receiverParent);
EntityUtils.getPosition(receiverParent).set(entityRealm.getSpawnPoint());
LifeUtils.getLifeState(receiverParent).revive();
}
}