Jump to content

Item dupe when tossed while tag is beeing updated in inventoryTick (Ghost Item)


HDainester

Recommended Posts

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.

Edited by HDainester
Removed irrelevant information and added link to example project.
Link to comment
Share on other sites

If you want help with your code, put a reproducable example of your problem on github.

Not random and incomplete code snippets out of context in this forum.

We need to see how the code fits together and maybe try it for ourselves if the problem is not obvious

 

I am not very familiar with inventoryTick and what rules apply to it. It is mostly used by Mojang to do animation related stuff on the client,

But one place they do use it on the server is to update MapItem information. This does not modify the actual item, instead it updates information stored elsewhere.

 

It would not suprise to learn that modifying an ItemStack while the game is iterating over the inventory causes it to become very confused.

The tags on an ItemStack form part of its "identity".

But I don't know that for sure.

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

A quick search finds this example in the Botania mod updating tags during inventoryTick, so my concern about that is probably not correct?

https://github.com/VazkiiMods/Botania/blob/0568ec726bd42c506cdfa00705159dbe9b897b46/Xplat/src/main/java/vazkii/botania/common/item/equipment/tool/VitreousPickaxeItem.java#L90

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

By the way, if you are concerned about lag, you can always throttle your tick handling.

Something like:

if (entity.tickCount % 20 == 0) {
   // do processing once per second
}

 

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

Posted (edited)

Hi warjort,

thanks for the answer. I have set up a repository with a minimal example illustrating the issue. You can find it here: https://gitlab.com/hd-mc-mods/examples/item-tick-bug . There is also a gif that shows how to reproduce the bug. For now I will look into how Botania did it (though maybe the bug went unnoticed on their side?! I will have to check I guess). Thanks for pointing that out!

14 hours ago, warjort said:

It would not suprise to learn that modifying an ItemStack while the game is iterating over the inventory causes it to become very confused.

I indeed get the hunch that this might be the case considering I had no issues replicating the bug with a minimal example.

Edited by HDainester
Fixed link to repo
Link to comment
Share on other sites

So I have experimented around with the example project and could reproduce this bug with following alternatives:

Changing the tag in an override of onUseTick()

ExampleItem#onUseTick

@Override
public void onUseTick(Level level, LivingEntity living, ItemStack stack, int count) {
    if(!level.isClientSide) {
        stack.getOrCreateTag().putInt("test", (int)(1000*Math.random()));
    }
}

Changing the tag of only the main- or offhand item in an tick event handler for the LivingEntity holding the stack

ExampleItem#update

public static void update(LivingEntity entity) {
    var stack = entity.getMainHandItem();
    var item = ExampleMod.EXAMPLE_ITEM.get();

    if(!stack.is(item)) {
        stack = entity.getOffhandItem();
    }

    if(stack.is(item)) {
        var tag = stack.getOrCreateTag();
        tag.putInt("test", (int)(1000*Math.random()));
    }
}

ExampleMod

// ... (static fields)

public ExampleMod() {
    IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
    ITEMS.register(modEventBus);
    modEventBus.addListener(this::commonSetup);
}

public void commonSetup(FMLCommonSetupEvent evt) {
    IEventBus bus = MinecraftForge.EVENT_BUS;
    bus.addListener((LivingEvent.LivingTickEvent e) -> ExampleItem.update(e.getEntity()));
}

I was also able to reproduce the bug while updating the tag only every 5 ticks, e.g.

ExampleItem#update

public static void update(LivingEntity entity) {
    if(entity.tickCount % 5 == 0) {
    	// ...
    }
}

I could lower the update rate even more but I feel like that this would not be a real soution to the problem but rather making the bug less likely to occour (apart from beeing a little bit inconvenient).

At this point I am really not sure anymore where and how to update tag values properly. It feels like I am missing something crucial. But looking at the source code of other mods (e.g. Botania or MiningGadgets) I cannot seem to figure out what they are doing different.

Link to comment
Share on other sites

Posted (edited)

So, I seem to have found a fix/workaround for this bug.

Simply override Item#onDroppedByPlayer (requires forge) to prevent the original drop action, and instead remove and drop the item from there. Here an example:

@Override
public boolean onDroppedByPlayer(ItemStack stack, Player player) {
    player.getInventory().removeItem(stack);
    player.drop(stack, true);
    return false; // prevents original drop action
}

I am still not really sure why this is necessary (I have my assumptions) or if I am updating my item tags wrong but for now I am happy that I got it to work. Still, I wouldn't mind of somebody with more insight would shed some light into the situation.

Edited by HDainester
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • [net.minecraftforge.fml.loading.RuntimeDistCleaner/DISTXFORM]: Attempted to load class net/minecraft/client/MouseHandler for invalid dist DEDICATED_SERVER when im trying to start server mods: sinytra connector forgified fabric api jei forge origins forge moraks medival races forge geckolib forge wthit forge wizards fabric paladins and priests fabric runes fabric spell engine fabric playeranimator fabric (i checked its not clientside only mod and spell engine doesnt work without it) pehkui forge soulbound forge biomes o plenty forge biome blender forge terralith forge starlight fabric serializationisbad fabric ice and fire forge lazydfu fabric gravestone forge citadel forge alex mobs forge the undead revamped forge badpackets forge trinkets forge rpg difficulty fabric azurelib armor forge cloth config forge caelus forge ferritecore forge   [09May2024 11:32:59.097] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher running: args [--launchTarget, forgeserver, --fml.forgeVersion, 47.2.20, --fml.mcVersion, 1.20.1, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20230612.114412] [09May2024 11:32:59.102] [main/INFO] [cpw.mods.modlauncher.Launcher/MODLAUNCHER]: ModLauncher 10.0.9+10.0.9+main.dcd20f30 starting: java version 17.0.11 by Eclipse Adoptium; OS Linux arch amd64 version 5.4.0-172-generic [09May2024 11:33:00.615] [main/INFO] [net.minecraftforge.fml.loading.ImmediateWindowHandler/]: ImmediateWindowProvider not loading because launch target is forgeserver [09May2024 11:33:00.694] [main/INFO] [mixin-transmog/]: Mixin Transmogrifier is definitely up to no good... [09May2024 11:33:00.798] [main/INFO] [mixin-transmog/]: crimes against java were committed [09May2024 11:33:00.830] [main/INFO] [mixin-transmog/]: Original mixin transformation service successfully crobbed by mixin-transmogrifier! [09May2024 11:33:00.997] [main/INFO] [mixin/]: SpongePowered MIXIN Subsystem Version=0.8.5 Source=union:/server/server-data/mods/Connector-1.0.0-beta.43+1.20.1.jar%23133%23136!/ Service=ModLauncher Env=SERVER [09May2024 11:33:01.008] [main/INFO] [io.dogboy.serializationisbad.core.SerializationIsBad/]: Initializing SerializationIsBad, implementation type: modlauncher [09May2024 11:33:01.815] [main/INFO] [io.dogboy.serializationisbad.core.SerializationIsBad/]: Using remote config file [09May2024 11:33:01.820] [main/INFO] [io.dogboy.serializationisbad.core.SerializationIsBad/]: Loaded config file [09May2024 11:33:01.822] [main/INFO] [io.dogboy.serializationisbad.core.SerializationIsBad/]:   Blocking Enabled: true [09May2024 11:33:01.823] [main/INFO] [io.dogboy.serializationisbad.core.SerializationIsBad/]:   Loaded Patch Modules: 39 [09May2024 11:33:03.095] [main/WARN] [net.minecraftforge.fml.loading.moddiscovery.ModFileParser/LOADING]: Mod file /server/jars/forge-1.20.1-47.2.20/libraries/net/minecraftforge/fmlcore/1.20.1-47.2.20/fmlcore-1.20.1-47.2.20.jar is missing mods.toml file [09May2024 11:33:03.096] [main/WARN] [net.minecraftforge.fml.loading.moddiscovery.ModFileParser/LOADING]: Mod file /server/jars/forge-1.20.1-47.2.20/libraries/net/minecraftforge/javafmllanguage/1.20.1-47.2.20/javafmllanguage-1.20.1-47.2.20.jar is missing mods.toml file [09May2024 11:33:03.097] [main/WARN] [net.minecraftforge.fml.loading.moddiscovery.ModFileParser/LOADING]: Mod file /server/jars/forge-1.20.1-47.2.20/libraries/net/minecraftforge/lowcodelanguage/1.20.1-47.2.20/lowcodelanguage-1.20.1-47.2.20.jar is missing mods.toml file [09May2024 11:33:03.098] [main/WARN] [net.minecraftforge.fml.loading.moddiscovery.ModFileParser/LOADING]: Mod file /server/jars/forge-1.20.1-47.2.20/libraries/net/minecraftforge/mclanguage/1.20.1-47.2.20/mclanguage-1.20.1-47.2.20.jar is missing mods.toml file [09May2024 11:33:04.426] [main/WARN] [net.minecraftforge.jarjar.selection.JarSelector/]: Attempted to select two dependency jars from JarJar which have the same identification: Mod File:  and Mod File: . Using Mod File: [09May2024 11:33:04.427] [main/INFO] [net.minecraftforge.fml.loading.moddiscovery.JarInJarDependencyLocator/]: Found 50 dependencies adding them to mods collection [09May2024 11:33:10.029] [main/INFO] [dev.su5ed.sinytra.connector.service.hacks.ModuleLayerMigrator/]: Successfully made module authlib transformable [09May2024 11:33:14.416] [main/INFO] [mixin/]: Compatibility level set to JAVA_17 [09May2024 11:33:15.020] [main/ERROR] [dev.su5ed.sinytra.connector.loader.ConnectorEarlyLoader/]: Skipping early mod setup due to previous error [09May2024 11:33:15.095] [main/INFO] [cpw.mods.modlauncher.LaunchServiceHandler/MODLAUNCHER]: Launching target 'forgeserver' with arguments [] [09May2024 11:33:22.894] [main/ERROR] [net.minecraftforge.fml.loading.RuntimeDistCleaner/DISTXFORM]: Attempted to load class net/minecraft/client/MouseHandler for invalid dist DEDICATED_SERVER [09May2024 11:33:22.895] [main/WARN] [mixin/]: Error loading class: net/minecraft/client/MouseHandler (java.lang.RuntimeException: Attempted to load class net/minecraft/client/MouseHandler for invalid dist DEDICATED_SERVER) [09May2024 11:33:22.896] [main/WARN] [mixin/]: @Mixin target net.minecraft.client.MouseHandler was not found fabric-screen-api-v1.mixins.json:MouseMixin from mod fabric_screen_api_v1 [09May2024 11:33:22.898] [main/ERROR] [net.minecraftforge.fml.loading.RuntimeDistCleaner/DISTXFORM]: Attempted to load class net/minecraft/client/gui/screens/Screen for invalid dist DEDICATED_SERVER [09May2024 11:33:22.899] [main/WARN] [mixin/]: Error loading class: net/minecraft/client/gui/screens/Screen (java.lang.RuntimeException: Attempted to load class net/minecraft/client/gui/screens/Screen for invalid dist DEDICATED_SERVER) [09May2024 11:33:22.899] [main/WARN] [mixin/]: @Mixin target net.minecraft.client.gui.screens.Screen was not found fabric-screen-api-v1.mixins.json:ScreenAccessor from mod fabric_screen_api_v1 [09May2024 11:33:24.819] [main/INFO] [MixinExtras|Service/]: Initializing MixinExtras via com.llamalad7.mixinextras.service.MixinExtrasServiceImpl(version=0.3.5).
    • I think i've found a more "generation friendly way" of generating random blobs of mineral around the ore. This both does the trick and make the generation work flawlessly (albeit i need to make some adjustments). I just ended up thinking "MAYBE there is another Feature I can use to place the minerals instead of doing it manually" And, low and behold, SCATTERED_ORE  is actually a thing. I don't really know how "orthodox" this solution is, but it works and rids me of all the problems I had witht my original "manual" implementation. If anybody has any insight on why my original class could've been causing lag to the point of freezes and chunk generation just refusing to keep loading new chunks, I'm also all ears:   Here is the full if (placed) block for anyone with a smiliar issue: if (placed) { // Define the block to replace surrounding blocks with BlockState surroundingBlockState = BlockInit.ABERRANT_MINERALOID.get().defaultBlockState(); RuleTest stoneReplacement = new TagMatchTest(BlockTags.STONE_ORE_REPLACEABLES); //Tag which indicates ores that can replace stone RuleTest deepslateReplacement = new TagMatchTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES); //Tag which indicates ores that can replace deepslate // Create a list of TargetBlockState for the Aberrant Mineraloids List<OreConfiguration.TargetBlockState> targets = new ArrayList<>(); targets.add(OreConfiguration.target(stoneReplacement, surroundingBlockState)); targets.add(OreConfiguration.target(deepslateReplacement, surroundingBlockState)); // Create a new OreConfiguration for the Aberrant Mineraloids OreConfiguration mineraloidConfig = new OreConfiguration(targets, 9); // vein size // Create a new context for the Aberrant Mineraloids FeaturePlaceContext<OreConfiguration> mineraloidCtx = new FeaturePlaceContext<>( Optional.empty(), world, ctx.chunkGenerator(), ctx.random(), offsetOrigin, mineraloidConfig ); // Generate the Aberrant Mineraloids using the SCATTERED_ORE configuration boolean mineraloidsPlaced = Feature.SCATTERED_ORE.place(mineraloidCtx); }  
    • bonjour , j ai trouver une vidéo très intéressant sur Minecraft comment voler des villageois sans qu'il sans rendent compte en 37 manière , c est très intéressant a voir et surtout  le refaire après    Je vous les met le lien de la vidéo YouTube : https://shrinkme.cc/ZlHy 
    • Wow, thanks @scientistknight1 ! That was exactly it. The issue: I was extending BaseEntityBlock, which implements getRenderShape as invisible for some reason: public abstract class BaseEntityBlock extends Block implements EntityBlock { ... public RenderShape getRenderShape(BlockState p_49232_) { return RenderShape.INVISIBLE; } ... } Looking at the Implementation on Block, it calls BlockBehaviour, which returns RenderShape.MODEL. Overriding it on my Entity did the trick.   public class AutomataStartBlock extends BaseEntityBlock { ... @Override public RenderShape getRenderShape(BlockState p_49232_) { return RenderShape.MODEL; } ... } It now works. I wonder why why BaseEntityBlock returns INVISIBLE, though.
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.