unified item transfer flow

This commit is contained in:
austin 2025-05-13 16:45:21 -04:00
parent 676494ff20
commit 198ce812bd
11 changed files with 245 additions and 19 deletions

View File

@ -1754,6 +1754,8 @@ Inventory window max width
Natural inventory panel wraps on width limit
Fix target inventory window clearing
Non-ideal implementation of multiple inventory windows drawing at once
Inventory packet for unified item transform requests from client
Server inventory utility for unified item transform requests

View File

@ -14,6 +14,9 @@ import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.net.parser.net.message.NetworkMessage;
import electrosphere.net.server.protocol.InventoryProtocol;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elementtypes.ClickableElement.ClickEventCallback;
@ -130,19 +133,26 @@ public class NaturalInventoryPanel {
panel = ItemIconPanel.createPanel(currentItem, i, inventory);
} else {
panel = ItemIconPanel.createEmptyItemPanel(() -> {
if(Globals.dragSourceInventory instanceof RelationalInventoryState){
if(Globals.dragSourceInventory == InventoryUtils.getToolbarInventory(entity)){
InventoryUtils.clientAddToNatural(Globals.draggedItem);
} else if(Globals.dragSourceInventory == InventoryUtils.getEquipInventory(entity)){
RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity);
ClientEquipState equipState = ClientEquipState.getEquipState(entity);
equipState.commandAttemptUnequip(equipInventory.getItemSlot(Globals.draggedItem));
}
} else if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){
if(ItemUtils.getContainingParent(Globals.draggedItem) != Globals.playerEntity){
throw new UnsupportedOperationException("Unimplemented!");
}
}
NetworkMessage requestPickupMessage = InventoryMessage.constructclientRequestStoreItemMessage(
Globals.clientSceneWrapper.mapClientToServerId(entity.getId()),
InventoryProtocol.INVENTORY_TYPE_NATURAL,
0 + "",
Globals.clientSceneWrapper.mapClientToServerId(Globals.draggedItem.getId())
);
Globals.clientConnection.queueOutgoingMessage(requestPickupMessage);
// if(Globals.dragSourceInventory instanceof RelationalInventoryState){
// if(Globals.dragSourceInventory == InventoryUtils.getToolbarInventory(entity)){
// InventoryUtils.clientAddToNatural(Globals.draggedItem);
// } else if(Globals.dragSourceInventory == InventoryUtils.getEquipInventory(entity)){
// RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity);
// ClientEquipState equipState = ClientEquipState.getEquipState(entity);
// equipState.commandAttemptUnequip(equipInventory.getItemSlot(Globals.draggedItem));
// }
// } else if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){
// if(ItemUtils.getContainingParent(Globals.draggedItem) != Globals.playerEntity){
// throw new UnsupportedOperationException("Unimplemented!");
// }
// }
});
}
panelContainer.addChild(panel);

View File

@ -191,6 +191,7 @@ public class ClientInventoryState implements BehaviorTree {
ClientChargeState clientChargeState = ClientChargeState.getClientChargeState(clientInventoryItem);
clientChargeState.setCharges(message.getcharges());
} break;
case CLIENTREQUESTSTOREITEM:
case CLIENTREQUESTCRAFT:
case CLIENTUPDATETOOLBAR:
case CLIENTREQUESTADDNATURAL:

View File

@ -7,6 +7,7 @@ import java.util.stream.Collectors;
import org.joml.Vector3d;
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
import electrosphere.data.creature.equip.EquipPoint;
import electrosphere.data.item.Item;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
@ -284,6 +285,43 @@ public class InventoryUtils {
return inventoryItem;
}
/**
* Tries to add an item to a given inventory on a given container
* @param container The container to store the item in
* @param item The item to store
* @param containerType The type of container to store into
* @param slotId (Optional) The slot within the container to store into
* @return The in-inventory item
*/
public static void serverAttemptStoreItemTransform(Entity container, Entity itemEnt, int containerType, String slotId){
if(itemEnt == null){
throw new Error("Null item provided! " + itemEnt);
}
if(!ItemUtils.isItem(itemEnt)){
throw new Error("Item is not an item!");
}
if(containerType != InventoryProtocol.INVENTORY_TYPE_EQUIP && containerType != InventoryProtocol.INVENTORY_TYPE_NATURAL && containerType != InventoryProtocol.INVENTORY_TYPE_TOOLBAR){
throw new Error("Invalid container type! " + containerType);
}
//check if should remove from existing container
if(ItemUtils.getContainingParent(itemEnt) != null && ItemUtils.getContainingParent(itemEnt) != container){
Entity existingContainer = ItemUtils.getContainingParent(itemEnt);
InventoryUtils.serverRemoveItemFromInventories(existingContainer,itemEnt);
}
if(containerType == InventoryProtocol.INVENTORY_TYPE_EQUIP){
ServerEquipState equipState = ServerEquipState.getEquipState(container);
EquipPoint point = equipState.getEquipPoint(slotId);
equipState.commandAttemptEquip(itemEnt, point);
} else if(containerType == InventoryProtocol.INVENTORY_TYPE_NATURAL){
InventoryUtils.serverAddToNatural(container, itemEnt);
} else if(containerType == InventoryProtocol.INVENTORY_TYPE_TOOLBAR){
ServerToolbarState serverToolbarState = ServerToolbarState.getServerToolbarState(container);
serverToolbarState.attemptEquip(itemEnt, Integer.parseInt(slotId));
}
}
/**
* 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

View File

@ -8,6 +8,8 @@ import electrosphere.entity.Entity;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.equip.ServerToolbarState;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.InventoryMessage;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
@ -89,6 +91,30 @@ public class ServerInventoryState implements BehaviorTree {
ServerToolbarState serverToolbarState = ServerToolbarState.getServerToolbarState(parent);
serverToolbarState.attemptChangeSelection(message.gettoolbarId());
} break;
case CLIENTREQUESTSTOREITEM: {
Entity itemEnt = EntityLookupUtils.getEntityById(message.getitemEntId());
Entity currentParent = ItemUtils.getContainingParent(itemEnt);
Entity container = EntityLookupUtils.getEntityById(message.gettargetEntId());
//error checking
if(itemEnt == null){
throw new Error("Failed to locate server entity " + message.getitemEntId());
}
if(container == null){
throw new Error("Failed to locate server entity " + message.gettargetEntId());
}
//picking up from in the world
if(currentParent == null){
if(container != this.parent){
LoggerInterface.loggerEngine.WARNING("A client is trying to pick up an item for another entity!");
} else {
InventoryUtils.serverAttemptStoreItemTransform(parent, itemEnt, message.getcontainerType(), message.getequipPointId());
}
}
//transfering from one container to another
if(currentParent != null){
InventoryUtils.serverAttemptStoreItemTransform(container, itemEnt, message.getcontainerType(), message.getequipPointId());
}
} break;
case CLIENTREQUESTCRAFT:
case CLIENTREQUESTPERFORMITEMACTION:
case SERVERCOMMANDUNEQUIPITEM:

View File

@ -74,6 +74,7 @@ public class InventoryProtocol implements ClientProtocolTemplate<InventoryMessag
}
}
} break;
case CLIENTREQUESTSTOREITEM:
case CLIENTREQUESTCRAFT:
case CLIENTUPDATETOOLBAR:
case CLIENTREQUESTADDNATURAL:

View File

@ -18,6 +18,7 @@ public class InventoryMessage extends NetworkMessage {
SERVERCOMMANDEQUIPITEM,
SERVERCOMMANDUNEQUIPITEM,
CLIENTREQUESTUNEQUIPITEM,
CLIENTREQUESTSTOREITEM,
CLIENTREQUESTADDTOOLBAR,
CLIENTREQUESTADDNATURAL,
CLIENTUPDATETOOLBAR,
@ -33,6 +34,8 @@ public class InventoryMessage extends NetworkMessage {
String itemTemplate;
String equipPointId;
int entityId;
int itemEntId;
int targetEntId;
int equipperId;
int containerType;
int toolbarId;
@ -107,6 +110,34 @@ public class InventoryMessage extends NetworkMessage {
this.entityId = entityId;
}
/**
* Gets itemEntId
*/
public int getitemEntId() {
return itemEntId;
}
/**
* Sets itemEntId
*/
public void setitemEntId(int itemEntId) {
this.itemEntId = itemEntId;
}
/**
* Gets targetEntId
*/
public int gettargetEntId() {
return targetEntId;
}
/**
* Sets targetEntId
*/
public void settargetEntId(int targetEntId) {
this.targetEntId = targetEntId;
}
/**
* Gets equipperId
*/
@ -295,6 +326,8 @@ public class InventoryMessage extends NetworkMessage {
return InventoryMessage.canParseserverCommandUnequipItemMessage(byteBuffer);
case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTUNEQUIPITEM:
return InventoryMessage.canParseclientRequestUnequipItemMessage(byteBuffer);
case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTSTOREITEM:
return InventoryMessage.canParseclientRequestStoreItemMessage(byteBuffer);
case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR:
if(byteBuffer.getRemaining() >= TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR_SIZE){
return true;
@ -670,6 +703,64 @@ public class InventoryMessage extends NetworkMessage {
return rVal;
}
/**
* Checks if a message of type clientRequestStoreItem can be parsed from the byte stream
*/
public static boolean canParseclientRequestStoreItemMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
if(currentStreamLength < 6){
return false;
}
if(currentStreamLength < 10){
return false;
}
int equipPointIdSize = 0;
if(currentStreamLength < 14){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(10 + 0));
temporaryByteQueue.add(byteBuffer.peek(10 + 1));
temporaryByteQueue.add(byteBuffer.peek(10 + 2));
temporaryByteQueue.add(byteBuffer.peek(10 + 3));
equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 14 + equipPointIdSize){
return false;
}
if(currentStreamLength < 18 + equipPointIdSize){
return false;
}
return true;
}
/**
* Parses a message of type clientRequestStoreItem
*/
public static InventoryMessage parseclientRequestStoreItemMessage(CircularByteBuffer byteBuffer, MessagePool pool){
InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
rVal.messageType = InventoryMessageType.CLIENTREQUESTSTOREITEM;
InventoryMessage.stripPacketHeader(byteBuffer);
rVal.settargetEntId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setcontainerType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
rVal.setitemEntId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
/**
* Constructs a message of type clientRequestStoreItem
*/
public static InventoryMessage constructclientRequestStoreItemMessage(int targetEntId,int containerType,String equipPointId,int itemEntId){
InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTSTOREITEM);
rVal.settargetEntId(targetEntId);
rVal.setcontainerType(containerType);
rVal.setequipPointId(equipPointId);
rVal.setitemEntId(itemEntId);
rVal.serialize();
return rVal;
}
/**
* Parses a message of type clientRequestAddToolbar
*/
@ -1001,6 +1092,33 @@ public class InventoryMessage extends NetworkMessage {
rawBytes[6+i] = stringBytes[i];
}
break;
case CLIENTREQUESTSTOREITEM:
rawBytes = new byte[2+4+4+4+equipPointId.length()+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
//entity messaage header
rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTSTOREITEM;
intValues = ByteStreamUtils.serializeIntToBytes(targetEntId);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(containerType);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
stringBytes = equipPointId.getBytes();
for(int i = 0; i < equipPointId.length(); i++){
rawBytes[14+i] = stringBytes[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(itemEntId);
for(int i = 0; i < 4; i++){
rawBytes[14+equipPointId.length()+i] = intValues[i];
}
break;
case CLIENTREQUESTADDTOOLBAR:
rawBytes = new byte[2+4+4];
//message header

View File

@ -385,6 +385,11 @@ public abstract class NetworkMessage {
rVal = InventoryMessage.parseclientRequestUnequipItemMessage(byteBuffer,pool);
}
break;
case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTSTOREITEM:
if(InventoryMessage.canParseMessage(byteBuffer,secondByte)){
rVal = InventoryMessage.parseclientRequestStoreItemMessage(byteBuffer,pool);
}
break;
case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR:
if(InventoryMessage.canParseMessage(byteBuffer,secondByte)){
rVal = InventoryMessage.parseclientRequestAddToolbarMessage(byteBuffer,pool);

View File

@ -159,12 +159,13 @@ public class TypeBytes {
public static final byte INVENTORY_MESSAGE_TYPE_SERVERCOMMANDEQUIPITEM = 4;
public static final byte INVENTORY_MESSAGE_TYPE_SERVERCOMMANDUNEQUIPITEM = 5;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTUNEQUIPITEM = 6;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR = 7;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL = 8;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR = 9;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTPERFORMITEMACTION = 10;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTCRAFT = 11;
public static final byte INVENTORY_MESSAGE_TYPE_SERVERUPDATEITEMCHARGES = 12;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTSTOREITEM = 7;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR = 8;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL = 9;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR = 10;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTPERFORMITEMACTION = 11;
public static final byte INVENTORY_MESSAGE_TYPE_CLIENTREQUESTCRAFT = 12;
public static final byte INVENTORY_MESSAGE_TYPE_SERVERUPDATEITEMCHARGES = 13;
/*
Inventory packet sizes
*/

View File

@ -101,6 +101,12 @@ public class InventoryProtocol implements ServerProtocolTemplate<InventoryMessag
// InventoryUtils.serverGetInventoryState(target).addNetworkMessage(message);
}
} break;
case CLIENTREQUESTSTOREITEM: {
target = EntityLookupUtils.getEntityById(connectionHandler.getPlayerEntityId());
if(target != null && InventoryUtils.hasNaturalInventory(target)){
InventoryUtils.serverGetInventoryState(target).addNetworkMessage(message);
}
} break;
case SERVERCOMMANDUNEQUIPITEM:
case SERVERCOMMANDMOVEITEMCONTAINER:
case SERVERCOMMANDEQUIPITEM:

View File

@ -17,6 +17,14 @@
"name" : "entityId",
"type" : "FIXED_INT"
},
{
"name" : "itemEntId",
"type" : "FIXED_INT"
},
{
"name" : "targetEntId",
"type" : "FIXED_INT"
},
{
"name" : "equipperId",
"type" : "FIXED_INT"
@ -121,6 +129,16 @@
"equipPointId"
]
},
{
"messageName" : "clientRequestStoreItem",
"description" : "Requests that a given item be placed in a given container type on a given container",
"data" : [
"targetEntId",
"containerType",
"equipPointId",
"itemEntId"
]
},
{
"messageName" : "clientRequestAddToolbar",
"description" : "Requests that the server add the item to the client entity's toolbar",