crafting improvements
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-30 15:28:40 -04:00
parent bd2f49ab09
commit e207269489
8 changed files with 297 additions and 55 deletions

View File

@ -1617,6 +1617,8 @@ Undo state transition "fix" that broke harvest interaction
Undo voxel "fix" that messed up terrain smooth transitions
Craftable wooden floor fab
Using up charges destroys the item (including toolbar instances)
Crafting can consume charges
Products from crafting can add charges to existing items
@ -1628,6 +1630,8 @@ Using up charges destroys the item (including toolbar instances)
High level netcode gen needs to send packets to containing player of inventory items
Implement gadgets
- Chemistry System

View File

@ -76,18 +76,28 @@ public class ServerToolbarState implements BehaviorTree {
* @param point The point to equip to
*/
public void attemptEquip(Entity inInventoryEntity, int slotId){
if(inInventoryEntity == null){
throw new Error("Entity is null!");
}
if(!ItemUtils.isItem(inInventoryEntity)){
throw new Error("Entity is not an item!");
}
RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(parent);
RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
ServerEquipState serverEquipState = ServerEquipState.getEquipState(parent);
boolean hasEquipped = toolbarInventory.hasItemInSlot(slotId + "");
boolean targetIsItem = ItemUtils.isItem(inInventoryEntity);
if(!hasEquipped && targetIsItem){
if(!toolbarInventory.hasItemInSlot(slotId + "")){
//remove from equip state
if(equipInventory != null && equipInventory.containsItem(inInventoryEntity)){
if(InventoryUtils.hasEquipInventory(parent)){
RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent);
serverEquipState.serverAttemptUnequip(equipInventory.getItemSlot(inInventoryEntity));
equipInventory.tryRemoveItem(inInventoryEntity);
}
//remove from natural inventory
if(InventoryUtils.hasNaturalInventory(parent)){
UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
naturalInventory.removeItem(inInventoryEntity);
}
//add to toolbar
toolbarInventory.tryRemoveItem(inInventoryEntity);
this.unequip(inInventoryEntity);

View File

@ -55,7 +55,7 @@ public class ClientInventoryState implements BehaviorTree {
case REMOVEITEMFROMINVENTORY: {
Entity item = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId());
if(item != null){
InventoryUtils.removeItemFromInventories(parent, item);
InventoryUtils.clientRemoveItemFromInventories(parent, item);
//attempt re-render ui
WindowUtils.attemptRedrawInventoryWindows();
//destroy the item

View File

@ -1,5 +1,9 @@
package electrosphere.entity.state.inventory;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import org.joml.Vector3d;
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
@ -515,7 +519,7 @@ public class InventoryUtils {
* @param creature The creature to remove the item from (likely to be player entity)
* @param item The item to remove
*/
public static void removeItemFromInventories(Entity creature, Entity item){
public static void clientRemoveItemFromInventories(Entity creature, Entity item){
if(creature == null){
throw new Error("Creature is null!");
}
@ -559,37 +563,172 @@ public class InventoryUtils {
}
}
/**
* [SERVER ONLY] Called when the server says to remove an item from all inventories
* 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 serverRemoveItemFromInventories(Entity creature, Entity item){
if(creature == null){
throw new Error("Creature is null!");
}
if(item == null){
throw new Error("Item is null!");
}
if(!CreatureUtils.isCreature(creature)){
throw new Error("Creature is not a creature!");
}
if(!ItemUtils.isItem(item)){
throw new Error("Item is not an item!");
}
if(!ItemUtils.itemIsInInventory(item)){
throw new Error("Item is not in an inventory!");
}
//check if the item is in an inventory
if(InventoryUtils.hasNaturalInventory(creature)){
//get inventory
UnrelationalInventoryState inventory = InventoryUtils.getNaturalInventory(creature);
//remove item from inventory
inventory.removeItem(item);
}
if(InventoryUtils.hasEquipInventory(creature)){
//get inventory
RelationalInventoryState inventory = InventoryUtils.getEquipInventory(creature);
//get real world item
Entity realWorldItem = ItemUtils.getRealWorldEntity(item);
if(realWorldItem != null){
//drop item
ServerEquipState equipState = ServerEquipState.getEquipState(creature);
equipState.serverTransformUnequipPoint(inventory.getItemSlot(item));
}
//remove item from inventory
inventory.tryRemoveItem(item);
}
if(InventoryUtils.hasToolbarInventory(creature)){
RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(creature);
toolbarInventory.tryRemoveItem(item);
Globals.cursorState.hintClearBlockCursor();
ServerToolbarState.getServerToolbarState(creature).update();
}
}
//need creature so we can figure out where to drop the item
// public static void attemptDestroyItem(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){
// 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.getEquipState(creature);
// equipState.transformUnequipPoint(inventory.getItemSlot(item));
// }
// //remove item from inventory
// inventory.tryRemoveItem(item);
// }
// //delete in container item
// ItemUtils.destroyInInventoryItem(item);
// }
// }
/**
* Destroys an item that is in an inventory
* @param item The item
*/
public static void serverDestroyInventoryItem(Entity item){
Entity creature = ItemUtils.getContainingParent(item);
if(creature == null){
throw new Error("Creature is null!");
}
if(item == null){
throw new Error("Item is null!");
}
if(!CreatureUtils.isCreature(creature)){
throw new Error("Creature is not a creature!");
}
if(!ItemUtils.isItem(item)){
throw new Error("Item is not an item!");
}
if(!ItemUtils.itemIsInInventory(item)){
throw new Error("Item is not in an inventory!");
}
//check if the item is in an inventory
if(InventoryUtils.hasNaturalInventory(creature)){
//get inventory
UnrelationalInventoryState inventory = InventoryUtils.getNaturalInventory(creature);
//remove item from inventory
inventory.removeItem(item);
}
if(InventoryUtils.hasEquipInventory(creature)){
//get inventory
RelationalInventoryState inventory = InventoryUtils.getEquipInventory(creature);
//get real world item
Entity realWorldItem = ItemUtils.getRealWorldEntity(item);
if(realWorldItem != null){
//drop item
ServerEquipState equipState = ServerEquipState.getEquipState(creature);
equipState.serverTransformUnequipPoint(inventory.getItemSlot(item));
}
//remove item from inventory
inventory.tryRemoveItem(item);
}
ServerEntityUtils.destroyEntity(item);
}
/**
* Creates an item in the creature's inventory
* @param creature The creature
* @param itemId The item's ID
*/
public static void serverCreateInventoryItem(Entity creature, String itemId, int count){
Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(itemId);
if(itemData.getMaxStack() == null){
for(int i = 0; i < count; i++){
ItemUtils.serverCreateContainerItem(creature, itemData);
}
} else {
//scan for items to add charges to first
int added = 0;
List<Entity> existingItems = InventoryUtils.getAllInventoryItems(creature);
for(Entity existingItem : existingItems){
Item existingData = Globals.gameConfigCurrent.getItemMap().getItem(existingItem);
if(existingData.getId().equals(itemId)){
ServerChargeState serverChargeState = ServerChargeState.getServerChargeState(existingItem);
if(serverChargeState.getCharges() < existingData.getMaxStack()){
int available = existingData.getMaxStack() - serverChargeState.getCharges();
//just need to add charges to this
if(available >= count - added){
serverChargeState.attemptAddCharges(count - added);
added = count;
break;
} else {
serverChargeState.attemptAddCharges(available);
added = added + available;
}
}
}
}
//need to start creating items to add more charges
Item targetData = Globals.gameConfigCurrent.getItemMap().getItem(itemId);
if(added < count){
int numFullItemsToAdd = (count - added) / targetData.getMaxStack();
int remainder = (count - added) % targetData.getMaxStack();
for(int i = 0; i < numFullItemsToAdd; i++){
Entity newInventoryItem = ItemUtils.serverCreateContainerItem(creature, itemData);
ServerChargeState.getServerChargeState(newInventoryItem).setCharges(targetData.getMaxStack());
}
if(remainder > 0){
Entity newInventoryItem = ItemUtils.serverCreateContainerItem(creature, itemData);
ServerChargeState.getServerChargeState(newInventoryItem).setCharges(remainder);
}
}
}
}
/**
* Gets the list of all items in all inventories of a creature
* @param creature The creature
* @return The list of all items
*/
public static List<Entity> getAllInventoryItems(Entity creature){
List<Entity> rVal = new LinkedList<Entity>();
if(InventoryUtils.hasEquipInventory(creature)){
RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(creature);
rVal.addAll(equipInventory.getItems());
}
if(InventoryUtils.hasNaturalInventory(creature)){
UnrelationalInventoryState equipInventory = InventoryUtils.getNaturalInventory(creature);
rVal.addAll(equipInventory.getItems());
}
if(InventoryUtils.hasToolbarInventory(creature)){
RelationalInventoryState equipInventory = InventoryUtils.getToolbarInventory(creature);
rVal.addAll(equipInventory.getItems());
}
//filter null items
rVal = rVal.stream().filter((Entity el) -> {return el != null;}).collect(Collectors.toList());
return rVal;
}
}

View File

@ -28,6 +28,9 @@ public class UnrelationalInventoryState {
// }
public void addItem(Entity item){
if(items.size() == capacity){
throw new Error("Trying to add more items than inventory can hold!");
}
items.add(item);
}

View File

@ -6,6 +6,7 @@ import electrosphere.entity.state.equip.ServerToolbarState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
@ -88,6 +89,26 @@ public class ServerChargeState implements BehaviorTree {
}
}
}
/**
* Attempts to remove a charge from whatever item the parent entity currently has equipped
* @param parent The parent
*/
public void attemptAddCharges(int charges){
this.setCharges(this.getCharges() + charges);
Entity containingParent = ItemUtils.getContainingParent(this.parent);
if(this.charges <= 0){
InventoryUtils.serverDestroyInventoryItem(this.parent);
} else if(containingParent != null) {
if(CreatureUtils.hasControllerPlayerId(containingParent)){
//get the player
int controllerPlayerID = CreatureUtils.getControllerPlayerId(containingParent);
Player controllerPlayer = Globals.playerManager.getPlayerFromId(controllerPlayerID);
//send message
controllerPlayer.addMessage(SynchronizationMessage.constructUpdateClientIntStateMessage(parent.getId(), BehaviorTreeIdEnums.BTREE_SERVERCHARGESTATE_ID, FieldIdEnums.TREE_SERVERCHARGESTATE_SYNCEDFIELD_CHARGES_ID, this.getCharges()));
}
}
}
/**
* <p> (initially) Automatically generated </p>

View File

@ -537,15 +537,15 @@ public class ItemUtils {
* @param parent The parent that contains the item
* @param itemData The item data
*/
public static void serverCreateContainerItem(Entity parent, Item itemData){
public static Entity serverCreateContainerItem(Entity parent, Item itemData){
if(parent == null || itemData == null){
throw new Error("Provided bad data! " + parent + " " + itemData);
}
//make sure there's an item to store the item
//make sure there's an inventory to store the item
UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent);
RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(parent);
if(naturalInventory == null && toolbarInventory == null){
return;
throw new Error("Trying to store an item in an entity with no inventories!");
}
Realm realm = Globals.realmManager.getEntityRealm(parent);
Vector3d parentPos = EntityUtils.getPosition(parent);
@ -558,6 +558,12 @@ public class ItemUtils {
//apply item transforms to an entity
ItemUtils.serverApplyItemEntityTransforms(realm, parentPos, rVal, itemData);
//store the item in its actual inventory
naturalInventory.addItem(rVal);
//associate with parent and set other data
ItemUtils.setContainingParent(rVal, parent);
//destroy physics
if(realm.getCollisionEngine() != null){
realm.getCollisionEngine().destroyPhysics(rVal);
@ -574,6 +580,8 @@ public class ItemUtils {
Player player = Globals.playerManager.getPlayerFromId(playerId);
player.addMessage(InventoryMessage.constructaddItemToInventoryMessage(rVal.getId(), itemData.getId()));
}
return rVal;
}
/**

View File

@ -1,14 +1,16 @@
package electrosphere.net.server.protocol;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.state.item.ServerChargeState;
import electrosphere.game.data.crafting.RecipeData;
import electrosphere.game.data.crafting.RecipeIngredientData;
import electrosphere.game.data.item.Item;
@ -28,11 +30,19 @@ import electrosphere.server.player.PlayerActions;
public class InventoryProtocol implements ServerProtocolTemplate<InventoryMessage> {
//the entity's equip inventory
/**
* the entity's equip inventory
*/
public static final int INVENTORY_TYPE_EQUIP = 0;
//the natural inventory of the entity
/**
* the natural inventory of the entity
*/
public static final int INVENTORY_TYPE_NATURAL = 1;
//the toolbar
/**
* the toolbar
*/
public static final int INVENTORY_TYPE_TOOLBAR = 2;
@Override
@ -132,13 +142,22 @@ public class InventoryProtocol implements ServerProtocolTemplate<InventoryMessag
//get reagents
List<Entity> reagentList = new LinkedList<Entity>();
boolean hasReagents = true;
Map<String,Integer> ingredientTargetMap = new HashMap<String,Integer>();
Map<String,Integer> ingredientAccretionMap = new HashMap<String,Integer>();
//find the reagents we're going to use to craft
for(RecipeIngredientData ingredient : recipe.getIngredients()){
ingredientTargetMap.put(ingredient.getItemType(),ingredient.getCount());
ingredientAccretionMap.put(ingredient.getItemType(),0);
int found = 0;
if(naturalInventory != null){
for(Entity itemEnt : naturalInventory.getItems()){
if(itemMap.getItem(itemEnt).getId().matches(ingredient.getItemType())){
found++;
if(ServerChargeState.hasServerChargeState(itemEnt)){
ServerChargeState serverChargeState = ServerChargeState.getServerChargeState(itemEnt);
found = found + serverChargeState.getCharges();
} else {
found++;
}
reagentList.add(itemEnt);
}
if(found >= ingredient.getCount()){
@ -152,7 +171,12 @@ public class InventoryProtocol implements ServerProtocolTemplate<InventoryMessag
continue;
}
if(itemMap.getItem(itemEnt).getId().matches(ingredient.getItemType())){
found++;
if(ServerChargeState.hasServerChargeState(itemEnt)){
ServerChargeState serverChargeState = ServerChargeState.getServerChargeState(itemEnt);
found = found + serverChargeState.getCharges();
} else {
found++;
}
reagentList.add(itemEnt);
}
if(found >= ingredient.getCount()){
@ -167,22 +191,55 @@ public class InventoryProtocol implements ServerProtocolTemplate<InventoryMessag
}
if(hasReagents){
for(Entity reagentEnt : reagentList){
if(naturalInventory != null){
naturalInventory.removeItem(reagentEnt);
//determine how many we need to still remove
Item itemData = itemMap.getItem(reagentEnt);
int targetToRemove = ingredientTargetMap.get(itemData.getId());
int alreadyFound = ingredientAccretionMap.get(itemData.getId());
if(alreadyFound > targetToRemove){
throw new Error("Removed too many ingredients! " + targetToRemove + " " + alreadyFound);
} else if(alreadyFound == targetToRemove){
continue;
}
if(toolbarInventory != null){
toolbarInventory.tryRemoveItem(reagentEnt);
if(ServerChargeState.hasServerChargeState(reagentEnt)){
ServerChargeState serverChargeState = ServerChargeState.getServerChargeState(reagentEnt);
int available = serverChargeState.getCharges();
if(available > targetToRemove - alreadyFound){
int chargesToRemove = targetToRemove - alreadyFound;
serverChargeState.attemptAddCharges(-chargesToRemove);
//just remove charges
ingredientAccretionMap.put(itemData.getId(),alreadyFound + chargesToRemove);
} else {
//remove item entirely (consuming all charges)
if(naturalInventory != null){
naturalInventory.removeItem(reagentEnt);
}
if(toolbarInventory != null){
toolbarInventory.tryRemoveItem(reagentEnt);
}
this.deleteItemInInventory(crafter, reagentEnt);
ingredientAccretionMap.put(itemData.getId(),alreadyFound + available);
}
} else {
if(naturalInventory != null){
naturalInventory.removeItem(reagentEnt);
}
if(toolbarInventory != null){
toolbarInventory.tryRemoveItem(reagentEnt);
}
this.deleteItemInInventory(crafter, reagentEnt);
ingredientAccretionMap.put(itemData.getId(),alreadyFound + 1);
}
this.deleteItemInInventory(crafter, reagentEnt);
}
for(RecipeIngredientData product : recipe.getProducts()){
Item productType = itemMap.getItem(product.getItemType());
if(productType == null){
throw new Error("Could not locate product definition! " + productType + " " + product.getItemType());
}
for(int i = 0; i < product.getCount(); i++){
ItemUtils.serverCreateContainerItem(crafter, productType);
}
InventoryUtils.serverCreateInventoryItem(crafter, product.getItemType(), product.getCount());
}
}
}