Jump to content

Ipsissimus418

Members
  • Posts

    21
  • Joined

  • Last visited

Posts posted by Ipsissimus418

  1. I have a low occurrence issue reported by users of my mod which is resulting in a ConcurrentModificationException. I'm currently trying to investigate some possible options, since I'm having problems duplicating the problem and my understanding of a couple of Minecraft areas is not good.

    I've had a look at some of the Minecraft code, but I'm not understanding it well enough to satisfy my theories.

     

    I have a WorldTickEvent handler in my mod, that simply walks a list of block positions using a iter.hasNext loop.

    Each loop calls a simple piece of code on the current blockpos and then uses the iter.remove() to remove it from the list.

     

    .....onWorldTick(TickEvent.WorldTickEvent event) .....
    .... MultiBlockTracker.run()
    
    [MultiBlockTracker.java]
    
    public void run() {
    ....
    Iterator<BlockPos> iter = blocks.iterator();
    while (iter.hasNext()) {
        BlockPos pos = iter.next();
        TileEntity te = world.getTileEntity(pos);
        if (te instanceof MultiBlockGlueProvider) {
            ((MultiBlockGlueProvider)te).getGlue().onHello(world, i.getPos());
            iter.remove();
        }
    }

     

    Each relevant tile entity in my mod can add blocks to this block list via an override of the TileEntity.validate() method.

    [MultiBlockTileEntity.java]
    @Override
    public void validate() {
        super.validate();
        if (!world.isRemote) {
            MultiBlockTracker.get().addEntry(pos);
        }
    }
    
    [MultiBlockTracker.java]
    public void addEntry(BlockPos pos) {
        blocks.add(new BlockPos(pos));
    }

     

    The ConcurrentModificationException is pointing at the iter.next.

    	
    java.util.ConcurrentModificationException: null
    	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) ~[?:1.8.0_181] {}
    	at java.util.ArrayList$Itr.next(ArrayList.java:859) ~[?:1.8.0_181] {}
    	at ipsis.woot.modules.factory.multiblock.MultiBlockTracker.run(MultiBlockTracker.java:45) ~[woot:1.16.4-1.0.3.0] {re:classloading}

     

    As far as I can see I am using the iterator correctly and have used the same pattern successfully(?) elsewhere in my code.

    My current guess is that the concurrent modification is because one thread is trying to add to this list, while the other one is trying to remove items from it.

     

    However I'm not sure if this is how Minecraft actually works, because I'm not confident in my understanding of the world tick.

     

    So does anyone know what threads of execution are actually going on here

     

    Can the world tick event and the tile entity validate be running in different threads causing this concurrent access to happen and I need to add some locking around the block list?

     

    Or is there a different thread for each world meaning I could have two WorldTickEvent at the same time therefore I've got two iterators running over the same list removing items at the "same time"?

     

    Or am I just looking at a red herring and the problem actually lies elsewhere?

     

    Thanks

     

     

  2. After a good day of debugging I have my answer.

    Server was working perfectly.

    It was the client that was failing.

    When the client was processing the Container.slotClick it does the following

    slot6.getItemStackLimit

        SlotItemHandler.getItemStackLimit

            Get a full stack and try to insert it into the IItemHandler

                calls isValidItemForSlot which on the client was returning false.

     

    My isItemValidForSlot looks up the recipes loaded on startup to see if the item is a valid input. When running with an internal server, this input item list was being created by my code by the server part. However on a standalone client, it was always empty as the server code isn't there to fill it.

    Therefore the client updated the gui with a an empty itemstack as the item wasn't valid.

     

    My transferStackInSlot also used this input item validation code, which is why it didn't work.

     

    By removing this input slot validation just now, then it all works. So back to adding some code to make the validation work on both sides.

     

    I hadn't appreciated that the item validation was being performed by client code, but that seems to be because the client is refreshing the stacks to show the user in the gui. The server only corrects those stack if the client shows something that is out of sync with its knowledge.

     

    Well that is my understanding of what is going on, so I go and fix my code and be more appreciative of the differences between the client and server operation.

        

  3. Been doing some more debugging - including a completely fresh Intellj checkout.

     

    Items being inserted via a hopper while the gui is open work correctly - probably because they modify the destination stack size.

    You can correctly remove (manually or shift-click) an item from the machine inventory.

    The issue is limited to items going into the single slot of the machine either via mouse drag or via shift-click on the item.

     

    I've rewritten the container slot handling and the tlle entity inventory using other people's code as an example but nothing seems to fix it.

     

    It looks very much like when the item is dragged into the machine slot via the gui, then the slot update packet is not being sent to the client. The update only happens when something else causes the machine inventory stack to change eg. item processed, that the client is refreshed. And even when that happens only the destination slot is refreshed, not the source slot or the dragged stack.

    (And by that I mean that I've broken it in some way).

     

  4. (I initially asked for help of Discord where Gigaherz referenced his transferStackInSlot method which I've tried, however I'm still having issue, so I'm posting here with more context)

     

    I have a few machines with inventory slots and have implemented the whole transferStackInSlot with both my own and then Gigaherz version.

    With an internal server moving items manually from the inventory to the input slot of the machine or via transferStackInSlot works fine. GUI updates immediately and there are no visual issues.

     

    I've retested with a dedicated server and client and now things dont work so well.

     

    There are a few issues

    * delay between moving the item and the gui refreshing

    * original itemstack remains attached to the cursor or with shift-click visually moves to another slot in the inventory

     

    eg. manual version

    Drag an item stack of 10 items into the machine slot

    Machine starts processing

    A few seconds later the destination slot renders the stack (handleSetSlot breakpoint not hit for about 4 seconds on the client)

    Stack is still visually in the dragged state and I can place it in the inventory

    Double clicking this fake stack makes it vanish.

     

    eg. Shift-click version

    Shift click item from toolbar to machine

    Machine starts processing, destination slot is empty

    A few seconds later the destination slot renders the stack (handleSetSlot breakpoint not hit for about 4 seconds on the client)

    Stack visually moves to the player inventory

    Double clicking this fake stack makes it vanish.

     

    The 4 second delay to the handleSetSlot seems to line up with the time for the machine to process one item and therefore decrement the input stack size.

     

    I would almost say that the slot numbering on the dedicated server and client are different.

    There are no issues with a standalone client and internal server.

     

    Container code https://github.com/Ipsis/Woot/blob/1.15.x/src/main/java/ipsis/woot/modules/squeezer/blocks/DyeSqueezerContainer.java

    TileEntity code https://github.com/Ipsis/Woot/blob/1.15.x/src/main/java/ipsis/woot/modules/squeezer/blocks/DyeSqueezerTileEntity.java

     

    I know I've overlooked something but I completely stumped as to what.

    I had other issues related to dedicated server which I've fixed  when  registering of the containers.

    So any pointers as to what might be going on here.

     

    Thanks

    Ipsis

  5. I'm currently updating/rewriting/experimenting with  my mod for 1.14.4 and have been running into a confusing issue with spawning.

    I can happily spawn mobs and kill them, except for when I need to modify the entity.

     

    The best example is that I need to spawn and kill small slimes.

     

    I have an access transformer for setSlimeSize that is working fine.

    I then use setSlimeSize to set a size of 1 - small.

    But when I get the LivingDropEvent ~50% of the time the size is back to 2 - large.

     

    I've been dumping the UUID for the entity at creation time and drop event time, to make sure I'm actually seeing the same entity and they look fine.

     

    To create the entity I've been basing it off the AbstractSpawner.java vanilla code, then I set the slime size

    public net.minecraft.entity.monster.SlimeEntity func_70799_a(IZ)V # setSlimeSize
    
        Entity entity = EntityType.func_220335_a(.....
        ....
        MobEntity mobEntity = (MobEntity)entity;
        ....
    	SlimeEntity slimeEntity = (SlimeEntity)mobEntity;
            if (fakeMob.isSmallSlime()) {
                slimeEntity.setSlimeSize(1, false);
            } else {
                slimeEntity.setSlimeSize(2, false);
            }
    
    	...
    	mobEntity.onInitialSpawn(world,
                    world.getDifficultyForLocation(new BlockPos(entity)),
                    SpawnReason.SPAWNER,
                    null, null);
    	...
    	mobEntity.onDeath(DamageSource.causePlayerDamage(fakePlayer));

     

    I don't know if I'm missing some extra step after calling setSlimeSize to sync the change before it gets spawned.

    Looking at SlimeEntity,java I'm not seeing anything jump out.

     

    Any suggestions as to what I could be missing out here?

     

    eg

    The "set size to small 1" debug is from " LOGGER.debug("SlimeSpawner: set size to small {}", slimeEntity.getSlimeSize());"

    Good spawn

    18:34:48] [Server thread/INFO] [ip.wo.Woot/]: Spawning and killing minecraft:slime,small@1 ipsis.woot.simulation.dimension.TartarusDimension@a4cf04a
    [18:34:48] [Server thread/DEBUG] [ip.wo.Woot/]: SlimeSpawner: set size to small 1
    [18:34:48] [Server thread/DEBUG] [ip.wo.Woot/]: SpawnController:spawnKill minecraft:slime,small@1 1858da71-6e5c-48ce-9615-3bbbf501abb6
    [18:34:48] [Server thread/INFO] [ip.wo.Woot/]: onLivingDropsEvent fake kill minecraft:slime,small@1 1858da71-6e5c-48ce-9615-3bbbf501abb6 [ItemEntity['Slimeball'/324, l='Single Factory', x=4.00, y=20.00, z=4.00]]

     

    Bad spawn

    [18:34:48] [Server thread/INFO] [ip.wo.Woot/]: Spawning and killing minecraft:slime,small@3 ipsis.woot.simulation.dimension.TartarusDimension@a4cf04a
    [18:34:48] [Server thread/DEBUG] [ip.wo.Woot/]: SlimeSpawner: set size to small 1
    [18:34:48] [Server thread/DEBUG] [ip.wo.Woot/]: SpawnController:spawnKill minecraft:slime,small@3 b5a5a679-6972-48b9-b93d-2826c37801c5
    [18:34:48] [Server thread/INFO] [ip.wo.Woot/]: onLivingDropsEvent fake kill minecraft:slime,large@3 b5a5a679-6972-48b9-b93d-2826c37801c5 []
    [18:34:48] [Server thread/ERROR] [ip.wo.Woot/]: onLivingDropEvent: Large slime found SlimeEntity['Slime'/320, l='Single Factory', x=4.00, y=52.00, z=4.00] FakePlayer['[woot_3]'/125, l='Single Factory', x=0.50, y=5.00, z=-47.50] size 2

     

  6. I've updated my code to use the new gui opening code, however whenever I click on the block, the GUI never displays. (Forge 1.13.2-25.0.73)

    https://github.com/Ipsis/Woot/tree/1.13.x

     

    So far I've done the following

    * registered an extension point for returning the guiscreen

    ** https://github.com/Ipsis/Woot/blob/1.13.x/src/main/java/ipsis/woot/Woot.java#L68

    * return a new GuiScreen for the FMLPlayMessages,OpenContainer

    ** https://github.com/Ipsis/Woot/blob/1.13.x/src/main/java/ipsis/woot/client/GuiHandler.java#L30

    * used NetworkHooks.openGui in the onBlockActivated method for the block

    ** https://github.com/Ipsis/Woot/blob/1.13.x/src/main/java/ipsis/woot/util/WootBlock.java#L92

     

    If I walk through the code then I can see the client side code being called, the correct block position being passed, the correct gui id being requested and the GuiScreen object being returned.

    Then FMLPlayMessages.handle method calls the displayGuiScreen method successfully,  no obvious errors seem to occur and no event seems to be cancelled. That particular method gets to the end without issue.

     

    I've put a breakpoint in the GUI drawGuiContainerBackgroundLayer and that is never hit.

    Adding debug to the FMLPlayMessage.OpenContainer method handler in my code shows that I can call the gui open sequence repeatedly by right-clicking the block.

     

    I'm assuming that I'm missing something really simple but I cannot for the life of me work out what it is.

     

    Does anyone have any hints as to what obvious thing I'm overlooking.

     

    Thanks.

    Ipsis

     

     

  7. That actually fits in with a piece of code in EntityDragon

     

    attackDragonFrom
    if health <= 0.0F && !currentphase.isStationary
    	setHealth(1.0F)
    	setPhase(DYING)

     

    That seems to tick the Dragon back up by 1 health if you attack it while it is dying, but still moving.

    It would therefore be allowed to reach the onDeath multiple times as the health > 0.0F.

     

    If that is the case, I might try caching the last EntityID in my event handler to try and filter out the duplicate Dragon ones. It wont be 100% successful, but it should cut them down a bit.

  8. In my mod I use the onLivingDeath event to decide if a user has killed enough of a specific mob for something to occur.

    I recently had an issue raised on GitHub where the user said that they could keep hitting the Dragon with arrows while it was dying and they could register multiple deaths.

     

    I've added some debug to my event handler and sure enough, if I was quick enough with a bow I could get multiple events raised until a point in the EnderDragon death sequence

     

    eg.

    public class HandlerLivingDeathEvent {
    
        @SubscribeEvent
        public void onLivingDeathEvent(LivingDeathEvent event) {
    
            LogHelper.info("onLivingDeathEvent: " + event.getSource() + "/" + event.getEntity() + "/" + event.getEntity().isDead);
            new Exception().printStackTrace();

     

    Gave the output

     

    [12:26:23] [Server thread/INFO]: Woot: onLivingDeathEvent: net.minecraft.util.EntityDamageSourceIndirect@70bea580/EntityDragon['Ender Dragon'/277010, l='Mob Test', x=7.20, y=84.56, z=-28.32]/false
    [12:26:23] [main/INFO]: Woot: onLivingDeathEvent: net.minecraft.util.DamageSource@369d50fa/EntityDragon['Ender Dragon'/277010, l='MpServer', x=7.50, y=84.50, z=-29.54]/false
    [12:26:24] [Server thread/INFO]: Woot: onLivingDeathEvent: net.minecraft.util.EntityDamageSourceIndirect@764bce76/EntityDragon['Ender Dragon'/277010, l='Mob Test', x=7.99, y=80.26, z=-24.57]/false
    [12:26:25] [Server thread/INFO]: Woot: onLivingDeathEvent: net.minecraft.util.EntityDamageSourceIndirect@4a8c7eaa/EntityDragon['Ender Dragon'/277010, l='Mob Test', x=9.94, y=68.92, z=-15.77]/false

     

    So I managed three server events for onLivingDeath and one client event.

    On another run I managed to get six server events and one client event.

    I'm only summoning one EnderDragon so it can only be for the one mob.

     

    Dumping the stack for the server event showed the same path for each event

    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at ipsis.woot.event.HandlerLivingDeathEvent.onLivingDeathEvent(HandlerLivingDeathEvent.java:21)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_188_HandlerLivingDeathEvent_onLivingDeathEvent_LivingDeathEvent.invoke(.dynamic)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:90)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:179)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraftforge.common.ForgeHooks.onLivingDeath(ForgeHooks.java:600)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.EntityLivingBase.onDeath(EntityLivingBase.java:1282)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.EntityLivingBase.attackEntityFrom(EntityLivingBase.java:1127)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.boss.EntityDragon.attackDragonFrom(EntityDragon.java:643)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.boss.EntityDragon.attackEntityFromPart(EntityDragon.java:601)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.MultiPartEntityPart.attackEntityFrom(MultiPartEntityPart.java:51)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.projectile.EntityArrow.onHit(EntityArrow.java:391)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.projectile.EntityArrow.onUpdate(EntityArrow.java:286)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.entity.projectile.EntityTippedArrow.onUpdate(EntityTippedArrow.java:110)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.world.World.updateEntityWithOptionalForce(World.java:2168)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.world.WorldServer.updateEntityWithOptionalForce(WorldServer.java:871)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.world.World.updateEntity(World.java:2127)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.world.World.updateEntities(World.java:1928)
    [12:29:54] [Server thread/INFO]: [ipsis.woot.event.HandlerLivingDeathEvent:onLivingDeathEvent:21]: 	at net.minecraft.world.WorldServer.updateEntities(WorldServer.java:643)

     

    This is using Forge 1.12.2-14.23.3.2655.

    I have a few mods in my dev environment for testing, but nothing is jumping out as having any impact on the Dragon death sequence.

    Looking at the methods in the stack trace I'm not seeing any obvious path that allows this.

     

    attackEntityFromPart(dragonPart, source, damage)
    	damage = modify damage if neede
    	attackDragonFrom(source, damage)
    		attackEntityFrom(source, damage)	
    			raise onLivingAttack event
    			if health <= 0.0F
    				return
    			damageEntity
    			if health <= 0.0F
    				onDeath
    					raise onLivingDeath event

     

    So am I just using the wrong event to register the death occurring in my code, or is this a known "quirk" of the Dragon death and the fact that it is a multi-part mob?

  9. So TileEntity::validate did the trick.

     

    First try it got called on both the server and the client - which created a very impressive stack overflow.

    Limiting that to the server - which is where I needed to do it - allowed me to walk to the master.

     

    One initial concern was the algorithm I use to walk to the master was travelling over other TEs in the same chunk which had not yet had their validate methods called yet. However as I only use their position to determine the path and never try to access them, I don't think that is an issue.

     

    I'm now horribly embarrassed for investigating every other method in block and TE and completely overlooking the "validate" one.

     

    Thanks diesieben07

  10. I currently have a working multiblock with a mixture of ticking and non-ticking TEs.

    The main block (heart/master) is a ticking TE with a public method interruptStructure which basically tells it to do a scan of the multiblock.

    All the other blocks are non-ticking TEs which when block.onBlockAdded is called, find the nearest reachable heart and call master.interruptStructure. They do something similar for when the block/te is invalidated.

    So I've got a way to say hello-block.onBlockAdded and goodbye-te.invalidate

     

    This seems to work nicely until someone builds the multiblock over a chunk boundary :(

     

    The problems occurs when the player moves away from the multiblock and returns.

    When the first chunk loads and it contains the heart, then the heart does an initial scan and fails since some of the multiblock is in the unloaded chunk.

    The player moves further forward, the next chunk loads and then the rest of the multiblock is loaded, but cannot say hello because there is no block.onBlockAdded for a chunk load.

     

    My solution - which I don't like - is to make them all tickable, then on the first tick of the non-heart blocks, find the master and poke it. All subsequent ticks for that TE are then no-ops.

    But of course I've just registered possibly 60 new ticking TEs per multiblock - which doesn't seem right.

     

    So does anyone have any suggestions of a way to fix this that doesn't involve making them all ITickable?

     

    Possible alternative: Keep track of which chunks have heart TEs and then when a neighbouring chunk loads, use that list to force the heart to rescan.

     

    Thanks

    Ipsis

  11. So I gave Choonster's pointers a go and I think I have something working.

     

    I added a new factory with my new type that allowed me to specify an enchant id and enchant level.

    The factory then parsed those json entries and applies them as the enchantment to the itemstack so it shows up in the recipe tooltips.

    The factory then created a new IngredientEnchantedBook object with the itemstack, enchantment id and enchantment level.

    The IngredientEnchantedBook apply method then uses EnchantmentHelper to pull the enchantments off the input stack and looks for the stored enchantment id and level in that map.

    The recipes were then updated to do the following:

     

    {
    "type": "woot:enchanted_book",
    "item": "minecraft:enchanted_book",
    "enchant_id", 16,
    "enchant_lvl": 1
    }

     

    This moves away from matching the NBT tags for now, but does mean that as long as a valid enchantment is present it will match.

    I am a little concerned with this method processing all the enchantments on the itemstack to do this match, as it seems a lot of processing compared to a quicker(?) partial-nbt match.

     

    Below is a link to the commit with the factory and EnchantmentHelper version for future reference.

    Github commit

     

    I'll investigate the NBTPredicate method next.

     

  12. I've had a bug report raised to me where my crafting recipes using enchanted books were not matching anymore.

    The issue came down to me testing with cheated in or enchantment table books and the user creating them with the anvil.

     

    The anvil added an extra nbt tag "RepairCost" that caused the book to no longer match in the recipe.

     

    So I'm guessing that the ingredient type "minecraft:item_nbt" has to match exactly and have no other nbt tags present.

     

    Does anyone have any pointers as to how to handle this situation of extra, unwanted nbt tags being present on the item that item_nbt matches against?

    I've looked at IIngredientFactory but I'm not sure that is going to help me.

     

    Thanks

    Ipsis

     

    This is what I'm using to match against.

        {
          "type": "minecraft:item_nbt",
          "item": "minecraft:enchanted_book",
          "nbt": "{ StoredEnchantments: [ { id: 21s, lvl: 1s } ] }"
        }

     

    The user showed a screenshot with the nbt as

    {RepairCost:1,StoredEnchantments:[{lvl:2s,id:48s}]}

     

  13. So I think I've solved this, because my upgrade to Forge 14.23.1.2554 didn't fully refresh the dev environment.

    Now that I'm definitely running with the latest forge, it looks like my recipe issues are not happening anymore and I've getting unique items.

     

    So I'll pass on my apologies for wasting peoples time.

    (No matter how much you check, you always miss the obvious!)

     

     

  14. I had upgraded my mod to use the json recipes as part of the 1.12.X port and I believe they were working find when I first tested them. I used to use a custom recipe handler in the pre-1.12 versions.

    However I've recently retested due to a bug report (StoredEnchandments needing to use shorts in the nbt) and seem to be getting the same output item for all the recipes that have the all the same ingredients, apart from a different enchanted book.

    These recipes all use vanilla enchanted books as an ingredient.

    JEI shows the correct output for the input ingredients, but the vanilla crafting table gives the wrong output.

     

    I've updated to using Forge 14.23.1.2554 with no difference.

     

    eg. 

    rate 1 upgrade (metadata 0) - factory base + t1 upgrade core + power I enchanted book -> output is decapitate I (metadata 12)

    looting 1 upgrade (metadata 3) - factory base + t1 upgrade core + looting I enchanted book -> output is decapitate I (metadata 12)

     

    https://github.com/Ipsis/Woot/tree/1_12/src/main/resources/assets/woot/recipes

    https://github.com/Ipsis/Woot/blob/1_12/src/main/resources/assets/woot/recipes/upgrade_looting_i.json

    https://github.com/Ipsis/Woot/blob/1_12/src/main/resources/assets/woot/recipes/upgrade_rate_i.json

    https://github.com/Ipsis/Woot/blob/1_12/src/main/resources/assets/woot/recipes/upgrade_decapitate_i.json

     

     

    All the recipes with enchanted books output the same item but with different metadata. 

     "result": {
        "item": "woot:upgrade",
        "data": 3
      },

     

     

    This is the format of ingredient I was using successfully(?) before, probably during 1.12 development rather than 1.12.1 or 1.12.2.

        {
          "type": "minecraft:item_nbt",
          "item": "minecraft:enchanted_book",
          "nbt": {
            "StoredEnchantments": [
              {
                "id": 21,
                "lvl": 1
              }
            ]
          }
        }

     

    I've also tried using the vanilla string nbt version of this with the same results.

         {
           "type": "minecraft:item_nbt",
           "item": "minecraft:enchanted_book",
          "nbt": "{ StoredEnchantments: [ { id: 32s, lvl: 1s } ] }"
         }

     

×
×
  • Create New...

Important Information

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