equipped item serialization
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-08-09 21:05:27 -04:00
parent ff3914cc19
commit 9349b35596
18 changed files with 491 additions and 76 deletions

View File

@ -524,6 +524,15 @@ Math overhaul
- Engine defined origin, up, and left vectors
- Redo math for camera calculations
Rotate player models to face correct direction
Remove BLENDER_TRANSFORM token
Redo of creature-spawning logic to support including attached items
- Items do not necessarily send from server if they are in the scene! They must also not have a parent
Ability to serialize/deserialize a creature with equipped items
- Serialize
- Deserialize
- Send to client
- Receive from server
# TODO

View File

@ -120,6 +120,15 @@ public class ClientTerrainManager {
return terrainCache.containsChunkDataAtWorldPoint(worldX, worldY, worldZ);
}
/**
* Checks if the terrain cache contains chunk data at a given world position
* @param worldPos The vector containing the world-space position
* @return true if the data exists, false otherwise
*/
public boolean containsChunkDataAtWorldPoint(Vector3i worldPos){
return terrainCache.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z);
}
/**
* Checks that the cache contains chunk data at a real-space coordinate
* @param x the x coordinate

View File

@ -13,10 +13,15 @@ import electrosphere.entity.EntityUtils;
*/
public class ClientVoxelSampler {
/**
* Returned if a voxel is sampled from an invalid position
*/
public static final int INVALID_POSITION = -1;
/**
* Gets the voxel type beneath an entity
* @param entity The entity
* @return The voxel type
* @return The voxel type, INVALID_POSITION if the position queried is invalid
*/
public static int getVoxelTypeBeneathEntity(Entity entity){
return ClientVoxelSampler.getVoxelType(EntityUtils.getPosition(entity));
@ -25,13 +30,18 @@ public class ClientVoxelSampler {
/**
* Gets the voxel type at a given real-space position
* @param realPos The real-space position
* @return The voxel type id
* @return The voxel type id, INVALID_POSITION if the position queried is invalid
*/
public static int getVoxelType(Vector3d realPos){
int voxelId = 0;
Vector3i chunkSpacePos = Globals.clientWorldData.convertRealToWorldSpace(realPos);
Vector3i voxelSpacePos = Globals.clientWorldData.convertRealToVoxelSpace(realPos);
ChunkData chunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkSpacePos);
int voxelId = chunkData.getType(voxelSpacePos);
if(Globals.clientTerrainManager.containsChunkDataAtWorldPoint(chunkSpacePos)){
ChunkData chunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkSpacePos);
voxelId = chunkData.getType(voxelSpacePos);
} else {
return INVALID_POSITION;
}
return voxelId;
}

View File

@ -153,16 +153,16 @@ public class LoadingUtils {
//send default template back
String race = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().get(0);
CreatureData type = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(race);
CreatureTemplate template = new CreatureTemplate(race);
CreatureTemplate template = CreatureTemplate.create(race);
for(VisualAttribute attribute : type.getVisualAttributes()){
if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){
float min = attribute.getMinValue();
float max = attribute.getMaxValue();
float defaultValue = min + (max - min)/2.0f;
//add attribute to creature template
template.putValue(attribute.getAttributeId(), defaultValue);
template.putAttributeValue(attribute.getAttributeId(), defaultValue);
} else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){
template.putValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId());
template.putAttributeValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId());
}
}
//set player character template

View File

@ -106,7 +106,10 @@ public class ClientAttackTree implements BehaviorTree {
StateTransitionUtilItem.create(
AttackTreeState.WINDUP,
() -> {
TreeDataState state = currentMove.getWindupState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getWindupState();
}
if(state == null){
return null;
} else {
@ -114,7 +117,10 @@ public class ClientAttackTree implements BehaviorTree {
}
},
() -> {
TreeDataState state = currentMove.getWindupState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getWindupState();
}
if(state == null){
return null;
} else {
@ -126,7 +132,10 @@ public class ClientAttackTree implements BehaviorTree {
StateTransitionUtilItem.create(
AttackTreeState.HOLD,
() -> {
TreeDataState state = currentMove.getHoldState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getHoldState();
}
if(state == null){
return null;
} else {
@ -134,7 +143,10 @@ public class ClientAttackTree implements BehaviorTree {
}
},
() -> {
TreeDataState state = currentMove.getHoldState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getHoldState();
}
if(state == null){
return null;
} else {
@ -146,7 +158,10 @@ public class ClientAttackTree implements BehaviorTree {
StateTransitionUtilItem.create(
AttackTreeState.ATTACK,
() -> {
TreeDataState state = currentMove.getAttackState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getAttackState();
}
if(state == null){
return null;
} else {
@ -154,7 +169,10 @@ public class ClientAttackTree implements BehaviorTree {
}
},
() -> {
TreeDataState state = currentMove.getAttackState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getAttackState();
}
if(state == null){
return null;
} else {
@ -166,7 +184,10 @@ public class ClientAttackTree implements BehaviorTree {
StateTransitionUtilItem.create(
AttackTreeState.COOLDOWN,
() -> {
TreeDataState state = currentMove.getCooldownState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getCooldownState();
}
if(state == null){
return null;
} else {
@ -174,7 +195,10 @@ public class ClientAttackTree implements BehaviorTree {
}
},
() -> {
TreeDataState state = currentMove.getCooldownState();
TreeDataState state = null;
if(currentMove != null){
state = currentMove.getCooldownState();
}
if(state == null){
return null;
} else {

View File

@ -12,6 +12,7 @@ import org.ode4j.ode.DBody;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
@ -24,6 +25,7 @@ import electrosphere.entity.types.item.ItemUtils;
import electrosphere.game.data.common.TreeDataAnimation;
import electrosphere.game.data.creature.type.equip.EquipPoint;
import electrosphere.game.data.item.type.EquipWhitelist;
import electrosphere.game.data.item.type.Item;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
@ -165,6 +167,15 @@ public class ClientEquipState implements BehaviorTree {
}
} else {
//does not depend on the type of creature, must be attaching to a bone
//make sure it's visible
if(EntityUtils.getActor(toEquip) == null){
Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(ItemUtils.getType(toEquip));
EntityCreationUtils.makeEntityDrawable(toEquip, itemData.getModelPath());
if(itemData.getIdleAnim() != null){
toEquip.putData(EntityDataStrings.ANIM_IDLE,itemData.getIdleAnim());
}
}
//actually equip
equipMap.put(point.getEquipPointId(),toEquip);
if(parent != Globals.firstPersonEntity || Globals.controlHandler.cameraIsThirdPerson()){
AttachUtils.clientAttachEntityToEntityAtBone(

View File

@ -401,7 +401,7 @@ public class ServerEquipState implements BehaviorTree {
/**
* Gets whether an item is equipped at a point or not
* @param point THe point to check
* @param point The point to check
* @return true if an item is equipped at the point, false otherwise
*/
public boolean hasEquippedAtPoint(String point){

View File

@ -79,8 +79,9 @@ public class InventoryUtils {
* 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
* @return The in-inventory item
*/
public static void serverAttemptStoreItemTransform(Entity creature, Entity item){
public static Entity serverAttemptStoreItemTransform(Entity creature, Entity item){
boolean creatureIsCreature = CreatureUtils.isCreature(creature);
boolean itemIsItem = ItemUtils.isItem(item);
boolean hasInventory = hasNaturalInventory(creature);
@ -116,7 +117,9 @@ public class InventoryUtils {
ItemUtils.serverDestroyInWorldItem(item);
//alert script engine
ServerScriptUtils.fireSignalOnEntity(creature, "itemPickup", item.getId(), inventoryItem.getId());
return inventoryItem;
}
return null;
}
/**
@ -129,7 +132,7 @@ public class InventoryUtils {
NetworkMessage requestPickupMessage = InventoryMessage.constructaddItemToInventoryMessage(
Globals.clientSceneWrapper.mapClientToServerId(item.getId()),
ItemUtils.getType(item)
);
);
Globals.clientConnection.queueOutgoingMessage(requestPickupMessage);
}
@ -137,10 +140,11 @@ public class InventoryUtils {
* 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
* @return The in-inventory entity if it succeeded, null otherwise
*/
public static void serverAttemptStoreItem(Entity creature, Entity item){
public static Entity serverAttemptStoreItem(Entity creature, Entity item){
//immediately attempt the transform
serverAttemptStoreItemTransform(creature,item);
return serverAttemptStoreItemTransform(creature,item);
}
/**

View File

@ -7,6 +7,7 @@ import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.actor.Actor;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.ServerEntityTagUtils;
@ -181,7 +182,9 @@ public class AttachUtils {
//update entities attached to bones of other entities
for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){
Entity parent;
if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){
if(currentEntity == null){
LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Trying to update client bone attachment where null entity is registered!"));
} else if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){
clientUpdateEntityTransforms(currentEntity,parent);
} else if(currentEntity.getData(EntityDataStrings.ATTACH_TARGET_BASE)!=null){
Vector3d positionOffset = getVectorOffset(currentEntity);

View File

@ -0,0 +1,91 @@
package electrosphere.entity.types.creature;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Data on what a creature has equipped currently
*/
public class CreatureEquipData {
//Map of equip slot -> item definition
Map<String,EquippedItem> slotToItemMap = new HashMap<String,EquippedItem>();
/**
* Gets the slots in the equip data
* @return The set of equip slot ids
*/
public Set<String> getSlots(){
return slotToItemMap.keySet();
}
/**
* Gets the item occupying a given slot
* @param slotId The id of the slot
* @return The item definition
*/
public EquippedItem getSlotItem(String slotId){
return slotToItemMap.get(slotId);
}
/**
* Sets a slot as containing an item type
* @param slotId The slot
* @param itemType The item definition
*/
public void setSlotItem(String slotId, EquippedItem itemType){
slotToItemMap.put(slotId, itemType);
}
/**
* Clears the equip data
*/
public void clear(){
slotToItemMap.clear();
}
/**
* An item that is equipped
*/
public static class EquippedItem {
/**
* The type of the item
*/
String itemType;
/**
* The entity id of the item
*/
int entityId;
/**
* Constructor
* @param entityId The id of the item entity
* @param itemType The type of the item
*/
public EquippedItem(int entityId, String itemType){
this.entityId = entityId;
this.itemType = itemType;
}
/**
* The type of the item
* @return The type
*/
public String getItemType(){
return itemType;
}
/**
* The id of the entity that is this item
* @return The id
*/
public int getEntityId(){
return entityId;
}
}
}

View File

@ -3,58 +3,139 @@ package electrosphere.entity.types.creature;
import java.util.HashMap;
import java.util.Map;
/**
* The template used to construct the creature on the client
*/
public class CreatureTemplate {
/**
* The type of the creature
*/
String creatureType;
/**
* The attribute map for visual variants
*/
Map<String,CreatureTemplateAttributeValue> attributeMap = new HashMap<String,CreatureTemplateAttributeValue>();
public CreatureTemplate(String creatureType){
this.creatureType = creatureType;
/**
* The equip data for the creature
*/
private CreatureEquipData equipData = new CreatureEquipData();
/**
* Creates the creature template
* @param creatureType The type of creature
* @return The creature template
*/
public static CreatureTemplate create(String creatureType){
CreatureTemplate rVal = new CreatureTemplate();
rVal.creatureType = creatureType;
return rVal;
}
public void putValue(String attributeName, float value){
/**
* Puts an attribute value in the template
* @param attributeName The name of the attribute
* @param value The value of the attribute
*/
public void putAttributeValue(String attributeName, float value){
attributeMap.put(attributeName,new CreatureTemplateAttributeValue(value));
}
public void putValue(String attributeName, String value){
/**
* Puts an attribute value into the template
* @param attributeName The name of the attribute
* @param value The value of the attribute
*/
public void putAttributeValue(String attributeName, String value){
attributeMap.put(attributeName,new CreatureTemplateAttributeValue(value));
}
public CreatureTemplateAttributeValue getValue(String attributeName){
/**
* Gets the value of an attribte
* @param attributeName The name of the attribute
* @return The value of the attribute
*/
public CreatureTemplateAttributeValue getAttributeValue(String attributeName){
return attributeMap.get(attributeName);
}
/**
* Gets the type of the creature
* @return The type of the creature
*/
public String getCreatureType(){
return creatureType;
}
/**
* Gets the creature equip data for the template
* @return The creature equip data for the template
*/
public CreatureEquipData getCreatureEquipData(){
return this.equipData;
}
/**
* A visual attribute of a creature (ie how wide is their nose, what type of hairstyle do they have, etc)
*/
public class CreatureTemplateAttributeValue {
/**
* The string value of the attribute
*/
String variantId;
/**
* The float value of the attribute
*/
float value;
/**
* Creates a float attribute
* @param value The value
*/
public CreatureTemplateAttributeValue(float value){
this.value = value;
}
/**
* Creates a string attribute
* @param variantId The string
*/
public CreatureTemplateAttributeValue(String variantId){
this.variantId = variantId;
}
/**
* Gets the float value of the attribute
* @return The value
*/
public float getValue(){
return value;
}
/**
* Gets the string value of the attribute
* @return The string value
*/
public String getVariantId(){
return variantId;
}
/**
* Sets the float value of the attribute
* @param value The float value
*/
public void setValue(float value){
this.value = value;
}
/**
* Sets the string value of the attribute
* @param variantId The string value
*/
public void setVariantId(String variantId){
this.variantId = variantId;
}

View File

@ -45,6 +45,8 @@ import electrosphere.entity.state.rotator.RotatorHierarchyNode;
import electrosphere.entity.state.rotator.RotatorTree;
import electrosphere.entity.state.rotator.ServerRotatorTree;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.creature.type.CreatureData;
import electrosphere.game.data.creature.type.SprintSystem;
@ -66,12 +68,10 @@ import electrosphere.net.server.player.Player;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorBoneRotator;
import electrosphere.renderer.actor.ActorStaticMorph;
import electrosphere.renderer.actor.ActorUtils;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor;
import electrosphere.server.poseactor.PoseActorUtils;
import electrosphere.util.Utilities;
import electrosphere.util.math.MathUtils;
@ -248,7 +248,7 @@ public class CreatureUtils {
}
}
//variants
CreatureTemplate storedTemplate = new CreatureTemplate(rawType.getCreatureId());
CreatureTemplate storedTemplate = CreatureTemplate.create(rawType.getCreatureId());
if(rawType.getVisualAttributes() != null){
ActorStaticMorph staticMorph = null;
for(VisualAttribute attributeType : rawType.getVisualAttributes()){
@ -257,20 +257,20 @@ public class CreatureUtils {
AttributeVariant variant = attributeType.getVariants().get(0);
//if the template isn't null, try to find the variant from the template in the variant list
//if the variant is found, set the variable "variant" to the searched for variant
if(template != null && template.getValue(attributeType.getAttributeId()) != null){
String variantId = template.getValue(attributeType.getAttributeId()).getVariantId();
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null){
String variantId = template.getAttributeValue(attributeType.getAttributeId()).getVariantId();
for(AttributeVariant searchVariant : attributeType.getVariants()){
if(searchVariant.getId().equals(variantId)){
variant = searchVariant;
//if we find the variant, store in on-creature template as well
storedTemplate.putValue(attributeType.getAttributeId(), variantId);
storedTemplate.putAttributeValue(attributeType.getAttributeId(), variantId);
break;
}
}
}
//make sure stored template contains creature data
if(storedTemplate.getValue(attributeType.getAttributeId())==null){
storedTemplate.putValue(attributeType.getAttributeId(), attributeType.getVariants().get(0).getId());
if(storedTemplate.getAttributeValue(attributeType.getAttributeId())==null){
storedTemplate.putAttributeValue(attributeType.getAttributeId(), attributeType.getVariants().get(0).getId());
}
// attributeType.getAttributeId();
// variant.getId();
@ -289,25 +289,25 @@ public class CreatureUtils {
if(attributeType.getPrimaryBone() != null && staticMorph.getBoneTransforms(attributeType.getPrimaryBone()) == null){
staticMorph.initBoneTransforms(attributeType.getPrimaryBone());
//if the template isn't null, set the value of the morph
if(template != null && template.getValue(attributeType.getAttributeId()) != null){
float templateValue = template.getValue(attributeType.getAttributeId()).getValue();
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null){
float templateValue = template.getAttributeValue(attributeType.getAttributeId()).getValue();
staticMorph.updateValue(attributeType.getSubtype(), attributeType.getPrimaryBone(), templateValue);
}
}
if(attributeType.getMirrorBone() != null && staticMorph.getBoneTransforms(attributeType.getMirrorBone()) == null){
staticMorph.initBoneTransforms(attributeType.getMirrorBone());
//if the template isn't null, set the value of the morph
if(template != null && template.getValue(attributeType.getAttributeId()) != null){
float templateValue = template.getValue(attributeType.getAttributeId()).getValue();
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null){
float templateValue = template.getAttributeValue(attributeType.getAttributeId()).getValue();
staticMorph.updateValue(attributeType.getSubtype(), attributeType.getMirrorBone(), templateValue);
}
}
//make sure stored template contains creature data
if(template != null && template.getValue(attributeType.getAttributeId()) != null) {
storedTemplate.putValue(attributeType.getAttributeId(), template.getValue(attributeType.getAttributeId()).getValue());
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null) {
storedTemplate.putAttributeValue(attributeType.getAttributeId(), template.getAttributeValue(attributeType.getAttributeId()).getValue());
} else {
float midpoint = (attributeType.getMaxValue() - attributeType.getMinValue())/2.0f + attributeType.getMinValue();
storedTemplate.putValue(attributeType.getAttributeId(), midpoint);
storedTemplate.putAttributeValue(attributeType.getAttributeId(), midpoint);
}
}
}
@ -464,13 +464,31 @@ public class CreatureUtils {
break;
}
}
//
//
// EQUIP STATE
//
//
if(rawType.getEquipPoints() != null && rawType.getEquipPoints().size() > 0){
ServerEquipState.attachTree(rVal, rawType.getEquipPoints());
rVal.putData(EntityDataStrings.EQUIP_INVENTORY, RelationalInventoryState.buildRelationalInventoryStateFromEquipList(rawType.getEquipPoints()));
}
//
//
// BLOCK STATE
//
//
if(rawType.getBlockSystem() != null){
ServerBlockTree.attachTree(rVal, rawType.getBlockSystem());
}
//
//
// TOKENS
//
//
for(String token : rawType.getTokens()){
switch(token){
case "ATTACKER": {
@ -516,29 +534,27 @@ public class CreatureUtils {
}
}
//variants
CreatureTemplate storedTemplate = new CreatureTemplate(rawType.getCreatureId());
CreatureTemplate storedTemplate = CreatureTemplate.create(rawType.getCreatureId());
if(rawType.getVisualAttributes() != null){
ActorStaticMorph staticMorph = null;
for(VisualAttribute attributeType : rawType.getVisualAttributes()){
if(attributeType.getType().equals("remesh")){
if(attributeType.getVariants() != null && attributeType.getVariants().size() > 0){
AttributeVariant variant = attributeType.getVariants().get(0);
//if the template isn't null, try to find the variant from the template in the variant list
//if the variant is found, set the variable "variant" to the searched for variant
if(template != null && template.getValue(attributeType.getAttributeId()) != null){
String variantId = template.getValue(attributeType.getAttributeId()).getVariantId();
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null){
String variantId = template.getAttributeValue(attributeType.getAttributeId()).getVariantId();
for(AttributeVariant searchVariant : attributeType.getVariants()){
if(searchVariant.getId().equals(variantId)){
variant = searchVariant;
//if we find the variant, store in on-creature template as well
storedTemplate.putValue(attributeType.getAttributeId(), variantId);
storedTemplate.putAttributeValue(attributeType.getAttributeId(), variantId);
break;
}
}
}
//make sure stored template contains creature data
if(storedTemplate.getValue(attributeType.getAttributeId())==null){
storedTemplate.putValue(attributeType.getAttributeId(), attributeType.getVariants().get(0).getId());
if(storedTemplate.getAttributeValue(attributeType.getAttributeId())==null){
storedTemplate.putAttributeValue(attributeType.getAttributeId(), attributeType.getVariants().get(0).getId());
}
//TODO: determine if this should be relevant to pose actor
//pretty certain it shouldn't be but you never know
@ -558,25 +574,25 @@ public class CreatureUtils {
if(attributeType.getPrimaryBone() != null && staticMorph.getBoneTransforms(attributeType.getPrimaryBone()) == null){
staticMorph.initBoneTransforms(attributeType.getPrimaryBone());
//if the template isn't null, set the value of the morph
if(template != null && template.getValue(attributeType.getAttributeId()) != null){
float templateValue = template.getValue(attributeType.getAttributeId()).getValue();
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null){
float templateValue = template.getAttributeValue(attributeType.getAttributeId()).getValue();
staticMorph.updateValue(attributeType.getSubtype(), attributeType.getPrimaryBone(), templateValue);
}
}
if(attributeType.getMirrorBone() != null && staticMorph.getBoneTransforms(attributeType.getMirrorBone()) == null){
staticMorph.initBoneTransforms(attributeType.getMirrorBone());
//if the template isn't null, set the value of the morph
if(template != null && template.getValue(attributeType.getAttributeId()) != null){
float templateValue = template.getValue(attributeType.getAttributeId()).getValue();
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null){
float templateValue = template.getAttributeValue(attributeType.getAttributeId()).getValue();
staticMorph.updateValue(attributeType.getSubtype(), attributeType.getMirrorBone(), templateValue);
}
}
//make sure stored template contains creature data
if(template != null && template.getValue(attributeType.getAttributeId()) != null) {
storedTemplate.putValue(attributeType.getAttributeId(), template.getValue(attributeType.getAttributeId()).getValue());
if(template != null && template.getAttributeValue(attributeType.getAttributeId()) != null) {
storedTemplate.putAttributeValue(attributeType.getAttributeId(), template.getAttributeValue(attributeType.getAttributeId()).getValue());
} else {
float midpoint = (attributeType.getMaxValue() - attributeType.getMinValue())/2.0f + attributeType.getMinValue();
storedTemplate.putValue(attributeType.getAttributeId(), midpoint);
storedTemplate.putAttributeValue(attributeType.getAttributeId(), midpoint);
}
}
}
@ -642,7 +658,6 @@ public class CreatureUtils {
//The server initialization logic checks what type of entity this is, if this function is called prior to its type being stored
//the server will not be able to synchronize it properly.
ServerEntityUtils.initiallyPositionEntity(realm,rVal,position);
return rVal;
}
@ -677,9 +692,13 @@ public class CreatureUtils {
return rVal;
}
/**
* Gets the creature to the player
* @param player The player to send the creature to
* @param creature The creature entity
*/
public static void sendEntityToPlayer(Player player, Entity creature){
int id = creature.getId();
String type = CreatureUtils.getType(creature);
Vector3d position = EntityUtils.getPosition(creature);
String template = Utilities.stringify(CreatureUtils.getCreatureTemplate(creature));
NetworkMessage message = EntityMessage.constructSpawnCreatureMessage(
@ -688,7 +707,6 @@ public class CreatureUtils {
position.x,
position.y,
position.z);
// NetworkMessage message = EntityMessage.constructCreateMessage(id, EntityDataStrings.ENTITY_CATEGORY_CREATURE, type, (float)position.x, (float)position.y, (float)position.z);
player.addMessage(message);
if(CreatureUtils.hasControllerPlayerId(creature)){
LoggerInterface.loggerNetworking.INFO("Sending controller packets");
@ -811,8 +829,23 @@ public class CreatureUtils {
e.putData(EntityDataStrings.CREATURE_TEMPLATE, template);
}
/**
* Gets the template for the creature
* @param e The creature
* @return The template
*/
public static CreatureTemplate getCreatureTemplate(Entity e){
return (CreatureTemplate)e.getData(EntityDataStrings.CREATURE_TEMPLATE);
CreatureTemplate template = (CreatureTemplate)e.getData(EntityDataStrings.CREATURE_TEMPLATE);
if(ServerEquipState.hasEquipState(e)){
ServerEquipState serverEquipState = ServerEquipState.getEquipState(e);
CreatureEquipData equipData = template.getCreatureEquipData();
equipData.clear();
for(String point : serverEquipState.equippedPoints()){
Entity item = serverEquipState.getEquippedItemAtPoint(point);
equipData.setSlotItem(point, new EquippedItem(item.getId(),ItemUtils.getType(item)));
}
}
return template;
}

View File

@ -18,6 +18,7 @@ import electrosphere.entity.state.AnimationPriorities;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.item.type.EquipData;
import electrosphere.game.data.item.type.EquipWhitelist;
@ -27,7 +28,6 @@ import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.server.player.Player;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorUtils;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor;
@ -283,6 +283,34 @@ public class ItemUtils {
return (int)e.getData(EntityDataStrings.ENTITY_TYPE) == ENTITY_TYPE_ITEM;
}
/**
* Checks if an item should be sent to a client on synchronization
* @param item The item
* @return true if should be sent, false otherwise
*/
public static boolean itemShouldBeSentToClient(Entity item){
//if the item is attached to a creature, don't send a dedicated item
//instead, the creature template should include the item
if(AttachUtils.hasParent(item)){
return false;
}
return true;
}
/**
* Checks if an item should be serialized to disk when saving a chunk
* @param item The item
* @return true if should be sent, false otherwise
*/
public static boolean itemShouldBeSerialized(Entity item){
//if the item is attached to a creature, don't save a dedicated item
//instead, the creature template should include the item
if(AttachUtils.hasParent(item)){
return false;
}
return true;
}
/**
* Gets the type of item
* @param item The entity
@ -353,6 +381,7 @@ public class ItemUtils {
ItemUtils.setContainingParent(rVal, containingParent);
EntityUtils.setEntitySubtype(rVal, EntityUtils.getEntitySubtype(item));
Globals.clientSceneWrapper.getScene().registerEntity(rVal);
Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.ITEM);
return rVal;
} else {
return null;

View File

@ -107,7 +107,7 @@ public class MenuGeneratorsMultiplayer {
ActorStaticMorph staticMorph = new ActorStaticMorph();
//create creature template
CreatureTemplate template = new CreatureTemplate(race);
CreatureTemplate template = CreatureTemplate.create(race);
List<Element> controlsToAdd = new LinkedList<Element>();
//create edit controls here
@ -134,7 +134,7 @@ public class MenuGeneratorsMultiplayer {
staticMorph.initBoneTransforms(attribute.getMirrorBone());
}
//add attribute to creature template
template.putValue(attribute.getAttributeId(), defaultValue);
template.putAttributeValue(attribute.getAttributeId(), defaultValue);
//set callback for when we change the slider value to update the static morph
boneSlider.setOnValueChangeCallback(new ValueChangeEventCallback() {public void execute(ValueChangeEvent event) {
if(characterActor.getStaticMorph() != null){
@ -143,7 +143,7 @@ public class MenuGeneratorsMultiplayer {
if(attribute.getMirrorBone() != null){
staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat());
}
template.getValue(attribute.getAttributeId()).setValue(event.getAsFloat());
template.getAttributeValue(attribute.getAttributeId()).setValue(event.getAsFloat());
}
}});
} else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){
@ -161,13 +161,13 @@ public class MenuGeneratorsMultiplayer {
if(!hasAddedValue){
hasAddedValue = true;
//add attribute to template
template.putValue(attribute.getAttributeId(), variant.getId());
template.putAttributeValue(attribute.getAttributeId(), variant.getId());
}
}
//callback for updating remesh
variantCarousel.setOnValueChangeCallback(new ValueChangeEventCallback(){public void execute(ValueChangeEvent event) {
//TODO: implement updating visuals
template.getValue(attribute.getAttributeId()).setVariantId(event.getAsString());
template.getAttributeValue(attribute.getAttributeId()).setVariantId(event.getAsString());
AttributeVariant variant = null;
for(AttributeVariant variantCurrent : attribute.getVariants()){
if(variantCurrent.getId().equals(event.getAsString())){

View File

@ -11,7 +11,10 @@ import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
@ -91,6 +94,22 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
newlySpawnedEntity = CreatureUtils.clientSpawnBasicCreature(template.getCreatureType(),template);
ClientEntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()));
Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
//if the creature template includes an equip section, spawn all the equipped items
if(template != null && template.getCreatureEquipData() != null && template.getCreatureEquipData().getSlots() != null){
for(String equipSlotId : template.getCreatureEquipData().getSlots()){
//add the item to the creature's inventory
EquippedItem itemDefinition = template.getCreatureEquipData().getSlotItem(equipSlotId);
Entity itemInInventory = InventoryUtils.clientConstructInInventoryItem(newlySpawnedEntity,itemDefinition.getItemType());
//equip the item to the slot defined in the template
ClientEquipState clientEquipState = ClientEquipState.getEquipState(newlySpawnedEntity);
clientEquipState.attemptEquip(itemInInventory, clientEquipState.getEquipPoint(equipSlotId));
//map the constructed item to its server id
Globals.clientSceneWrapper.mapIdToId(itemInInventory.getId(), itemDefinition.getEntityId());
}
}
} break;
case SPAWNITEM: {
LoggerInterface.loggerNetworking.DEBUG("Spawn Item " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());

View File

@ -5,6 +5,11 @@ import java.util.List;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
@ -12,6 +17,8 @@ import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.entity.types.structure.StructureUtils;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.util.Utilities;
/**
* Contains all content for a given cell
@ -37,9 +44,12 @@ public class ContentSerialization {
serializedEntity.setRotation(EntityUtils.getRotation(entity));
serializedEntity.setType(CreatureUtils.ENTITY_TYPE_CREATURE);
serializedEntity.setSubtype(CreatureUtils.getType(entity));
if(CreatureUtils.getCreatureTemplate(entity) != null){
serializedEntity.setTemplate(Utilities.stringify(CreatureUtils.getCreatureTemplate(entity)));
}
rVal.serializedEntities.add(serializedEntity);
}
if(ItemUtils.isItem(entity)){
if(ItemUtils.isItem(entity) && ItemUtils.itemShouldBeSerialized(entity)){
EntitySerialization serializedEntity = new EntitySerialization();
serializedEntity.setPosition(EntityUtils.getPosition(entity));
serializedEntity.setRotation(EntityUtils.getRotation(entity));
@ -75,8 +85,33 @@ public class ContentSerialization {
for(EntitySerialization serializedEntity : serializedEntities){
switch(serializedEntity.getType()){
case CreatureUtils.ENTITY_TYPE_CREATURE: {
Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), null);
CreatureTemplate template = null;
if(serializedEntity.getTemplate() != null){
template = Utilities.deserialize(serializedEntity.getTemplate(), CreatureTemplate.class);
}
//
//Spawn the creature itself
Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), template);
EntityUtils.getRotation(creature).set(serializedEntity.getRotation());
//
//now that creature has been spawned, need to create all attached items
if(template != null && template.getCreatureEquipData() != null && template.getCreatureEquipData().getSlots() != null){
for(String equipSlotId : template.getCreatureEquipData().getSlots()){
//spawn the item in the world
EquippedItem itemDefinition = template.getCreatureEquipData().getSlotItem(equipSlotId);
Entity itemInWorld = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), itemDefinition.getItemType());
//add the item to the creature's inventory
Entity itemInInventory = InventoryUtils.serverAttemptStoreItem(creature, EntityLookupUtils.getEntityById(itemInWorld.getId()));
//equip the item to the slot defined in the template
ServerEquipState serverEquipState = ServerEquipState.getEquipState(creature);
serverEquipState.commandAttemptEquip(itemInInventory,serverEquipState.getEquipPoint(equipSlotId));
}
}
} break;
case ItemUtils.ENTITY_TYPE_ITEM: {
Entity item = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), serializedEntity.getSubtype());

View File

@ -8,9 +8,29 @@ import org.joml.Vector3d;
*/
public class EntitySerialization {
/**
* The type of the entity
*/
int type;
/**
* The subtype of the entity
*/
String subtype;
/**
* The (optional) template of the entity
*/
String template;
/**
* The position of the entity
*/
Vector3d position;
/**
* The rotation of the entity
*/
Quaterniond rotation;
//type getter
@ -18,37 +38,74 @@ public class EntitySerialization {
return type;
}
//type setter
/**
* Sets the type of the entity
* @param type The type
*/
public void setType(int type){
this.type = type;
}
//subtype getter
/**
* Gets the subtype of the entity
* @return The subtype
*/
public String getSubtype(){
return subtype;
}
//subtype setter
/**
* Sets the subtype of the entity
* @param subtype The subtype
*/
public void setSubtype(String subtype){
this.subtype = subtype;
}
//position getter
/**
* Gets the (optional) template of the entity
* @return The template
*/
public String getTemplate(){
return template;
}
/**
* Sets the template of the entity
* @param template The template
*/
public void setTemplate(String template){
this.template = template;
}
/**
* Gets the position of the entity
* @return The position
*/
public Vector3d getPosition(){
return position;
}
//position setter
/**
* Sets the position of the entity
* @param position The position
*/
public void setPosition(Vector3d position){
this.position = position;
}
//rotation getter
/**
* Gets the rotation of the entity
* @return The rotation
*/
public Quaterniond getRotation(){
return rotation;
}
//rotation setter
/**
* Sets the rotation of the entity
* @param rotation The rotation
*/
public void setRotation(Quaterniond rotation){
this.rotation = rotation;
}

View File

@ -147,7 +147,7 @@ public class ServerDataCell {
if(CreatureUtils.isCreature(entity)){
CreatureUtils.sendEntityToPlayer(player, entity);
}
if(ItemUtils.isItem(entity)){
if(ItemUtils.isItem(entity) && ItemUtils.itemShouldBeSentToClient(entity)){
ItemUtils.sendEntityToPlayer(player, entity);
}
if(ObjectUtils.isObject(entity)){