Jump to content

andGarrett

Members
  • Posts

    101
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by andGarrett

  1. it's odd to see something in the Minecraft code like "nbtTagList". it's like saying "named binary tag tag list." like saying "ATM machine".
  2. I've been experimenting with storing complex sets of data inside a capability. To be more specific, in my "SaleItemListCapability", I'm trying to store an arraylist of objects that store a string and a double. I'm also storing another arraylist of objects that store a string, integer, and a long. finally the capability stores a long and an integer. this is pretty simple for a Class, but when it comes time to write said information to the NBT format, I run into problems. As far as I know, there should be only one "writeNBT" method for each capability storage class, which means I would need to store all these sets into one NBT. This seems almost possible given the types of data I am trying to store. It seems that ListNBT can only store one type of data per list, so I cant use that for my two arraylists as the each store more than one type. CompoundNBT can do what the ListNBT can't when it comes to storing more than one type, but I can't seem to store either ListNBT or CompoundNBT in a CompoundNBT. am I missing something or should I not be storing such complex sets of data in capabilities?
  3. will do. so I should always use packets to send data between logical sides? when you say "dedicated server", I take it you mean a server that is used for multiplayer and not simply the "logical server"?
  4. in one of my methods that gets run on the server side, I set the the server side value for the players capability, then on the very next line, I use "Minecraft.getInstance().player" to access the client side player capability to set that value. technically that's not at the "same time", but because there is no code in between the two actions, it's close enough to the same time. I guess I should have said that I am changing it in the same method.
  5. "Minecraft.getInstance().player" is the missing piece to this puzzle, thank you! now I can access the client side player's capability at the same time I'm accessing the server side player capability and update both at the same time. Then I will use the client side capability for displaying the value on my store screen.
  6. how would I get access to the client side player entity from the server side? I could pass the client side player entity to the packet, but then I don't know how I would encode/decode the player entity. I don't see any PacketBuffer read/write methods for Player entities.
  7. I want to display a double value from a server side player capability on one of my container screens and possibly other screens in the future. what is the best way to access this data from the container screen? would there be overlap if two players were using the same container, or are screens separate to each player? [SOLUTION] wherever the server is changing the value, send a packet to the client side that then uses "Minecraft.getInstance().player" to access the client side playaer capability and set the value there.
  8. I'm not sure yet. I'm still deciding on how to implement something.
  9. There is a client side player entity and a server side player entity right? does this mean I could be attaching a capability to both? should I only be attaching to the server side one?
  10. I've been trying to figure out how to work with packets, but I've hit a stumbling block. In my packet handler class I get an odd issue that may be related to intellij, but I'm not sure. if it is intellij, where would be the best place to get support? if it's something to do with minecraft/forge, I could use some help. I used EnderUnknown's post about the same topic as a framework to work off of. It is incomplete as I can't really move forward until I get this part figured out. the issue is on the line near the bottom that contains: channel.registerMessage(id++, PacketSellButton.class, PacketSellButton::encode, PacketSellButton::decode, PacketSellButton::handle); this seems to be the correct way to do things. I've seen other peoples packet handlers, and they all seem to do it this way. package com.garrett.merchantcraft.network; import com.garrett.merchantcraft.network.packets.PacketSellButton; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.NetworkRegistry; import net.minecraftforge.fml.network.simple.SimpleChannel; public final class MerchantcraftPacketHandler { private static final String PROTICOL_VERSION = "1"; public static SimpleChannel channel; public void register() { channel = NetworkRegistry.newSimpleChannel( new ResourceLocation("merchantcraft","main") ,() -> PROTICOL_VERSION , PROTICOL_VERSION::equals , PROTICOL_VERSION::equals); int id = 0; channel.registerMessage(id++, PacketSellButton.class, PacketSellButton::encode, PacketSellButton::decode, PacketSellButton::handle); } } The error message: here's the packet sell button class if that matters: package com.garrett.merchantcraft.network.packets; import com.google.common.base.Supplier; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; public class PacketSellButton { private final ItemStack item; public PacketSellButton(ItemStack stack) { this.item = stack; } public static void encode(PacketSellButton msg, PacketBuffer buf) { buf.writeItemStack(msg.item); } public static PacketSellButton decode(PacketBuffer buf) { return new PacketSellButton(buf.readItemStack()); } public static void handle(PacketSellButton msg, Supplier<NetworkEvent.Context> ctx) { ctx.get().enqueueWork(() -> { // Work that needs to be threadsafe (most work) ServerPlayerEntity sender = ctx.get().getSender(); // the client that sent this packet // do stuff }); ctx.get().setPacketHandled(true); } } [SOLUTION] I imported imported the wrong Supplier "com.google.common.base.Supplier;" correct Supplier: java.util.function.Supplier 
  11. This would require setting up my own custom packet and packet handler?
  12. I'm trying to delete items from an inventory, but no matter what I do, they keep coming back in a weird way. the inventory looks empty, but if I click on one of the seemingly empty slots, they all reappear. I've tried all kind of things like getSlot(i).putStack(ItemStack.EMPTY);, setting the stack count to zero, decreasing the stack size to zero etc. it always ends the same way. The items are "deleted" in the "sellItems" method near the bottom. package com.garrett.backtobasics.blocks; import com.garrett.backtobasics.capabilities.BankAccount.BankAccountProvider; import com.garrett.backtobasics.capabilities.itemvalues.ItemValuesProvider; import com.garrett.backtobasics.capabilities.itemvalues.TradeItem; import com.garrett.backtobasics.capabilities.saleitemlist.SaleItemListProvider; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.IContainerListener; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IWorldPosCallable; import net.minecraft.util.IntReferenceHolder; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.SlotItemHandler; import net.minecraftforge.items.wrapper.InvWrapper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import static com.garrett.backtobasics.blocks.ModBlocks.STORE_CONTAINER; import javax.annotation.Nonnull; import java.util.ArrayList; public class StoreContainer extends Container { private int sellSlots = 16; private IInventory storeInventory; private TileEntity tileEntity; private PlayerEntity playerEntity; private IItemHandler playerInventory; private ArrayList<TradeItem> itemValueList; // itemList is a list of items taken from itemValueList for use with .contains() private ArrayList<String> itemList; // valueList is a list of values taken from itemValueList for use with .contains() private ArrayList<Double> valueList; private double inventoryValue; private static final Logger LOGGER = LogManager.getLogger(); public StoreContainer(int windowId, World world, BlockPos pos, PlayerInventory PlayerInventory, PlayerEntity player) { super(STORE_CONTAINER, windowId); tileEntity = world.getTileEntity(pos); this.playerEntity = player; this.playerInventory = new InvWrapper(PlayerInventory); world.getCapability(ItemValuesProvider.ITEM_VALUES_CAPABILITY).ifPresent(h -> { itemValueList = h.getItemValueList(); itemList = h.getItemList(); valueList = h.getValueList(); }); tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { createSlotGrid(h, 4, 4, 0, 20, 23); addListener(new IContainerListener() { @Override public void sendAllContents(Container containerToSend, NonNullList<ItemStack> itemsList) { } @Override public void sendSlotContents(Container containerToSend, int slotInd, ItemStack stack) { inventoryValue = calculateInventoryValue(); } @Override public void sendWindowProperty(Container containerIn, int varToUpdate, int newValue) { } }); }); layoutPlayerInventorySlots(20, 138); /* * communicates inventory value between server and client * this allows the gui screen to update real time */ trackInt(new IntReferenceHolder() { @Override public int get() { return (int) inventoryValue; } @Override public void set(int value) { inventoryValue = value; } }); } @Override public boolean canInteractWith(PlayerEntity playerIn) { return isWithinUsableDistance(IWorldPosCallable.of(tileEntity.getWorld(), tileEntity.getPos()), playerEntity, ModBlocks.STORE); } private int addSlotRange(IItemHandler handler, int index, int x, int y, int amount, int dx) { for (int i = 0 ; i < amount ; i++) { addSlot(new SlotItemHandler(handler, index, x, y)); x += dx; index++; } return index; } private int addSlotBox(IItemHandler handler, int index, int x, int y, int horAmount, int dx, int verAmount, int dy) { for (int j = 0 ; j < verAmount ; j++) { index = addSlotRange(handler, index, x, y, horAmount, dx); y += dy; } return index; } private void layoutPlayerInventorySlots(int leftCol, int topRow) { // Player inventory addSlotBox(playerInventory, 9, leftCol, topRow, 9, 18, 3, 18); // Hotbar topRow += 58; addSlotRange(playerInventory, 0, leftCol, topRow, 9, 18); } /* * Handles when the stack in slot is shift-clicked. Normally this moves the stack between the player * inventory and the other inventory(s). * copied from ChestContainer#transferStackInSlot */ @Nonnull @Override public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { /* playerIn.getCapability(SaleItemListProvider.SALE_ITEM_LIST_CAPABILITY).ifPresent(h -> { //LOGGER.info("SaleItemList"); }); */ ItemStack itemstack = ItemStack.EMPTY; Slot slot = this.inventorySlots.get(index); if (slot != null && slot.getHasStack()) { ItemStack itemstack1 = slot.getStack(); itemstack = itemstack1.copy(); if (index < 16) { if (!this.mergeItemStack(itemstack1, 16, this.inventorySlots.size(), true)) { return ItemStack.EMPTY; } } else if (!this.mergeItemStack(itemstack1, 0, 16, false)) { return ItemStack.EMPTY; } if (itemstack1.isEmpty()) { slot.putStack(ItemStack.EMPTY); } else { slot.onSlotChanged(); } } return itemstack; } private void createSlotGrid(IItemHandler h, int columns, int rows, int startIndex, int startX, int startY) { int index = 0; for (int j = 0; j < rows; j++) { for (int i = 0; i < columns; i++) { addSlot(new SlotItemHandler(h, index + startIndex, startX + (i * 18), startY + (j * 18))); index++; } } } private double calculateInventoryValue() { NonNullList<ItemStack> inventory = this.getInventory(); double totalValue = 0; for (int i = 0; i < sellSlots; i++) { // check if stack item is in ItemValues if (itemList.contains(inventory.get(i).getItem().toString())) { totalValue += valueList.get(itemList.indexOf((inventory.get(i).getItem().toString()))) * inventory.get(i).getCount(); } } return totalValue; } public double getInventoryValue() { return inventoryValue; } public void sellItems() { inventoryValue = calculateInventoryValue(); playerEntity.getCapability(BankAccountProvider.BANK_ACCOUNT_CAPABILITY).ifPresent(h -> { h.setBalance(h.getBalance() + inventoryValue); }); NonNullList<ItemStack> inventory = this.getInventory(); for (int i = 0; i < sellSlots; i++) { // check if stack item is in itemValueList and has a value greater than zero if (itemList.contains(inventory.get(i).getItem().toString()) && (valueList.get(itemList.indexOf((inventory.get(i).getItem().toString()))) > 0)) { getSlot(i).putStack(ItemStack.EMPTY); } } inventoryValue = calculateInventoryValue(); } } the "sellItems" method is called on line 30 in this class. package com.garrett.backtobasics.blocks; import com.garrett.backtobasics.BackToBasics; import com.garrett.backtobasics.capabilities.BankAccount.BankAccountProvider; import com.mojang.blaze3d.platform.GlStateManager; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.client.gui.widget.button.Button; public class StoreScreen extends ContainerScreen<StoreContainer> { private ResourceLocation GUI = new ResourceLocation(BackToBasics.MODID, "textures/gui/store_inventory02.png"); private double playerBankBalance = 0; public StoreScreen(StoreContainer container, PlayerInventory inv, ITextComponent name) { super(container, inv, name); xSize = 200; ySize = 220; } @Override protected void init() { super.init(); //buttons.clear(); addButton(new Button(guiLeft + 31, guiTop + 110, 48, 20, "Sell", (button) -> { //do stuff container.sellItems(); })); } @Override public void render(int mouseX, int mouseY, float partialTicks) { this.renderBackground(); super.render(mouseX, mouseY, partialTicks); this.renderHoveredToolTip(mouseX, mouseY); } @Override protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { //drawString(Minecraft.getInstance().fontRenderer, "Auto-Miner", 10, 10, 434343); this.font.drawString("Store", (float) ((xSize / 2.0) - 15), 10,4210752); this.font.drawString(Integer.toString((int) container.getInventoryValue()), alignDigitsRight(container.getInventoryValue(), 9, 25), 100,4210752); playerInventory.player.getCapability(BankAccountProvider.BANK_ACCOUNT_CAPABILITY).ifPresent(h ->{ this.playerBankBalance = h.getBalance(); }); this.font.drawString("$" + ((int) this.playerBankBalance), alignDigitsRight(((int) this.playerBankBalance), 8, 25), 10,-16746496); } @Override protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); this.minecraft.getTextureManager().bindTexture(GUI); int relX = (this.width - this.xSize) / 2; int relY = (this.height - this.ySize) / 2; this.blit(relX, relY, 0, 0, this.xSize, this.ySize); } // generates x location that aligns text on the decimal point of a Double private int alignDigitsRight(double number, int maxLeadingDigits, int x) { int numDigits = Integer.toString((int) number).length(); int addedSpaces = 0; if (numDigits < maxLeadingDigits) { addedSpaces = maxLeadingDigits - numDigits; } return (addedSpaces * 6) + x; } }
  13. oh, that's right I forgot it was for LazyOptional, not just the regular optional.
  14. Please forgive my lack of java knowledge. I don't always realize something like an optional is part of java as opposed to forge/minecraft. if I had known, I would have looked into it as you suggested. I'm using minecraft modding as a way to get a deeper understanding of java. I learned java on code academy, because I don't have the money to go to college to learn java properly, and I don't have a mentor to help me. this has left many unknown gaps in my knowledge. sometimes I don't even know what I am lacking. I greatly appreciate all the help you and the others have given me. That being said, I must ask you to remember that helping people like me is always optional, and hostility helps no one. We are all human.
  15. ah, yup. now it works. It's very difficult to find information on how to create custom capabilities in 1.14. When I was first trying to learn how to create a custom capability, I threw a lot of spaghetti code at it just to figure things out. At some point I knew I needed a NonNullSupplier for holder.orelsethrow(???). so I created one and here's what Intellij gave me by default: NonNullSupplier<? extends NullPointerException> nonNullSupplier = new NonNullSupplier<NullPointerException>() { @Nonnull @Override public NullPointerException get() { return null; } } it returns null by default. Not knowing what it should actually be returning, I left it the way it was, and hey, it seemed to work. I didn't question it, because I know nothing about NonNullSuppliers. What should I be doing instead?
  16. I get a NullPointerException every time I load a game with my new capability: [21:11:11.880] [Server thread/INFO] [minecraft/MinecraftServer]: Dev joined the game [21:11:12.204] [Client thread/INFO] [minecraft/AdvancementList]: Loaded 0 advancements [21:11:12.749] [Server thread/INFO] [minecraft/IntegratedServer]: Saving and pausing game... [21:11:12.751] [Server thread/ERROR] [minecraft/MinecraftServer]: Encountered an unexpected exception net.minecraft.crash.ReportedException: Saving entity NBT at net.minecraft.entity.Entity.writeWithoutTypeId(Entity.java:1592) ~[?:?] {pl:accesstransformer:B} at net.minecraft.server.integrated.IntegratedPlayerList.writePlayerData(IntegratedPlayerList.java:27) ~[?:?] {pl:runtimedistcleaner:A} at net.minecraft.server.management.PlayerList.saveAllPlayerData(PlayerList.java:624) ~[?:?] {} at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:112) ~[?:?] {pl:runtimedistcleaner:A} at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:646) [?:?] {pl:accesstransformer:B} at java.lang.Thread.run(Thread.java:748) [?:1.8.0_221] {} Caused by: java.lang.NullPointerException at com.garrett.backtobasics.capabilities.BankAccount.BankAccountProvider.serializeNBT(BankAccountProvider.java:36) ~[?:?] {} at net.minecraftforge.common.capabilities.CapabilityDispatcher.serializeNBT(CapabilityDispatcher.java:127) ~[?:?] {} at net.minecraftforge.common.capabilities.CapabilityProvider.serializeCaps(CapabilityProvider.java:86) ~[?:?] {} at net.minecraft.entity.Entity.writeWithoutTypeId(Entity.java:1567) ~[?:?] {pl:accesstransformer:B} Here is the line that causes the exception: return BANK_ACCOUNT_CAPABILITY.getStorage().writeNBT(BANK_ACCOUNT_CAPABILITY, holder.orElseThrow(nonNullSupplier), null); it happens in line 36 of this class: package com.garrett.backtobasics.capabilities.BankAccount; import net.minecraft.nbt.INBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.NonNullSupplier; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BankAccountProvider implements ICapabilitySerializable<INBT> { @CapabilityInject(BankAccountCapability.class) public static Capability<BankAccountCapability> BANK_ACCOUNT_CAPABILITY = null; private final LazyOptional<BankAccountCapability> holder = LazyOptional.of(BankAccountCapability::new); @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return BANK_ACCOUNT_CAPABILITY.orEmpty(cap, holder); } @Override public INBT serializeNBT() { NonNullSupplier<? extends NullPointerException> nonNullSupplier = new NonNullSupplier<NullPointerException>() { @Nonnull @Override public NullPointerException get() { return null; } }; return BANK_ACCOUNT_CAPABILITY.getStorage().writeNBT(BANK_ACCOUNT_CAPABILITY, holder.orElseThrow(nonNullSupplier), null); } @Override public void deserializeNBT(INBT nbt) { NonNullSupplier<? extends NullPointerException> nonNullSupplier = new NonNullSupplier<NullPointerException>() { @Nonnull @Override public NullPointerException get() { return null; } }; BANK_ACCOUNT_CAPABILITY.getStorage().readNBT(BANK_ACCOUNT_CAPABILITY, holder.orElseThrow(nonNullSupplier), null, nbt); } } it's my first time creating a capability that attaches to players as apposed to the world, so I may have missed an extra step that might need to be taken when attaching capabilities to players. here is where I do the attaching: package com.garrett.backtobasics.capabilities; import com.garrett.backtobasics.BackToBasics; import com.garrett.backtobasics.capabilities.BankAccount.BankAccountProvider; import com.garrett.backtobasics.capabilities.blockpopulation.BlockPopulationProvider; import com.garrett.backtobasics.capabilities.itemvalues.ItemValuesProvider; import com.garrett.backtobasics.capabilities.saleitemlist.SaleItemListProvider; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; /** * Event handler used to attach capabilities */ public class BackToBasicsEventHandler { public static final ResourceLocation BLOCK_POPULATION_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "block_population"); public static final ResourceLocation BANK_ACCOUNT_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "bank_account"); public static final ResourceLocation ITEM_VALUES_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "item_values"); public static final ResourceLocation SALE_ITEM_LIST_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "sale_item_list"); @SubscribeEvent public void attachWorldCapability(AttachCapabilitiesEvent<World> event) { event.addCapability(BLOCK_POPULATION_CAPABILITY, new BlockPopulationProvider()); event.addCapability(ITEM_VALUES_CAPABILITY, new ItemValuesProvider()); } @SubscribeEvent public void attachEntityCapability(AttachCapabilitiesEvent<Entity> event) { if (event.getObject() instanceof PlayerEntity) { event.addCapability(BANK_ACCOUNT_CAPABILITY, new BankAccountProvider()); event.addCapability(SALE_ITEM_LIST_CAPABILITY, new SaleItemListProvider()); } } }
  17. I've been writing my own capabilities lately, and I'm not sure I understand the point of NBT. for example, in capability storage classes, you have "readNBT" and "writeNBT" methods. you could store data there, or in the capability class itself. In the case of my "Item Values" capability, which is attached to the world, I can simply interact with the capability directly with "world.getCapability(ItemValuesProvider.ITEM_VALUES_CAPABILITY)". What am I missing here?
  18. is that not what I am already doing? do you mean something like this: @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) { // drops everything in the inventory worldIn.getTileEntity(pos).getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { for (int i = 0; i < h.getSlots(); i++) { spawnAsEntity(worldIn, pos, h.getStackInSlot(i)); } }); worldIn.removeTileEntity(pos); } }
  19. oops, that's not entirely correct. I forgot I removed the part that is there by default that removes the tile entity. here's the real solution: @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { // drops everything in the inventory worldIn.getTileEntity(pos).getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { for (int i = 0; i < h.getSlots(); i++) { spawnAsEntity(worldIn, pos, h.getStackInSlot(i)); } }); if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) { worldIn.removeTileEntity(pos); } }
  20. ah, I needed to get the item handler. thanks! @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { worldIn.getTileEntity(pos).getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { for (int i = 0; i < h.getSlots(); i++) { spawnAsEntity(worldIn, pos, h.getStackInSlot(i)); } }); }
  21. That's how AbstractFurnaceBlock, as you mentioned before, seems to do it in 1.14.4-28.0.45: public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) { TileEntity tileentity = worldIn.getTileEntity(pos); if (tileentity instanceof AbstractFurnaceTileEntity) { InventoryHelper.dropInventoryItems(worldIn, pos, (AbstractFurnaceTileEntity)tileentity); worldIn.updateComparatorOutputLevel(pos, this); } super.onReplaced(state, worldIn, pos, newState, isMoving); } } I don't know why it takes a tile entity as the last parameter instead of an inventory in AbstractFurnaceBlock. when I look at InventoryHelper, the last parameter is always IInventory. package net.minecraft.inventory; import java.util.Random; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class InventoryHelper { private static final Random RANDOM = new Random(); public static void dropInventoryItems(World worldIn, BlockPos pos, IInventory inventory) { dropInventoryItems(worldIn, (double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), inventory); } public static void dropInventoryItems(World worldIn, Entity entityAt, IInventory inventory) { dropInventoryItems(worldIn, entityAt.posX, entityAt.posY, entityAt.posZ, inventory); } private static void dropInventoryItems(World worldIn, double x, double y, double z, IInventory inventory) { for(int i = 0; i < inventory.getSizeInventory(); ++i) { spawnItemStack(worldIn, x, y, z, inventory.getStackInSlot(i)); } } public static void dropItems(World p_219961_0_, BlockPos p_219961_1_, NonNullList<ItemStack> p_219961_2_) { p_219961_2_.forEach((p_219962_2_) -> { spawnItemStack(p_219961_0_, (double)p_219961_1_.getX(), (double)p_219961_1_.getY(), (double)p_219961_1_.getZ(), p_219962_2_); }); } public static void spawnItemStack(World worldIn, double x, double y, double z, ItemStack stack) { double d0 = (double)EntityType.ITEM.getWidth(); double d1 = 1.0D - d0; double d2 = d0 / 2.0D; double d3 = Math.floor(x) + RANDOM.nextDouble() * d1 + d2; double d4 = Math.floor(y) + RANDOM.nextDouble() * d1; double d5 = Math.floor(z) + RANDOM.nextDouble() * d1 + d2; while(!stack.isEmpty()) { ItemEntity itementity = new ItemEntity(worldIn, d3, d4, d5, stack.split(RANDOM.nextInt(21) + 10)); float f = 0.05F; itementity.setMotion(RANDOM.nextGaussian() * (double)0.05F, RANDOM.nextGaussian() * (double)0.05F + (double)0.2F, RANDOM.nextGaussian() * (double)0.05F); worldIn.addEntity(itementity); } } }
  22. how do I get the my blocks inventory from within the blocks class for "dropInventoryItems(World worldIn, BlockPos pos, IInventory inventory)" @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { InventoryHelper.dropInventoryItems(worldIn, pos, ???); }
  23. I can't, for the life of me, find the way vanilla blocks drop their inventory when they are destroyed, nor can I find a forum post that explains it. do I add something to the blocks "onPlayerDestroy" method? do I do something in the container class? [SOLUTION]------------------------------------------------------------------------------------------------ add this to your block class @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) { // drops everything in the inventory worldIn.getTileEntity(pos).getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { for (int i = 0; i < h.getSlots(); i++) { spawnAsEntity(worldIn, pos, h.getStackInSlot(i)); } }); worldIn.removeTileEntity(pos); } }
×
×
  • Create New...

Important Information

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