What is my goal:
Create an item with forge energy support. It is supposed to switch between an active and inactive state. It should drain energy while active and inside the inventory of an entity.
What I am currently doing to archieve this:
I have an override of inventoryTick() in my item class which currently looks like this:
@Override
public void inventoryTick(ItemStack stack, Level level, Entity entity, int i, boolean bl) {
if(!level.isClientSide) {
if(updateActive(stack, level, entity)) { // checks state of the 'active' boolean tag
for(var stackInHand : entity.getHandSlots()) {
if(stackInHand == stack) {
updateLight(level, entity); // might cause some lag (places light blocks)
break;
}
}
// extractEnergy(stack, 1);
stack.getOrCreateTag().putInt("energy", 1000 + (int)(1000*Math.random())); // for testing
}
}
}
Apart from that I have defined an ICapabilityProvider which provides an instance of my custom IEnergyStorage implementation (stores current energy of an ItemStack in the 'energy' tag). As can be seen in the snippet above I have disabled the the extractEnergy() call and modified the energy tag directly to ensure nothing is wrong with my IEnergyStorage implementation.
What's the issue:
It appears that sometimes when I drop an 'active' item into the world the entity is dropped but a ghost item stays in the slot of the player inventory. I could confirm with debug outputs that inventoryTick() is only called on the client side from that point on (checking the inventory slot with the data command also reports that no item exist in that slot). As soon as I open the inventory the ghost item becomes an actual item (i.e. it is beeing updated on the server side again) effectively duping the item.
I have observed this behaviour only when dropping the item while the game is lagging (sometimes). Though even a minor lag spike could be enough I guess. In my case this can be caused by the updateLight() call (depending on the mod settings and the spec of the machine) since it places light blocks in the world causing some light updates. I use this call with high settings (i.e. placing many light blocks) to forcefully cause some lag to be able to somewhat consistently replicate this issue.
I guess the information that the item was dropped does not reach the client. This is somewhat surprising to me since from my understanding this could happen to any item?! Though I have never observed this kind of bug with any other modded (or vanilla) item from what I can recall.
Whats interesting is that if I remove the randomness from the tag value (e.g. stack.getOrCreateTag().putInt("energy", 1000)) the issue seems to be gone. Hence I came to the conclusion this might be tied to the tag values getting out of sync between the server and client. But I have no idea what to do about this.
Minimal example:
I have set up a project with a minimal example showcasing the bug. The repository can be found here: https://gitlab.com/hd-mc-mods/examples/item-tick-bug
So this makes me wonder:
Am I not supposed to change tag values in inventoryTick()?
Is there a way to check on the client side if an item stack does not exist anymore on the server side (i.e. remove ghost items)?
Is it wrong to put to much load on the server inside inventoryTick() (e.g. updateLight())? What would be alternatives?
Am I doing something obviously wrong that is out of my grasp?
I hope somebody with a little more insight can help me with this or point me to good examples matching my usecase.