basic inventory networking

This commit is contained in:
austin 2022-05-17 14:27:54 -04:00
parent 726ffe065e
commit 4499a9e534
28 changed files with 1010 additions and 183 deletions

View File

@ -108,6 +108,16 @@
"positionZ"
]
},
{
"messageName" : "SpawnItem",
"data" : [
"entityID",
"creatureTemplate",
"positionX",
"positionY",
"positionZ"
]
},
{
"messageName" : "SetPosition",
"data" : [

46
net/inventory.json Normal file
View File

@ -0,0 +1,46 @@
{
"outputPath" : "./src/main/java/electrosphere/net/parser/",
"packageName" : "electrosphere.net.parser",
"categories":[
{
"categoryName" : "Inventory",
"data" : [
{
"name" : "itemTemplate",
"type" : "VAR_STRING"
},
{
"name" : "equipPointId",
"type" : "VAR_STRING"
},
{
"name" : "entityId",
"type" : "FIXED_INT"
}
],
"messageTypes" : [
{
"messageName" : "addItemToInventory",
"data" : [
"entityId",
"itemTemplate"
]
},
{
"messageName" : "removeItemFromInventory",
"data" : [
"entityId"
]
},
{
"messageName" : "equipItem",
"data" : [
"equipPointId",
"entityId",
"itemTemplate"
]
}
]
}
]
}

View File

@ -674,7 +674,7 @@ public class LoadingThread extends Thread {
//sword
Entity sword = ItemUtils.spawnBasicItem("Katana");
EntityUtils.getPosition(sword).set(new Vector3f(1,0.4f,2));
EntityUtils.initiallyPositionEntity(sword, new Vector3d(1,0.4f,2));
EntityUtils.getRotation(sword).set(new Quaternionf().rotationY((float)(Math.PI/2.0)));

View File

@ -163,6 +163,7 @@ public class EntityDataStrings {
public static final String ITEM_IN_WORLD_REPRESENTATION = "itemInWorldRepresentation";
public static final String ITEM_WEAPON_CLASS = "itemWeaponClass";
public static final String ITEM_WEAPON_DATA_RAW = "itemWeaponDataRaw";
public static final String ITEM_IS_IN_INVENTORY = "itemIsInInventory";
/*
@ -213,6 +214,7 @@ public class EntityDataStrings {
Inventory in general
*/
public static final String NATURAL_INVENTORY = "inventoryNatural";
public static final String INVENTORY_STATE = "inventoryState";
/*
Iron sight

View File

@ -20,6 +20,8 @@ public class EntityManager {
static Map<Integer,Entity> entityIdMap = new ConcurrentHashMap<Integer,Entity>();
static Map<Integer,Integer> clientToServerIdMap = new ConcurrentHashMap<Integer,Integer>();
static Map<Integer,Integer> serverToClientIdMap = new ConcurrentHashMap<Integer,Integer>();
static List<Entity> entityList = new CopyOnWriteArrayList<Entity>();
static List<Entity> drawableList = new CopyOnWriteArrayList<Entity>();
static List<Entity> moveableList = new CopyOnWriteArrayList<Entity>();
@ -248,18 +250,60 @@ public class EntityManager {
target.putData(EntityDataStrings.DATA_STRING_DRAW, true);
}
public void overrideEntityId(Entity e, int id){
LoggerInterface.loggerGameLogic.DEBUG("Overriding entity ID " + e.getId() + " => " + id);
if(entityIdMap.containsKey(e.getId())){
entityIdMap.remove(e.getId());
}
e.setId(id);
entityIdMap.put(e.getId(), e);
// public void overrideEntityId(Entity e, int id){
// LoggerInterface.loggerGameLogic.DEBUG("Overriding entity ID " + e.getId() + " => " + id);
// if(entityIdMap.containsKey(e.getId())){
// entityIdMap.remove(e.getId());
// }
// e.setId(id);
// entityIdMap.put(e.getId(), e);
// }
/**
* Registers a server provided ID as a mapping to a given ID on the client
* @param clientId The client's generated ID
* @param serverId The server's provided ID
*/
public void mapIdToId(int clientId, int serverId){
LoggerInterface.loggerEngine.DEBUG("MapID: " + clientId + " <===> " + serverId);
clientToServerIdMap.put(clientId, serverId);
serverToClientIdMap.put(serverId, clientId);
}
/**
* Resolves a client ID to the equivalent ID on the server
* @param clientId The id provided by the client
* @return The equivalent id on the server
*/
public int mapClientToServerId(int clientId){
return clientToServerIdMap.get(clientId);
}
/**
* Translates the id provided by the server into the equivalent id on the client
* @param serverId The id provided by the server
* @return The equivalent id on the client
*/
public int mapServerToClientId(int serverId){
return serverToClientIdMap.get(serverId);
}
public Entity getEntityFromId(int id){
return (Entity)entityIdMap.get(id);
}
/**
* [CLIENT ONLY] Gets the entity provided a server-provided id
* @param id The server-provided ID
* @return The entity in question
*/
public Entity getEntityFromServerId(int id){
if(Globals.RUN_SERVER){
return (Entity)entityIdMap.get(id);
} else {
return (Entity)entityIdMap.get(mapServerToClientId(id));
}
}
public void clearOutOfBoundsEntities(){
if(Globals.commonWorldData != null && Globals.playerEntity != null && Globals.clientPlayerData != null){

View File

@ -7,8 +7,10 @@ package electrosphere.entity;
import electrosphere.entity.state.collidable.CollidableTree;
import electrosphere.entity.state.movement.GroundMovementTree;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.game.server.datacell.ServerDataCell;
import electrosphere.renderer.Model;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorUtils;
@ -100,9 +102,9 @@ public class EntityUtils {
}
}
public static void setEntityID(Entity e, int id){
Globals.entityManager.overrideEntityId(e, id);
}
// public static void setEntityID(Entity e, int id){
// Globals.entityManager.mapIdToId(e.getId(), id);
// }
public static Actor getActor(Entity e){
return (Actor)e.getData(EntityDataStrings.DATA_STRING_ACTOR);
@ -123,5 +125,53 @@ public class EntityUtils {
public static boolean getDraw(Entity entity){
return (boolean)entity.getData(EntityDataStrings.DATA_STRING_DRAW);
}
/**
* Called when the creature is first spawned to serialize to all people in its initial chunk
* @param entity
* @param position
*/
public static void initiallyPositionEntity(Entity entity, Vector3d position){
//if server, get current server data cell
if(Globals.RUN_SERVER){
ServerDataCell oldDataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(entity));
ServerDataCell newDataCell = Globals.dataCellManager.getDataCellAtPoint(position);
if(newDataCell != null){
//initialize server datacell tracking of this entity
Globals.dataCellManager.initializeServerSideEntity(entity, newDataCell);
} else {
//if it doesn't already exist, try creating it and if successfull move creature
newDataCell = Globals.dataCellManager.tryCreateGroundDataCell(EntityUtils.getPosition(entity));
//initialize server datacell tracking of this entity
Globals.dataCellManager.initializeServerSideEntity(entity, newDataCell);
}
}
//reposition entity
CollisionObjUtils.positionCharacter(entity, Globals.spawnPoint);
}
/**
* Called to reposition the creature
* @param entity
* @param position
*/
public static void repositionEntity(Entity entity, Vector3d position){
//if server, get current server data cell
if(Globals.RUN_SERVER){
ServerDataCell oldDataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(entity));
ServerDataCell newDataCell = Globals.dataCellManager.getDataCellAtPoint(position);
if(newDataCell != null){
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
} else {
//if it doesn't already exist, try creating it and if successfull move creature
newDataCell = Globals.dataCellManager.tryCreateGroundDataCell(EntityUtils.getPosition(entity));
if(newDataCell != null){
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
}
}
}
//reposition entity
CollisionObjUtils.positionCharacter(entity, Globals.spawnPoint);
}
}

View File

@ -261,7 +261,7 @@ public class AttackTree {
} else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructattackUpdateMessage(
parent.getId(),
Globals.entityManager.mapClientToServerId(parent.getId()),
System.currentTimeMillis(),
(float)position.x,
(float)position.y,
@ -383,7 +383,7 @@ public class AttackTree {
} else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructattackUpdateMessage(
parent.getId(),
Globals.entityManager.mapClientToServerId(parent.getId()),
System.currentTimeMillis(),
(float)position.x,
(float)position.y,
@ -434,7 +434,7 @@ public class AttackTree {
} else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructattackUpdateMessage(
parent.getId(),
Globals.entityManager.mapClientToServerId(parent.getId()),
System.currentTimeMillis(),
(float)position.x,
(float)position.y,

View File

@ -0,0 +1,72 @@
package electrosphere.entity.state.inventory;
import java.util.concurrent.CopyOnWriteArrayList;
import electrosphere.entity.Entity;
import electrosphere.entity.state.BehaviorTree;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.InventoryMessage;
/**
* Principally used to handle network messages related to inventory and thread synchronization
*/
public class InventoryState implements BehaviorTree {
CopyOnWriteArrayList<InventoryMessage> networkMessageQueue = new CopyOnWriteArrayList<InventoryMessage>();
Entity parent;
InventoryState() {
}
public static InventoryState createInventoryState(Entity parent){
InventoryState rVal = new InventoryState();
rVal.parent = parent;
Globals.entityManager.registerBehaviorTree(rVal);
return rVal;
}
@Override
public void simulate() {
if(Globals.RUN_SERVER){
for(InventoryMessage message : networkMessageQueue){
networkMessageQueue.remove(message);
switch(message.getMessageSubtype()){
case ADDITEMTOINVENTORY:
InventoryUtils.attemptStoreItem(parent, Globals.entityManager.getEntityFromId(message.getentityId()));
break;
case REMOVEITEMFROMINVENTORY:
InventoryUtils.attemptEjectItem(parent, Globals.entityManager.getEntityFromId(message.getentityId()));
break;
case EQUIPITEM:
break;
}
}
} else {
for(InventoryMessage message : networkMessageQueue){
networkMessageQueue.remove(message);
switch(message.getMessageSubtype()){
case ADDITEMTOINVENTORY:
//the ID we get is of the in-inventory item
Entity inInventorySpawnedItem = InventoryUtils.constructInInventoryItem(parent,message.getitemTemplate());
//map id
if(inInventorySpawnedItem != null){
Globals.entityManager.mapIdToId(inInventorySpawnedItem.getId(), message.getentityId());
}
break;
case REMOVEITEMFROMINVENTORY:
InventoryUtils.removeItemFromNaturalInventory(parent, Globals.entityManager.getEntityFromServerId(message.getentityId()));
break;
case EQUIPITEM:
break;
}
}
}
}
public void addNetworkMessage(InventoryMessage networkMessage) {
networkMessageQueue.add(networkMessage);
}
}

View File

@ -10,7 +10,13 @@ import electrosphere.entity.state.equip.EquipState;
import electrosphere.entity.state.gravity.GravityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.game.server.datacell.ServerDataCell;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.server.player.Player;
import electrosphere.util.Utilities;
public class InventoryUtils {
@ -31,11 +37,36 @@ public class InventoryUtils {
return (RelationalInventoryState)target.getData(EntityDataStrings.EQUIP_INVENTORY);
}
public static void attemptStoreItem(Entity creature, Entity item){
/**
* Gets the current inventory state
* @param target the entity to get inventory state from
* @return The inventory state behavior tree or null
*/
public static InventoryState getInventoryState(Entity target){
return (InventoryState)target.getData(EntityDataStrings.INVENTORY_STATE);
}
/**
* Sets the current inventory state
* @param target The entity to attach inventory state to
* @param state The inventory state to attach
*/
public static void setInventoryState(Entity target, InventoryState state){
target.putData(EntityDataStrings.INVENTORY_STATE, state);
}
/**
* Perform the entity transforms to actually store an item in an inventory, if server this has the side effect of also sending packets on success
* @param creature The creature to store the item in
* @param item The item to store
*/
public static void attemptStoreItemTransform(Entity creature, Entity item){
boolean creatureIsCreature = CreatureUtils.isCreature(creature);
boolean itemIsItem = ItemUtils.isItem(item);
boolean hasInventory = hasNaturalInventory(creature);
if(creatureIsCreature && itemIsItem && hasInventory){
//check if the item is already in an inventory
boolean itemIsInInventory = ItemUtils.itemIsInInventory(item);
if(creatureIsCreature && itemIsItem && hasInventory && !itemIsInInventory){
//get inventory
//for the moment we're just gonna get natural inventory
//later we'll need to search through all creature inventories to find the item
@ -47,17 +78,90 @@ public class InventoryUtils {
ItemUtils.destroyInWorldItem(item);
//store item in inventory
inventory.addItem(inventoryItem);
//if we are the server, immediately send required packets
if(Globals.RUN_SERVER){
ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(item));
dataCell.removeEntity(item);
//broadcast destroy entity
dataCell.broadcastNetworkMessage(EntityMessage.constructDestroyMessage(item.getId()));
//tell controlling player that they have an item in their inventory
if(CreatureUtils.hasControllerPlayerId(creature)){
//get the player
int controllerPlayerID = CreatureUtils.getControllerPlayerId(creature);
Player controllerPlayer = Globals.playerManager.getPlayerFromId(controllerPlayerID);
//send message
controllerPlayer.addMessage(InventoryMessage.constructaddItemToInventoryMessage(inventoryItem.getId(), ItemUtils.getType(inventoryItem)));
}
}
}
}
//need creature so we can figure out where to drop the item
public static void attemptEjectItem(Entity creature, Entity item){
/**
* Attempts to store the in-world item entity in a creature inventory container
* @param creature the creature which has a natural inventory
* @param item the in-world item entity to store
*/
public static void attemptStoreItem(Entity creature, Entity item){
if(Globals.RUN_SERVER){
//if we're the server, immediately attempt the transform
attemptStoreItemTransform(creature,item);
} else {
//if we're the client, tell the server we want to try the transform
NetworkMessage requestPickupMessage = InventoryMessage.constructaddItemToInventoryMessage(
Globals.entityManager.mapClientToServerId(item.getId()),
ItemUtils.getType(item)
);
Globals.clientConnection.queueOutgoingMessage(requestPickupMessage);
}
}
/**
* [CLIENT ONLY] Places an item of provided type in the parent container's natural inventory
* @param parentContainer The entity (typically a creature) which will receive the item in their natural inventory
* @param type The type of item to place in the inventory
* @return The in-inventory item entity
*/
public static Entity constructInInventoryItem(Entity parentContainer, String type){
//sanity checks
boolean creatureIsCreature = CreatureUtils.isCreature(parentContainer);
boolean hasInventory = hasNaturalInventory(parentContainer);
if(creatureIsCreature && hasInventory){
//if we pass sanity checks, actually perform transform
//get inventory
//for the moment we're just gonna get natural inventory
//later we'll need to search through all creature inventories to find the item
UnrelationalInventoryState inventory = getNaturalInventory(parentContainer);
//create item
//TODO: optimize by directly creating the container item instead of first spawning regular item
Entity spawnedItem = ItemUtils.spawnBasicItem(type);
//convert to in-inventory
Entity inventoryItem = ItemUtils.recreateContainerItem(spawnedItem);
//destroy the item that was left over
ItemUtils.destroyInWorldItem(spawnedItem);
//store item in inventory
inventory.addItem(inventoryItem);
//return
return inventoryItem;
}
//if we fail, return null
return null;
}
/**
* Attempts the transform to eject an item from an inventory, if this is the server it has added side effect of sending packets on success
* @param creature The creature to eject the item from
* @param item The item to eject
*/
public static void attemptEjectItemTransform(Entity creature, Entity item){
//verify creature is creature, item is item, inventory exists, and item is in inventory
boolean creatureIsCreature = CreatureUtils.isCreature(creature);
boolean itemIsItem = ItemUtils.isItem(item);
boolean hasNaturalInventory = hasNaturalInventory(creature);
boolean hasEquipInventory = hasEquipInventory(creature);
if(creatureIsCreature && itemIsItem){
//check if the item is in an inventory
boolean itemIsInInventory = ItemUtils.itemIsInInventory(item);
if(creatureIsCreature && itemIsItem && itemIsInInventory){
if(hasNaturalInventory){
//get inventory
UnrelationalInventoryState inventory = getNaturalInventory(creature);
@ -77,6 +181,17 @@ public class InventoryUtils {
//remove item from inventory
inventory.tryRemoveItem(item);
}
//if server, tell player that the item is no longer in their inventory
if(Globals.RUN_SERVER){
//if the entity is a player entity
if(CreatureUtils.hasControllerPlayerId(creature)){
//get player
int playerId = CreatureUtils.getControllerPlayerId(creature);
Player controllerPlayer = Globals.playerManager.getPlayerFromId(playerId);
//tell the player they don't have the item anymore
controllerPlayer.addMessage(InventoryMessage.constructremoveItemFromInventoryMessage(item.getId()));
}
}
//compose item into in-world entity
Entity inWorldItem = ItemUtils.spawnBasicItem(ItemUtils.getType(item));
//delete in container item
@ -87,6 +202,62 @@ public class InventoryUtils {
EntityUtils.getPosition(inWorldItem).set(dropSpot);
//activate gravity
GravityUtils.attemptActivateGravity(inWorldItem);
//if server, add the item to closest data cell
if(Globals.RUN_SERVER){
//get closest chunk
ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(dropSpot);
//add item
Globals.dataCellManager.initializeServerSideEntity(inWorldItem, dataCell);
}
}
}
//need creature so we can figure out where to drop the item
public static void attemptEjectItem(Entity creature, Entity item){
if(Globals.RUN_SERVER){
//if we're the server, immediately attempt the transform
attemptEjectItemTransform(creature,item);
} else {
//if we're the client, tell the server we want to try the transform
NetworkMessage requestPickupMessage = InventoryMessage.constructremoveItemFromInventoryMessage(Globals.entityManager.mapClientToServerId(item.getId()));
Globals.clientConnection.queueOutgoingMessage(requestPickupMessage);
}
}
/**
* [CLIENT ONLY] Called when the server says to remove an item from natural inventory
* Only does the remove, doesn't create the in-world item
* @param creature The creature to remove the item from (likely to be player entity)
* @param item The item to remove
*/
public static void removeItemFromNaturalInventory(Entity creature, Entity item){
//verify creature is creature, item is item, inventory exists, and item is in inventory
boolean creatureIsCreature = CreatureUtils.isCreature(creature);
boolean itemIsItem = ItemUtils.isItem(item);
boolean hasNaturalInventory = hasNaturalInventory(creature);
boolean hasEquipInventory = hasEquipInventory(creature);
//check if the item is in an inventory
boolean itemIsInInventory = ItemUtils.itemIsInInventory(item);
if(creatureIsCreature && itemIsItem && itemIsInInventory){
if(hasNaturalInventory){
//get inventory
UnrelationalInventoryState inventory = getNaturalInventory(creature);
//remove item from inventory
inventory.removeItem(item);
}
if(hasEquipInventory){
//get inventory
RelationalInventoryState inventory = getEquipInventory(creature);
//get real world item
Entity realWorldItem = ItemUtils.getRealWorldEntity(item);
if(realWorldItem != null){
//drop item
EquipState equipState = (EquipState)creature.getData(EntityDataStrings.EQUIP_STATE);
equipState.unequipPoint(inventory.getItemSlot(item));
}
//remove item from inventory
inventory.tryRemoveItem(item);
}
}
}

View File

@ -31,8 +31,13 @@ public class UnrelationalInventoryState {
items.add(item);
}
public void removeItem(Entity item){
items.remove(item);
/**
* Removes an item from the inventory
* @param item the item to attempt to remove
* @return true if an item was removed, false otherwise
*/
public boolean removeItem(Entity item){
return items.remove(item);
}
public List<Entity> getItems(){

View File

@ -17,6 +17,8 @@ import electrosphere.entity.state.IdleTree;
import electrosphere.entity.state.collidable.CollidableTree;
import electrosphere.entity.state.equip.EquipState;
import electrosphere.entity.state.gravity.GravityTree;
import electrosphere.entity.state.inventory.InventoryState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.entity.types.collision.CollisionObjUtils;
@ -282,11 +284,12 @@ public class CreatureUtils {
// rVal.putData(EntityDataStrings.EQUIP_STATE, new EquipState(rVal,"MiddleLower.R"));
break;
case "INVENTORY":
rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10));
break;
rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10));
InventoryUtils.setInventoryState(rVal, InventoryState.createInventoryState(rVal));
break;
case "OUTLINE":
rVal.putData(EntityDataStrings.DRAW_OUTLINE, true);
break;
rVal.putData(EntityDataStrings.DRAW_OUTLINE, true);
break;
}
}
//variants
@ -496,72 +499,6 @@ public class CreatureUtils {
public static CreatureTemplate getCreatureTemplate(Entity e){
return (CreatureTemplate)e.getData(EntityDataStrings.CREATURE_TEMPLATE);
}
/**
* Called when the creature is first spawned to serialize to all people in its initial chunk
* @param creature
* @param position
*/
public static void initiallyPositionCreature(Entity creature, Vector3d position){
//if server, get current server data cell
if(Globals.RUN_SERVER){
ServerDataCell oldDataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(creature));
ServerDataCell newDataCell = Globals.dataCellManager.getDataCellAtPoint(position);
if(newDataCell != null){
newDataCell.addEntity(creature);
if(oldDataCell != null && oldDataCell != newDataCell){
oldDataCell.removeEntity(creature);
}
newDataCell.initializeEntityForNewPlayers(creature, null);
} else {
//if it doesn't already exist, try creating it and if successfull move creature
newDataCell = Globals.dataCellManager.tryCreateGroundDataCell(EntityUtils.getPosition(creature));
if(newDataCell != null){
newDataCell.addEntity(creature);
if(oldDataCell != null && oldDataCell != newDataCell){
oldDataCell.removeEntity(creature);
}
newDataCell.initializeEntityForNewPlayers(creature, null);
}
}
}
//reposition entity
// CreatureUtils.repositionCreature(creature, Globals.spawnPoint);
CollisionObjUtils.positionCharacter(creature, Globals.spawnPoint);
}
/**
* Called to reposition the creature
* @param creature
* @param position
*/
public static void repositionCreature(Entity creature, Vector3d position){
//if server, get current server data cell
if(Globals.RUN_SERVER){
ServerDataCell oldDataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(creature));
ServerDataCell newDataCell = Globals.dataCellManager.getDataCellAtPoint(position);
if(newDataCell != null){
newDataCell.addEntity(creature);
if(oldDataCell != null && oldDataCell != newDataCell){
oldDataCell.removeEntity(creature);
}
newDataCell.initializeEntityForNewPlayers(creature, oldDataCell);
} else {
//if it doesn't already exist, try creating it and if successfull move creature
newDataCell = Globals.dataCellManager.tryCreateGroundDataCell(EntityUtils.getPosition(creature));
if(newDataCell != null){
newDataCell.addEntity(creature);
if(oldDataCell != null && oldDataCell != newDataCell){
oldDataCell.removeEntity(creature);
}
newDataCell.initializeEntityForNewPlayers(creature, oldDataCell);
}
}
}
//reposition entity
// CreatureUtils.repositionCreature(creature, Globals.spawnPoint);
CollisionObjUtils.positionCharacter(creature, Globals.spawnPoint);
}
}

View File

@ -153,6 +153,7 @@ public class ItemUtils {
}
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
rVal.putData(EntityDataStrings.ITEM_IS_ITEM, true);
rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, false);
rVal.putData(EntityDataStrings.ITEM_TYPE, 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)));
@ -199,17 +200,14 @@ public class ItemUtils {
int id = item.getId();
String type = ItemUtils.getType(item);
Vector3d position = EntityUtils.getPosition(item);
NetworkMessage message = EntityMessage.constructCreateMessage(id, EntityDataStrings.ENTITY_CATEGORY_ITEM, type, (float)position.x, (float)position.y, (float)position.z);
//construct the spawn message and attach to player
NetworkMessage message = EntityMessage.constructSpawnItemMessage(
id,
type,
position.x,
position.y,
position.z);
player.addMessage(message);
if(AttachUtils.isAttached(item)){
player.addMessage(
EntityMessage.constructattachEntityToEntityMessage(
item.getId(),
AttachUtils.getTargetBone(item),
AttachUtils.getParent(item).getId()
)
);
}
}
public static boolean isItem(Entity item){
@ -236,6 +234,15 @@ public class ItemUtils {
return (List<EquipWhitelist>)item.getData(EntityDataStrings.ITEM_EQUIP_WHITELIST);
}
/**
* Checks if the item is inside an inventory container
* @param item The item entity to check
* @return true if the item IS in an inventory container, otherwise false
*/
public static boolean itemIsInInventory(Entity item){
return (boolean)item.getData(EntityDataStrings.ITEM_IS_IN_INVENTORY);
}
/**
* Emits an entity which represents the item inside a container
*/
@ -248,6 +255,7 @@ public class ItemUtils {
rVal.putData(EntityDataStrings.ITEM_ICON,ItemUtils.getItemIcon(item));
rVal.putData(EntityDataStrings.ITEM_EQUIP_CLASS, item.getData(EntityDataStrings.ITEM_EQUIP_CLASS));
rVal.putData(EntityDataStrings.ITEM_IS_ITEM, true);
rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, true);
rVal.putData(EntityDataStrings.ITEM_TYPE, item.getData(EntityDataStrings.ITEM_TYPE));
Globals.entityManager.registerEntity(rVal);
return rVal;

View File

@ -181,5 +181,19 @@ public class DataCellManager {
}
/**
* If we're spawning an entity for the first time, call this method with the cell you want it to start in.
* It adds the entity to the given cell and initializes it for all players in said cell
* @param entity The entity we are initializing
* @param cell The cell we are wanting to initialize the entity in
*/
public void initializeServerSideEntity(Entity entity, ServerDataCell cell){
//add the entity to the cell
cell.addEntity(entity);
//send the entity to all players
cell.initializeEntityForNewPlayers(entity, null);
}
}

View File

@ -8,6 +8,7 @@ import electrosphere.game.server.character.Character;
import electrosphere.game.server.pathfinding.NavMeshUtils;
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.server.player.Player;
@ -89,7 +90,7 @@ public class ServerDataCell {
* This should be used to translate an entity from one data cell to another.
* @param e
*/
public void addEntity(Entity e){
protected void addEntity(Entity e){
loadedEntities.add(e);
}
@ -126,10 +127,10 @@ public class ServerDataCell {
for(Player player : this.activePlayers){
if(previousCell != null){
if(!previousCell.containsPlayer(player)){
CreatureUtils.sendEntityToPlayer(player, creature);
serializeEntityToPlayer(creature,player);
}
} else {
CreatureUtils.sendEntityToPlayer(player, creature);
serializeEntityToPlayer(creature,player);
}
}
}
@ -141,18 +142,27 @@ public class ServerDataCell {
void serializeStateToPlayer(Player player){
if(player != Globals.clientPlayer){
for(Entity entity : loadedEntities){
if(CreatureUtils.isCreature(entity)){
CreatureUtils.sendEntityToPlayer(player, entity);
}
if(ItemUtils.isItem(entity)){
ItemUtils.sendEntityToPlayer(player, entity);
}
if(StructureUtils.isStructure(entity)){
StructureUtils.sendStructureToPlayer(player, entity);
}
serializeEntityToPlayer(entity,player);
}
}
}
/**
* Serializes an entity to a given player
* @param entity The entity to serialize
* @param player The player to send the entity to
*/
void serializeEntityToPlayer(Entity entity, Player player){
if(CreatureUtils.isCreature(entity)){
CreatureUtils.sendEntityToPlayer(player, entity);
}
if(ItemUtils.isItem(entity)){
ItemUtils.sendEntityToPlayer(player, entity);
}
if(StructureUtils.isStructure(entity)){
StructureUtils.sendStructureToPlayer(player, entity);
}
}
/**
@ -161,5 +171,43 @@ public class ServerDataCell {
public boolean containsPlayer(Player player){
return activePlayers.contains(player);
}
/**
* Moves an entity from one datacell to another. This implicitly destroys the entity on player connections that would no longer
* observe said entity (IE it sends destroy packets). It also initializes the entity for players that would not have already been
* tracking the entity
* @param entity The entity to move
* @param oldCell The old datacell it used to be in
* @param newCell The new datacell it's moving to
*/
public static void moveEntityFromCellToCell(Entity entity, ServerDataCell oldCell, ServerDataCell newCell){
//swap which holds the entity
if(oldCell != null){
oldCell.removeEntity(entity);
}
newCell.addEntity(entity);
//send the entity to new players that should care about it
for(Player player : newCell.activePlayers){
if(oldCell != null){
//if the player hasn't already seen the entity, serialize it
if(!oldCell.containsPlayer(player)){
newCell.serializeEntityToPlayer(entity, player);
}
} else {
//if the entity wasn't in a previous cell, send it to all players
newCell.serializeEntityToPlayer(entity, player);
}
}
//delete the entity for players that dont care about it
if(oldCell != null){
for(Player player : oldCell.activePlayers){
if(!newCell.containsPlayer(player)){
//if the player isn't also in the new cell, delete the entity
player.addMessage(EntityMessage.constructDestroyMessage(entity.getId()));
}
}
}
}
}

View File

@ -24,7 +24,7 @@ public class LoggerInterface {
loggerFileIO = new Logger(LogLevel.WARNING);
loggerGameLogic = new Logger(LogLevel.WARNING);
loggerRenderer = new Logger(LogLevel.WARNING);
loggerEngine = new Logger(LogLevel.WARNING);
loggerEngine = new Logger(LogLevel.DEBUG);
loggerAuth = new Logger(LogLevel.INFO);
loggerStartup.INFO("Initialized loggers");
}

View File

@ -12,6 +12,7 @@ import electrosphere.main.Main;
import electrosphere.net.parser.net.message.AuthMessage;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.LoreMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.parser.net.message.PlayerMessage;
@ -49,6 +50,9 @@ public class ClientProtocol {
case CHARACTER_MESSAGE:
CharacterProtocol.handleCharacterMessage((CharacterMessage)message);
break;
case INVENTORY_MESSAGE:
InventoryProtocol.handleInventoryMessage((InventoryMessage)message);
break;
}
}

View File

@ -2,6 +2,7 @@ package electrosphere.net.client.protocol;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
@ -34,7 +35,7 @@ public class EntityProtocol {
newlySpawnedEntity = ItemUtils.spawnBasicItem(message.getentitySubtype());
EntityUtils.getScale(newlySpawnedEntity).set(0.005f);
EntityUtils.getPosition(newlySpawnedEntity).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
EntityUtils.setEntityID(newlySpawnedEntity, message.getentityID());
Globals.entityManager.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
break;
}
break;
@ -45,19 +46,30 @@ public class EntityProtocol {
newlySpawnedEntity = CreatureUtils.spawnBasicCreature(template.getCreatureType(),template);
EntityUtils.getScale(newlySpawnedEntity).set(0.005f);
EntityUtils.getPosition(newlySpawnedEntity).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
EntityUtils.setEntityID(newlySpawnedEntity, message.getentityID());
Globals.entityManager.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
}
break;
case SPAWNITEM:
if(!Globals.RUN_SERVER){
LoggerInterface.loggerNetworking.DEBUG("Spawn Item " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
//spawn item
String itemType = message.getcreatureTemplate();
newlySpawnedEntity = ItemUtils.spawnBasicItem(itemType);
//position
EntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()));
Globals.entityManager.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
}
break;
case DESTROY:
//only obey if we're not also the server
if(!Globals.RUN_SERVER){
Globals.entityManager.deregisterEntity(Globals.entityManager.getEntityFromId(message.getentityID()));
Globals.entityManager.deregisterEntity(Globals.entityManager.getEntityFromServerId(message.getentityID()));
}
break;
case MOVE:
//literally just adding this to scope so I can use `` Entity target; `` again
if(message.getentityID() != -1){
Entity target = Globals.entityManager.getEntityFromId(message.getentityID());
Entity target = Globals.entityManager.getEntityFromServerId(message.getentityID());
LoggerInterface.loggerNetworking.DEBUG("ID: " + message.getentityID());
if(target != null){
EntityUtils.getPosition(target).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
@ -69,7 +81,7 @@ public class EntityProtocol {
break;
case SETPROPERTY:
if(message.getpropertyType()== 0){
Entity target = Globals.entityManager.getEntityFromId(message.getentityID());
Entity target = Globals.entityManager.getEntityFromServerId(message.getentityID());
if(target != null){
CreatureUtils.setControllerPlayerId(target, message.getpropertyValue());
if(Globals.clientPlayer != null && message.getpropertyValue() == Globals.clientPlayer.getId()){
@ -80,18 +92,18 @@ public class EntityProtocol {
}
break;
case ATTACHENTITYTOENTITY:
Entity child = Globals.entityManager.getEntityFromId(message.getentityID());
Entity parent = Globals.entityManager.getEntityFromId(message.gettargetID());
Entity child = Globals.entityManager.getEntityFromServerId(message.getentityID());
Entity parent = Globals.entityManager.getEntityFromServerId(message.gettargetID());
LoggerInterface.loggerNetworking.DEBUG("Attach " + message.getentityID() + " to " + message.gettargetID() + " on bone " + message.getbone());
if(child != null && parent != null){
AttachUtils.attachEntityToEntityAtBone(parent, child, message.getbone(), new Quaternionf());
}
break;
case MOVEUPDATE:
CreatureUtils.attachEntityMessageToMovementTree(Globals.entityManager.getEntityFromId(message.getentityID()),message);
CreatureUtils.attachEntityMessageToMovementTree(Globals.entityManager.getEntityFromServerId(message.getentityID()),message);
break;
case ATTACKUPDATE:
CreatureUtils.attachEntityMessageToAttackTree(Globals.entityManager.getEntityFromId(message.getentityID()),message);
CreatureUtils.attachEntityMessageToAttackTree(Globals.entityManager.getEntityFromServerId(message.getentityID()),message);
break;
case KILL:
break;

View File

@ -0,0 +1,35 @@
package electrosphere.net.client.protocol;
import electrosphere.entity.Entity;
import electrosphere.entity.state.inventory.InventoryState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.InventoryMessage;
public class InventoryProtocol {
protected static void handleInventoryMessage(InventoryMessage message){
switch(message.getMessageSubtype()){
case ADDITEMTOINVENTORY:
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] ADD ITEM TO INVENTORY " + message.getentityId());
if(Globals.playerEntity != null){
InventoryState inventoryState;
if((inventoryState = InventoryUtils.getInventoryState(Globals.playerEntity))!=null){
inventoryState.addNetworkMessage(message);
}
}
break;
case EQUIPITEM:
break;
case REMOVEITEMFROMINVENTORY:
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] REMOVE ITEM FROM INVENTORY " + message.getentityId());
if(Globals.playerEntity != null){
InventoryState inventoryState;
if((inventoryState = InventoryUtils.getInventoryState(Globals.playerEntity))!=null){
inventoryState.addNetworkMessage(message);
}
}
break;
}
}
}

View File

@ -9,6 +9,7 @@ public class EntityMessage extends NetworkMessage {
public enum EntityMessageType {
CREATE,
SPAWNCREATURE,
SPAWNITEM,
SETPOSITION,
SETFACING,
MOVEUPDATE,
@ -223,6 +224,8 @@ public class EntityMessage extends NetworkMessage {
return EntityMessage.canParseCreateMessage(byteStream);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNCREATURE:
return EntityMessage.canParseSpawnCreatureMessage(byteStream);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNITEM:
return EntityMessage.canParseSpawnItemMessage(byteStream);
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION:
if(byteStream.size() >= TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION_SIZE){
return true;
@ -394,6 +397,59 @@ public class EntityMessage extends NetworkMessage {
return rVal;
}
public static boolean canParseSpawnItemMessage(List<Byte> byteStream){
int currentStreamLength = byteStream.size();
List<Byte> temporaryByteQueue = new LinkedList();
if(currentStreamLength < 6){
return false;
}
int creatureTemplateSize = 0;
if(currentStreamLength < 10){
return false;
} else {
temporaryByteQueue.add(byteStream.get(6 + 0));
temporaryByteQueue.add(byteStream.get(6 + 1));
temporaryByteQueue.add(byteStream.get(6 + 2));
temporaryByteQueue.add(byteStream.get(6 + 3));
creatureTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 10 + creatureTemplateSize){
return false;
}
if(currentStreamLength < 14){
return false;
}
if(currentStreamLength < 22){
return false;
}
if(currentStreamLength < 30){
return false;
}
return true;
}
public static EntityMessage parseSpawnItemMessage(List<Byte> byteStream){
EntityMessage rVal = new EntityMessage(EntityMessageType.SPAWNITEM);
stripPacketHeader(byteStream);
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteStream));
rVal.setcreatureTemplate(ByteStreamUtils.popStringFromByteQueue(byteStream));
rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteStream));
rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteStream));
rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteStream));
return rVal;
}
public static EntityMessage constructSpawnItemMessage(int entityID,String creatureTemplate,double positionX,double positionY,double positionZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.SPAWNITEM);
rVal.setentityID(entityID);
rVal.setcreatureTemplate(creatureTemplate);
rVal.setpositionX(positionX);
rVal.setpositionY(positionY);
rVal.setpositionZ(positionZ);
rVal.serialize();
return rVal;
}
public static EntityMessage parseSetPositionMessage(List<Byte> byteStream){
EntityMessage rVal = new EntityMessage(EntityMessageType.SETPOSITION);
stripPacketHeader(byteStream);
@ -708,6 +764,37 @@ public class EntityMessage extends NetworkMessage {
rawBytes[26+creatureTemplate.length()+i] = intValues[i];
}
break;
case SPAWNITEM:
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_SPAWNITEM;
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 SETPOSITION:
rawBytes = new byte[2+4+8+8+8+8];
//message header

View File

@ -0,0 +1,245 @@
package electrosphere.net.parser.net.message;
import electrosphere.net.parser.util.ByteStreamUtils;
import java.util.LinkedList;
import java.util.List;
public class InventoryMessage extends NetworkMessage {
public enum InventoryMessageType {
ADDITEMTOINVENTORY,
REMOVEITEMFROMINVENTORY,
EQUIPITEM,
}
InventoryMessageType messageType;
String itemTemplate;
String equipPointId;
int entityId;
InventoryMessage(InventoryMessageType messageType){
this.type = MessageType.INVENTORY_MESSAGE;
this.messageType = messageType;
}
public InventoryMessageType getMessageSubtype(){
return this.messageType;
}
public String getitemTemplate() {
return itemTemplate;
}
public void setitemTemplate(String itemTemplate) {
this.itemTemplate = itemTemplate;
}
public String getequipPointId() {
return equipPointId;
}
public void setequipPointId(String equipPointId) {
this.equipPointId = equipPointId;
}
public int getentityId() {
return entityId;
}
public void setentityId(int entityId) {
this.entityId = entityId;
}
static void stripPacketHeader(List<Byte> byteStream){
byteStream.remove(0);
byteStream.remove(0);
}
public static boolean canParseMessage(List<Byte> byteStream, byte secondByte){
switch(secondByte){
case TypeBytes.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY:
return InventoryMessage.canParseaddItemToInventoryMessage(byteStream);
case TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY:
if(byteStream.size() >= TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY_SIZE){
return true;
} else {
return false;
}
case TypeBytes.INVENTORY_MESSAGE_TYPE_EQUIPITEM:
return InventoryMessage.canParseequipItemMessage(byteStream);
}
return false;
}
public static boolean canParseaddItemToInventoryMessage(List<Byte> byteStream){
int currentStreamLength = byteStream.size();
List<Byte> temporaryByteQueue = new LinkedList();
if(currentStreamLength < 6){
return false;
}
int itemTemplateSize = 0;
if(currentStreamLength < 10){
return false;
} else {
temporaryByteQueue.add(byteStream.get(6 + 0));
temporaryByteQueue.add(byteStream.get(6 + 1));
temporaryByteQueue.add(byteStream.get(6 + 2));
temporaryByteQueue.add(byteStream.get(6 + 3));
itemTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 10 + itemTemplateSize){
return false;
}
return true;
}
public static InventoryMessage parseaddItemToInventoryMessage(List<Byte> byteStream){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
stripPacketHeader(byteStream);
rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteStream));
rVal.setitemTemplate(ByteStreamUtils.popStringFromByteQueue(byteStream));
return rVal;
}
public static InventoryMessage constructaddItemToInventoryMessage(int entityId,String itemTemplate){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
rVal.setentityId(entityId);
rVal.setitemTemplate(itemTemplate);
rVal.serialize();
return rVal;
}
public static InventoryMessage parseremoveItemFromInventoryMessage(List<Byte> byteStream){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
stripPacketHeader(byteStream);
rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteStream));
return rVal;
}
public static InventoryMessage constructremoveItemFromInventoryMessage(int entityId){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
rVal.setentityId(entityId);
rVal.serialize();
return rVal;
}
public static boolean canParseequipItemMessage(List<Byte> byteStream){
int currentStreamLength = byteStream.size();
List<Byte> temporaryByteQueue = new LinkedList();
int equipPointIdSize = 0;
if(currentStreamLength < 6){
return false;
} else {
temporaryByteQueue.add(byteStream.get(2 + 0));
temporaryByteQueue.add(byteStream.get(2 + 1));
temporaryByteQueue.add(byteStream.get(2 + 2));
temporaryByteQueue.add(byteStream.get(2 + 3));
equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 6 + equipPointIdSize){
return false;
}
if(currentStreamLength < 6){
return false;
}
int itemTemplateSize = 0;
if(currentStreamLength < 10){
return false;
} else {
temporaryByteQueue.add(byteStream.get(6 + 0));
temporaryByteQueue.add(byteStream.get(6 + 1));
temporaryByteQueue.add(byteStream.get(6 + 2));
temporaryByteQueue.add(byteStream.get(6 + 3));
itemTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 10 + itemTemplateSize){
return false;
}
return true;
}
public static InventoryMessage parseequipItemMessage(List<Byte> byteStream){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.EQUIPITEM);
stripPacketHeader(byteStream);
rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteStream));
rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteStream));
rVal.setitemTemplate(ByteStreamUtils.popStringFromByteQueue(byteStream));
return rVal;
}
public static InventoryMessage constructequipItemMessage(String equipPointId,int entityId,String itemTemplate){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.EQUIPITEM);
rVal.setequipPointId(equipPointId);
rVal.setentityId(entityId);
rVal.setitemTemplate(itemTemplate);
rVal.serialize();
return rVal;
}
@Override
void serialize(){
byte[] intValues = new byte[8];
byte[] stringBytes;
switch(this.messageType){
case ADDITEMTOINVENTORY:
rawBytes = new byte[2+4+4+itemTemplate.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
//entity messaage header
rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY;
intValues = ByteStreamUtils.serializeIntToBytes(entityId);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(itemTemplate.length());
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
stringBytes = itemTemplate.getBytes();
for(int i = 0; i < itemTemplate.length(); i++){
rawBytes[10+i] = stringBytes[i];
}
break;
case REMOVEITEMFROMINVENTORY:
rawBytes = new byte[2+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
//entity messaage header
rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY;
intValues = ByteStreamUtils.serializeIntToBytes(entityId);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
break;
case EQUIPITEM:
rawBytes = new byte[2+4+equipPointId.length()+4+4+itemTemplate.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
//entity messaage header
rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_EQUIPITEM;
intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
stringBytes = equipPointId.getBytes();
for(int i = 0; i < equipPointId.length(); i++){
rawBytes[6+i] = stringBytes[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(entityId);
for(int i = 0; i < 4; i++){
rawBytes[6+equipPointId.length()+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(itemTemplate.length());
for(int i = 0; i < 4; i++){
rawBytes[10+equipPointId.length()+i] = intValues[i];
}
stringBytes = itemTemplate.getBytes();
for(int i = 0; i < itemTemplate.length(); i++){
rawBytes[14+equipPointId.length()+i] = stringBytes[i];
}
break;
}
serialized = true;
}
}

View File

@ -13,6 +13,7 @@ TERRAIN_MESSAGE,
SERVER_MESSAGE,
AUTH_MESSAGE,
CHARACTER_MESSAGE,
INVENTORY_MESSAGE,
}
MessageType type;
@ -47,6 +48,11 @@ CHARACTER_MESSAGE,
rVal = EntityMessage.parseSpawnCreatureMessage(byteStream);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNITEM:
if(EntityMessage.canParseMessage(byteStream,secondByte)){
rVal = EntityMessage.parseSpawnItemMessage(byteStream);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_SETPOSITION:
if(EntityMessage.canParseMessage(byteStream,secondByte)){
rVal = EntityMessage.parseSetPositionMessage(byteStream);
@ -274,6 +280,26 @@ CHARACTER_MESSAGE,
break;
}
break;
case TypeBytes.MESSAGE_TYPE_INVENTORY:
secondByte = byteStream.get(1);
switch(secondByte){
case TypeBytes.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY:
if(InventoryMessage.canParseMessage(byteStream,secondByte)){
rVal = InventoryMessage.parseaddItemToInventoryMessage(byteStream);
}
break;
case TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY:
if(InventoryMessage.canParseMessage(byteStream,secondByte)){
rVal = InventoryMessage.parseremoveItemFromInventoryMessage(byteStream);
}
break;
case TypeBytes.INVENTORY_MESSAGE_TYPE_EQUIPITEM:
if(InventoryMessage.canParseMessage(byteStream,secondByte)){
rVal = InventoryMessage.parseequipItemMessage(byteStream);
}
break;
}
break;
}
}
return rVal;

View File

@ -12,21 +12,23 @@ Message categories
public static final byte MESSAGE_TYPE_SERVER = 4;
public static final byte MESSAGE_TYPE_AUTH = 5;
public static final byte MESSAGE_TYPE_CHARACTER = 6;
public static final byte MESSAGE_TYPE_INVENTORY = 7;
/*
Entity subcategories
*/
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_SETPOSITION = 2;
public static final byte ENTITY_MESSAGE_TYPE_SETFACING = 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_MOVE = 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_SETBEHAVIORTREE = 9;
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY = 10;
public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 11;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNITEM = 2;
public static final byte ENTITY_MESSAGE_TYPE_SETPOSITION = 3;
public static final byte ENTITY_MESSAGE_TYPE_SETFACING = 4;
public static final byte ENTITY_MESSAGE_TYPE_MOVEUPDATE = 5;
public static final byte ENTITY_MESSAGE_TYPE_ATTACKUPDATE = 6;
public static final byte ENTITY_MESSAGE_TYPE_MOVE = 7;
public static final byte ENTITY_MESSAGE_TYPE_KILL = 8;
public static final byte ENTITY_MESSAGE_TYPE_DESTROY = 9;
public static final byte ENTITY_MESSAGE_TYPE_SETBEHAVIORTREE = 10;
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY = 11;
public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 12;
/*
Entity packet sizes
*/
@ -125,5 +127,15 @@ Message categories
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS_SIZE = 2;
public static final byte CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE_SIZE = 2;
public static final byte CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE = 2;
/*
Inventory subcategories
*/
public static final byte INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY = 0;
public static final byte INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY = 1;
public static final byte INVENTORY_MESSAGE_TYPE_EQUIPITEM = 2;
/*
Inventory packet sizes
*/
public static final byte INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY_SIZE = 6;
}

View File

@ -219,6 +219,13 @@ public class ServerConnectionHandler implements Runnable {
break;
}
break;
case INVENTORY_MESSAGE:
if(isServerClient()){
//basically don't send the message if this is the player that is also hosting the game
} else {
networkParser.addOutgoingMessage(message);
}
break;
default:
networkParser.addOutgoingMessage(message);
break;

View File

@ -4,6 +4,7 @@ import org.joml.Vector3d;
import org.joml.Vector3f;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.ironsight.IronSightTree;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureTemplate;
@ -54,7 +55,7 @@ public class CharacterProtocol {
Entity newPlayerEntity = CreatureUtils.spawnBasicCreature(raceName,template);
int playerCharacterId = newPlayerEntity.getId();
connectionHandler.setPlayerCharacterId(playerCharacterId);
CreatureUtils.initiallyPositionCreature(newPlayerEntity, new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z));
EntityUtils.initiallyPositionEntity(newPlayerEntity, new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z));
CreatureUtils.setControllerPlayerId(newPlayerEntity, connectionHandler.getPlayerId());
//attach player object to player character
playerObject.setPlayerEntity(newPlayerEntity);

View File

@ -50,53 +50,5 @@ public class EntityProtocol {
break;
}
}
@Deprecated
void queueChunkState(ServerConnectionHandler connectionHandler){
//queue messages for that chunk
if(Globals.RUN_SERVER && Globals.clientPlayer == null){
} else {
for(Entity currentEntity : Globals.entityManager.getMoveable()){
connectionHandler.addMessagetoOutgoingQueue(
EntityMessage.constructCreateMessage(
currentEntity.getId(),
0, //0 for creatures
CreatureUtils.getType(currentEntity),
EntityUtils.getPosition(currentEntity).x,
EntityUtils.getPosition(currentEntity).y,
EntityUtils.getPosition(currentEntity).z
)
);
if(CreatureUtils.isCreature(currentEntity)){
if(CreatureUtils.hasControllerPlayerId(currentEntity)){
LoggerInterface.loggerNetworking.INFO("Sending controller packets");
connectionHandler.addMessagetoOutgoingQueue(NetUtils.createSetCreatureControllerIdEntityMessage(currentEntity));
}
}
}
for(Entity currentEntity : Globals.entityManager.getItemEntities()){
connectionHandler.addMessagetoOutgoingQueue(
EntityMessage.constructCreateMessage(
currentEntity.getId(),
1, //1 for items
ItemUtils.getType(currentEntity),
EntityUtils.getPosition(currentEntity).x,
EntityUtils.getPosition(currentEntity).y,
EntityUtils.getPosition(currentEntity).z
)
);
if(AttachUtils.isAttached(currentEntity)){
connectionHandler.addMessagetoOutgoingQueue(
EntityMessage.constructattachEntityToEntityMessage(
currentEntity.getId(),
AttachUtils.getTargetBone(currentEntity),
AttachUtils.getParent(currentEntity).getId()
)
);
}
}
}
}
}

View File

@ -0,0 +1,34 @@
package electrosphere.net.server.protocol;
import electrosphere.entity.Entity;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.main.Globals;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.server.ServerConnectionHandler;
public class InventoryProtocol {
protected static void handleInventoryMessage(ServerConnectionHandler connectionHandler, InventoryMessage message){
Entity target;
switch(message.getMessageSubtype()){
case ADDITEMTOINVENTORY:
LoggerInterface.loggerNetworking.DEBUG("[SERVER] ADD ITEM TO INVENTORY " + message.getentityId());
target = Globals.entityManager.getEntityFromId(connectionHandler.getPlayerCharacterId());
if(InventoryUtils.hasNaturalInventory(target)){
InventoryUtils.getInventoryState(target).addNetworkMessage(message);
}
break;
case REMOVEITEMFROMINVENTORY:
LoggerInterface.loggerNetworking.DEBUG("[SERVER] REMOVE ITEM FROM INVENTORY " + message.getentityId());
target = Globals.entityManager.getEntityFromId(connectionHandler.getPlayerCharacterId());
if(InventoryUtils.hasNaturalInventory(target)){
InventoryUtils.getInventoryState(target).addNetworkMessage(message);
}
break;
case EQUIPITEM:
break;
}
}
}

View File

@ -18,6 +18,7 @@ import electrosphere.net.NetUtils;
import electrosphere.net.parser.net.message.AuthMessage;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.LoreMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.parser.net.message.PlayerMessage;
@ -63,6 +64,9 @@ public class ServerProtocol {
case LORE_MESSAGE:
LoreProtocol.handleLoreMessage(connectionHandler, (LoreMessage)message);
break;
case INVENTORY_MESSAGE:
InventoryProtocol.handleInventoryMessage(connectionHandler, (InventoryMessage)message);
break;
}
}

View File

@ -12,7 +12,8 @@
"./net/terrain.json",
"./net/world.json",
"./net/server.json",
"./net/character.json"
"./net/character.json",
"./net/inventory.json"
]
}