From 4b8aa104b5ccfed94012003290e658601055ba13 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 30 Apr 2025 18:38:18 -0400 Subject: [PATCH] DB characters store items --- docs/src/progress/renderertodo.md | 1 + .../engine/loadingthreads/LoadingUtils.java | 22 +++- .../types/creature/CreatureToolbarData.java | 78 +++++------ .../entity/types/creature/CreatureUtils.java | 26 +++- .../server/protocol/CharacterProtocol.java | 41 ++++-- .../server/character/CharacterService.java | 29 ++++ .../serialization/ContentSerialization.java | 124 ++++++++++++++---- .../serialization/EntitySerialization.java | 5 +- .../util/SerializationUtils.java | 61 +++++++++ 9 files changed, 288 insertions(+), 99 deletions(-) create mode 100644 src/main/java/electrosphere/util/SerializationUtils.java diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 8cf67add..d930d545 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1626,6 +1626,7 @@ Debounce fab placement Blocks stack Item tag adjustments Pine tree loot pool update +DB characters store toolbar items diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java index 0caff4de..d9c4faa7 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java @@ -13,8 +13,8 @@ import org.joml.Vector3i; import electrosphere.auth.AuthenticationManager; import electrosphere.engine.Globals; import electrosphere.engine.threads.LabeledThread.ThreadLabel; +import electrosphere.entity.types.EntityTypes.EntityType; import electrosphere.entity.types.creature.CreatureTemplate; -import electrosphere.entity.types.creature.CreatureToolbarData.ToolbarItem; import electrosphere.game.data.creature.type.CreatureData; import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; import electrosphere.logger.LoggerInterface; @@ -27,6 +27,7 @@ import electrosphere.net.server.player.Player; import electrosphere.net.server.protocol.CharacterProtocol; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerWorldData; +import electrosphere.server.entity.serialization.ContentSerialization; import electrosphere.server.simulation.MicroSimulation; /** @@ -164,12 +165,19 @@ public class LoadingUtils { template.putAttributeValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId()); } } - template.getCreatureToolbarData().setSlotItem("0", new ToolbarItem(71, "terrainTool")); - template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette")); - template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector")); - template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner")); - template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool")); - template.getCreatureToolbarData().setSlotItem("5", new ToolbarItem(76, "roomTool")); + String[] itemIds = new String[]{ + "terrainTool", + "spawningPalette", + "entityinspector", + "waterSpawner", + "fabTool", + "roomTool" + }; + int i = 0; + for(String itemId : itemIds){ + template.getCreatureToolbarData().setSlotItem(i + "", ContentSerialization.createNewSerialization(EntityType.ITEM, itemId)); + i++; + } //set player character template serverPlayerConnection.setCreatureTemplate(template); Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(CharacterProtocol.SPAWN_EXISTING_TEMPLATE + "")); diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureToolbarData.java b/src/main/java/electrosphere/entity/types/creature/CreatureToolbarData.java index b0234b58..c94253a6 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureToolbarData.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureToolbarData.java @@ -4,13 +4,22 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import electrosphere.server.entity.serialization.EntitySerialization; + /** * The data about what is in the creature's toolbar */ public class CreatureToolbarData { - //Map of equip slot -> item definition - Map slotToItemMap = new HashMap(); + /** + * Map of equip slot -> item definition + */ + Map slotToItemMap = new HashMap(); + + /** + * Maps a toolbar slot to its corresponding server ID + */ + Map slotToIdMap = new HashMap(); /** * Gets the slots in the equip data @@ -25,7 +34,7 @@ public class CreatureToolbarData { * @param slotId The id of the slot * @return The item definition */ - public ToolbarItem getSlotItem(String slotId){ + public EntitySerialization getSlotItem(String slotId){ return slotToItemMap.get(slotId); } @@ -34,10 +43,28 @@ public class CreatureToolbarData { * @param slotId The slot * @param itemType The item definition */ - public void setSlotItem(String slotId, ToolbarItem itemType){ + public void setSlotItem(String slotId, EntitySerialization itemType){ slotToItemMap.put(slotId, itemType); } + /** + * Gets the id of the entity at a given slot + * @param slotId The slot id + * @return The entity id + */ + public Integer getId(String slotId){ + return slotToIdMap.get(slotId); + } + + /** + * Sets the id of the entity at a given slot + * @param slotId The slot id + * @param id The entity id + */ + public void setSlotId(String slotId, Integer id){ + slotToIdMap.put(slotId, id); + } + /** * Clears the equip data */ @@ -45,48 +72,5 @@ public class CreatureToolbarData { slotToItemMap.clear(); } - /** - * An item that is equipped - */ - public static class ToolbarItem { - - /** - * 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 ToolbarItem(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; - } - - } - } diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 87b228dc..ebe5472e 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -20,12 +20,12 @@ import electrosphere.entity.state.equip.ServerEquipState; import electrosphere.entity.state.equip.ServerToolbarState; import electrosphere.entity.state.idle.ClientIdleTree; import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.entity.state.inventory.RelationalInventoryState; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree; import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree; import electrosphere.entity.types.EntityTypes.EntityType; import electrosphere.entity.types.common.CommonEntityUtils; import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem; -import electrosphere.entity.types.creature.CreatureToolbarData.ToolbarItem; import electrosphere.entity.types.item.ItemUtils; import electrosphere.game.data.creature.type.CreatureData; import electrosphere.game.data.creature.type.visualattribute.AttributeVariant; @@ -41,6 +41,8 @@ import electrosphere.renderer.actor.ActorStaticMorph; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.EntityLookupUtils; import electrosphere.server.entity.poseactor.PoseActor; +import electrosphere.server.entity.serialization.ContentSerialization; +import electrosphere.server.entity.serialization.EntitySerialization; import electrosphere.util.Utilities; /** @@ -173,15 +175,16 @@ public class CreatureUtils { for(String equipSlotId : template.getCreatureToolbarData().getSlots()){ //add the item to the creature's inventory - ToolbarItem itemDefinition = template.getCreatureToolbarData().getSlotItem(equipSlotId); - Entity itemInInventory = InventoryUtils.clientConstructInInventoryItem(creature,itemDefinition.getItemType()); + EntitySerialization itemDefinition = template.getCreatureToolbarData().getSlotItem(equipSlotId); + Entity itemInWorld = ContentSerialization.clientHydrateEntitySerialization(itemDefinition); + Entity itemInInventory = ItemUtils.clientRecreateContainerItem(itemInWorld, creature); //equip the item to the slot defined in the template ClientToolbarState clientToolbarState = ClientToolbarState.getClientToolbarState(creature); clientToolbarState.attemptAddToToolbar(itemInInventory, Integer.parseInt(equipSlotId)); //map the constructed item to its server id - Globals.clientSceneWrapper.mapIdToId(itemInInventory.getId(), itemDefinition.getEntityId()); + Globals.clientSceneWrapper.mapIdToId(itemInInventory.getId(), template.getCreatureToolbarData().getId(equipSlotId)); } } } @@ -330,8 +333,8 @@ public class CreatureUtils { for(String equipSlotId : template.getCreatureToolbarData().getSlots()){ //spawn the item in the world - ToolbarItem itemDefinition = template.getCreatureToolbarData().getSlotItem(equipSlotId); - Entity itemInWorld = ItemUtils.serverSpawnBasicItem(realm, EntityUtils.getPosition(creature), itemDefinition.getItemType()); + EntitySerialization itemDefinition = template.getCreatureToolbarData().getSlotItem(equipSlotId); + Entity itemInWorld = ContentSerialization.serverHydrateEntitySerialization(realm, itemDefinition); //add the item to the creature's inventory Entity itemInInventory = InventoryUtils.serverAttemptStoreItemTransform(creature, EntityLookupUtils.getEntityById(itemInWorld.getId())); @@ -550,6 +553,17 @@ public class CreatureUtils { equipData.setSlotItem(point, new EquippedItem(item.getId(),ItemUtils.getType(item))); } } + if(InventoryUtils.hasToolbarInventory(e)){ + RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(e); + for(String slot : toolbarInventory.getSlots()){ + Entity slotItem = toolbarInventory.getItemSlot(slot); + if(slotItem != null){ + EntitySerialization itemSerialized = ContentSerialization.constructEntitySerialization(slotItem); + template.getCreatureToolbarData().setSlotItem(slot,itemSerialized); + template.getCreatureToolbarData().setSlotId(slot, slotItem.getId()); + } + } + } template.setStateCollection(StateCollection.getStateCollection(e)); return template; } diff --git a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java index 93ad5f9b..c53184cf 100644 --- a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java @@ -14,8 +14,8 @@ import electrosphere.engine.loadingthreads.LoadingUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.ServerEntityUtils; +import electrosphere.entity.types.EntityTypes.EntityType; import electrosphere.entity.types.creature.CreatureTemplate; -import electrosphere.entity.types.creature.CreatureToolbarData.ToolbarItem; import electrosphere.game.data.creature.type.CreatureData; import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; import electrosphere.net.parser.net.message.CharacterMessage; @@ -27,6 +27,7 @@ import electrosphere.server.character.CharacterService; import electrosphere.server.character.PlayerCharacterCreation; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerWorldData; +import electrosphere.server.entity.serialization.ContentSerialization; import electrosphere.util.Utilities; /** @@ -138,12 +139,19 @@ public class CharacterProtocol implements ServerProtocolTemplate serializedEntities = this.getSerializedEntities(); for(EntitySerialization serializedEntity : serializedEntities){ - switch(EntityTypes.fromInt(serializedEntity.getType())){ - case CREATURE: { - CreatureTemplate template = null; - if(serializedEntity.getTemplate() != null){ - template = Utilities.deserialize(serializedEntity.getTemplate(), CreatureTemplate.class); - } + ContentSerialization.serverHydrateEntitySerialization(realm, serializedEntity); + } + } - // - //Spawn the creature itself - Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), template); - CreatureUtils.serverApplyTemplate(realm, creature, template); - EntityUtils.getRotation(creature).set(serializedEntity.getRotation()); - } break; - case ITEM: { - Entity item = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), serializedEntity.getSubtype()); - EntityUtils.getRotation(item).set(serializedEntity.getRotation()); - } break; - case COMMON: { - Entity object = CommonEntityUtils.serverSpawnBasicObject(realm, serializedEntity.getPosition(), serializedEntity.getSubtype()); - EntityUtils.getRotation(object).set(serializedEntity.getRotation()); - } break; - case FOLIAGE: { - long seed = Long.parseLong(serializedEntity.getTemplate()); - Entity foliage = FoliageUtils.serverSpawnTreeFoliage(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), seed); - EntityUtils.getRotation(foliage).set(serializedEntity.getRotation()); - } break; + /** + * Hydrates an entity serialization into a realm + * @param realm The realm + * @param serializedEntity The entity serialization + */ + public static Entity serverHydrateEntitySerialization(Realm realm, EntitySerialization serializedEntity){ + Entity rVal = null; + switch(EntityTypes.fromInt(serializedEntity.getType())){ + case CREATURE: { + CreatureTemplate template = null; + if(serializedEntity.getTemplate() != null){ + template = Utilities.deserialize(serializedEntity.getTemplate(), CreatureTemplate.class); + } + + // + //Spawn the creature itself + rVal = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), template); + CreatureUtils.serverApplyTemplate(realm, rVal, template); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case ITEM: { + rVal = ItemUtils.serverSpawnBasicItem(realm, serializedEntity.getPosition(), serializedEntity.getSubtype()); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case COMMON: { + rVal = CommonEntityUtils.serverSpawnBasicObject(realm, serializedEntity.getPosition(), serializedEntity.getSubtype()); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case FOLIAGE: { + long seed = Long.parseLong(serializedEntity.getTemplate()); + rVal = FoliageUtils.serverSpawnTreeFoliage(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), seed); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case ENGINE: { + throw new Error("Unsupported entity type!"); } } + return rVal; + } + + /** + * Hydrates an entity serialization into a realm + * @param serializedEntity The entity serialization + */ + public static Entity clientHydrateEntitySerialization(EntitySerialization serializedEntity){ + Entity rVal = null; + switch(EntityTypes.fromInt(serializedEntity.getType())){ + case CREATURE: { + CreatureTemplate template = null; + if(serializedEntity.getTemplate() != null){ + template = Utilities.deserialize(serializedEntity.getTemplate(), CreatureTemplate.class); + } + + // + //Spawn the creature itself + rVal = CreatureUtils.clientSpawnBasicCreature(serializedEntity.getSubtype(), template); + CreatureUtils.clientApplyTemplate(rVal, template); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case ITEM: { + rVal = ItemUtils.clientSpawnBasicItem(serializedEntity.getSubtype()); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case COMMON: { + rVal = CommonEntityUtils.clientSpawnBasicObject(serializedEntity.getSubtype()); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case FOLIAGE: { + long seed = Long.parseLong(serializedEntity.getTemplate()); + rVal = FoliageUtils.clientSpawnBasicFoliage(serializedEntity.getSubtype(), seed); + EntityUtils.getRotation(rVal).set(serializedEntity.getRotation()); + } break; + case ENGINE: { + throw new Error("Unsupported entity type!"); + } + } + return rVal; + } + + /** + * Creates a serialization of a given entity type without depending on a pre-existing entity + * @param type The type of entity + * @param id The id of the entity type + * @return The serialization + */ + public static EntitySerialization createNewSerialization(EntityType type, String id){ + EntitySerialization rVal = new EntitySerialization(); + rVal.setType(type.getValue()); + rVal.setSubtype(id); + rVal.setPosition(new Vector3d()); + rVal.setRotation(new Quaterniond()); + return rVal; } /** diff --git a/src/main/java/electrosphere/server/entity/serialization/EntitySerialization.java b/src/main/java/electrosphere/server/entity/serialization/EntitySerialization.java index 741b1e70..c0ce0a48 100644 --- a/src/main/java/electrosphere/server/entity/serialization/EntitySerialization.java +++ b/src/main/java/electrosphere/server/entity/serialization/EntitySerialization.java @@ -33,7 +33,10 @@ public class EntitySerialization { */ Quaterniond rotation; - //type getter + /** + * Gets the type of the entity + * @return The type of the entity + */ public int getType(){ return type; } diff --git a/src/main/java/electrosphere/util/SerializationUtils.java b/src/main/java/electrosphere/util/SerializationUtils.java new file mode 100644 index 00000000..218320ba --- /dev/null +++ b/src/main/java/electrosphere/util/SerializationUtils.java @@ -0,0 +1,61 @@ +package electrosphere.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import electrosphere.game.data.creature.type.ai.AITreeData; +import electrosphere.game.data.creature.type.ai.AITreeDataSerializer; +import electrosphere.game.data.creature.type.movement.MovementSystem; +import electrosphere.game.data.creature.type.movement.MovementSystemSerializer; +import electrosphere.server.macro.character.CharacterDataSerializer; +import electrosphere.server.macro.character.CharacterData; +import electrosphere.server.physics.terrain.generation.noise.NoiseModuleSerializer; +import electrosphere.server.physics.terrain.generation.noise.NoiseSampler; +import electrosphere.util.annotation.AnnotationExclusionStrategy; + +/** + * Utilities for serializing/deserializing entities + */ +public class SerializationUtils { + + /** + * Creates the gson instance + */ + static { + //init gson + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(MovementSystem.class, new MovementSystemSerializer()); + gsonBuilder.registerTypeAdapter(AITreeData.class, new AITreeDataSerializer()); + gsonBuilder.registerTypeAdapter(NoiseSampler.class, new NoiseModuleSerializer()); + gsonBuilder.registerTypeAdapter(CharacterData.class, new CharacterDataSerializer()); + gsonBuilder.addDeserializationExclusionStrategy(new AnnotationExclusionStrategy()); + gsonBuilder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy()); + gson = gsonBuilder.create(); + } + + /** + * used for serialization/deserialization in file operations + */ + static Gson gson; + + /** + * Serializes an object + * @param o The object + * @return The serialization string + */ + public static String serialize(Object o){ + return gson.toJson(o); + } + + /** + * Deserializes an object from a JSON string + * @param The type of object + * @param jsonString The JSON string to deserialize the object from + * @param className The class of the object inside the json string + * @return The Object + */ + public static T deserialize(String jsonString, Class className){ + return gson.fromJson(jsonString, className); + } + +}