DB characters store items
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-30 18:38:18 -04:00
parent b91654d7c3
commit 4b8aa104b5
9 changed files with 288 additions and 99 deletions

View File

@ -1626,6 +1626,7 @@ Debounce fab placement
Blocks stack
Item tag adjustments
Pine tree loot pool update
DB characters store toolbar items

View File

@ -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 + ""));

View File

@ -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<String,ToolbarItem> slotToItemMap = new HashMap<String,ToolbarItem>();
/**
* Map of equip slot -> item definition
*/
Map<String,EntitySerialization> slotToItemMap = new HashMap<String,EntitySerialization>();
/**
* Maps a toolbar slot to its corresponding server ID
*/
Map<String,Integer> slotToIdMap = new HashMap<String,Integer>();
/**
* 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;
}
}
}

View File

@ -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;
}

View File

@ -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<CharacterMessag
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
connectionHandler.setCreatureTemplate(template);
} else {
@ -161,12 +169,19 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
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
connectionHandler.setCreatureTemplate(template);
}

View File

@ -17,6 +17,9 @@ import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.db.DatabaseResult;
import electrosphere.server.db.DatabaseResultRow;
import electrosphere.server.entity.serialization.ContentSerialization;
import electrosphere.server.entity.serialization.EntitySerialization;
import electrosphere.util.SerializationUtils;
/**
* Service for interacting with macro-level characters
@ -97,6 +100,24 @@ public class CharacterService {
return null;
}
/**
* Gets the serialized entity data for the given character
* @param characterId The character's ID
* @return the serialziation if it exists, null otherwise
*/
public static EntitySerialization getSerialization(int characterId){
EntitySerialization rVal = null;
DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, serialization FROM charaSerializations WHERE id=?;",characterId);
if(result.hasResult()){
//if we get a valid response from the database, check that it actually matches hashes
for(DatabaseResultRow row : result){
String jsonString = row.getAsString("serialization");
rVal = SerializationUtils.deserialize(jsonString, EntitySerialization.class);
}
}
return rVal;
}
/**
* Saves a character from an entity
* @param characterEntity The entity
@ -119,6 +140,14 @@ public class CharacterService {
realPos.z
);
}
//store a serialization to associate with the character
EntitySerialization characterEntitySerialization = ContentSerialization.constructEntitySerialization(characterEntity);
Globals.dbController.executePreparedStatement(
"UPDATE charaData SET dataVal=? WHERE id=?;",
characterEntitySerialization.getTemplate(),
characterId
);
}
}

View File

@ -4,6 +4,9 @@ import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attach.AttachUtils;
@ -83,6 +86,9 @@ public class ContentSerialization {
serializedEntity.setType(EntityType.COMMON.getValue());
serializedEntity.setSubtype(CommonEntityUtils.getEntitySubtype(entity));
} break;
case ENGINE: {
throw new Error("Unsupported entity type!");
}
}
} else {
throw new Error("Trying to save entity that does not have a type!");
@ -97,34 +103,102 @@ public class ContentSerialization {
public void hydrateRawContent(Realm realm, ServerDataCell serverDataCell){
List<EntitySerialization> 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;
}
/**

View File

@ -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;
}

View File

@ -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 <T> 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>T deserialize(String jsonString, Class<T> className){
return gson.fromJson(jsonString, className);
}
}