ZigTheHedge Posted May 4, 2020 Report Share Posted May 4, 2020 (edited) Hey, fellow modders and authors of such a great API! I'm struggling with a problem, which I can't find the source of. When player breaks my block, it's inventory should be saved in dropped Item Attributes. Well, it does, I can confirm it via debug. Now, when I try to place the block using that item, I only get partial information from the former ItemStacks. Here are the code parts: OnBlockBroken (everything is saving inside ItemStack::Attributes just fine) public override void OnBlockBroken(IWorldAccessor world, BlockPos blockPos, IPlayer byPlayer, float dropQuantityMultiplier = 1) { if (world.Side == EnumAppSide.Server && (byPlayer == null || byPlayer.WorldData.CurrentGameMode != EnumGameMode.Creative)) { ItemStack[] drops = GetDrops(world, blockPos, byPlayer, 1); ItemStack droppedItem = null; if (drops != null) { if(drops.Length > 0) { droppedItem = drops[0].Clone(); } } if (EntityClass != null) { BlockEntity entity = world.BlockAccessor.GetBlockEntity(blockPos); if (entity != null) { if (entity is IBlockEntityContainer) { ParcelInventory inv = (ParcelInventory)((IBlockEntityContainer)entity).Inventory; droppedItem.Attributes.SetInt("contentsCount", inv.Slots.Length); for (int i = 0; i < inv.Slots.Length; i++) { ItemStack stack = inv.Slots[i].Itemstack.Clone(); droppedItem.Attributes.SetItemstack("slot_" + i, stack); } //droppedItem.Attributes has three Values. First one - is the size of the following ItemStacks, which are two. world.SpawnItemEntity(droppedItem, new Vec3d(blockPos.X + 0.5, blockPos.Y + 0.5, blockPos.Z + 0.5), null); } } } world.PlaySoundAt(Sounds?.GetBreakSound(byPlayer), blockPos.X, blockPos.Y, blockPos.Z, byPlayer); } world.BlockAccessor.SetBlock(0, blockPos); } Debug info from slot_0 (everything is fine - we have an Item here): OnBlockPlaced (ItemStack::Attributes gone crazy and lost almost all information about ItemStack beside Id) public override void OnBlockPlaced(IWorldAccessor world, BlockPos blockPos, ItemStack byItemStack = null) { base.OnBlockPlaced(world, blockPos, byItemStack); if (world.Side == EnumAppSide.Server && byItemStack != null) { int contentsCount = byItemStack.Attributes.GetInt("contentsCount", -1); if (contentsCount != -1) { if (EntityClass != null) { BlockEntity entity = world.BlockAccessor.GetBlockEntity(blockPos); if (entity != null) { if (entity is IBlockEntityContainer) { ParcelInventory inv = (ParcelInventory)((IBlockEntityContainer)entity).Inventory; for (int i = 0; i < contentsCount; i++) { ItemStack stack = byItemStack.Attributes.GetItemstack("slot_" + i); // stack is not a valid ItemStack! Block == null, Item == null ItemAttributes == null! inv.Slots[i].Itemstack = stack.Clone(); inv.MarkSlotDirty(i); } } entity.MarkDirty(true); world.BlockAccessor.MarkBlockEntityDirty(blockPos); } } } } } Debug info from stack (NPEs everywhere!): Any ideas? Edited May 5, 2020 by ZigTheHedge Link to comment Share on other sites More sharing options...
Tyron Posted May 5, 2020 Report Share Posted May 5, 2020 Hi Zig, what calls OnBlockPlaced there? The player when you place the stack yourself or something else? This item stack looks like it has been saved to disk manually and not fully loaded yet (via stack.ResolveBlockOrItem()) Also I think you are mixing up something there. stack.Attributes is not the same as stack.ItemAttributes stack.Attributes = Data specific for this item stack that you can set and read at will stack.ItemAttributes = shorthand for stack.Collectible.Attributes. This is attribute data as loaded from the block- or itemtype json files. In almost all circumstances you'd want this to be a read only data source. (upload test) 1 Link to comment Share on other sites More sharing options...
ZigTheHedge Posted May 5, 2020 Author Report Share Posted May 5, 2020 Hi, Tyron! 12 minutes ago, Tyron said: what calls OnBlockPlaced there? The player when you place the stack yourself or something else? This item stack looks like it has been saved to disk manually and not fully loaded yet (via stack.ResolveBlockOrItem()) The player. Regular right click with Item form of Block. 13 minutes ago, Tyron said: Also I think you are mixing up something there. stack.Attributes is not the same as stack.ItemAttributes Yeah, I know. The screenshot just showing that stack.ItemAttributes were there during the "save" in OnBlockBroken, and weren't during "load" in OnBlockPlaced. They should serialize via Attributes.SetItemstack, right? Link to comment Share on other sites More sharing options...
ZigTheHedge Posted May 5, 2020 Author Report Share Posted May 5, 2020 Oh, man... stack.ResolveBlockOrItem() did the trick! Thanks! 1 Link to comment Share on other sites More sharing options...
Recommended Posts