Jump to content

andGarrett

Members
  • Posts

    101
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by andGarrett

  1. hmm, I thought I did, but after double checking, there were some key aspects of the static keyword that I had either forgotten or never learnt. I could just create a static method essentially anywhere that would return the list. I feel silly for not remembering this is possible in java. Sorry to bring a java issue to a forge form
  2. where would I put this static variable, and how would I access it? I know I wouldn't want to put it in a block class as it would need to compute the list every time a such a block was created.
  3. for now what I did is pointless, as I don't need to change any data in the capability yet, but I was able to learn how to work with ListNBT and CompoundNBT. what if I never need to change any data? how might I code the write method in such a case? here's what I did: @Nullable @Override public ListNBT writeNBT(Capability<ItemValues> capability, ItemValues instance, Direction side) { ListNBT itemValueListNBT = new ListNBT(); int index = 0; for (TradeItem tradeItem:instance.getItemValueList()) { CompoundNBT compoundNBT = new CompoundNBT(); compoundNBT.putString("item", tradeItem.getItemRegistryName()); compoundNBT.putDouble("value", tradeItem.getMonetaryValue()); itemValueListNBT.add(index, compoundNBT); index++; } return itemValueListNBT; }
  4. I've got and arraylist of objects. the objects contain a string and a double. the purpose of this list is to contain monetary value for every item in the game. it's basically the Energy-Matter Currency (EMC) from "Equivalent Exchange." I started writing a capability to store the array. I'm not sure how to write the storage class for this capability. specifically the read and write methods. I tried returning a compoundNBT in the read method, but I don't yet understand compoundNBT, and I'm not even sure that's what I should be returning. package com.Garrett.backtobasics.capabilities.itemValues; import com.Garrett.backtobasics.capabilities.blockPopulation.IBlockPopulation; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; import net.minecraft.nbt.IntNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; public class ItemValuesStorage implements Capability.IStorage<ItemValues> { @Nullable @Override public CompoundNBT writeNBT(Capability<ItemValues> capability, ItemValues instance, Direction side) { return new CompoundNBT(instance.getValueList()); } @Override public void readNBT(Capability<ItemValues> capability, ItemValues instance, Direction side, INBT nbt) { } }
  5. I put log statements where I was changing the values for the capability: @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { worldIn.getCapability(BlockPopulationProvider.BLOCK_POPULATION_CAPABILITY).ifPresent(cap -> { cap.addStore(); LOGGER.info("onBlockPlacedBY"); LOGGER.info("world.isRemote = " + worldIn.isRemote + ", number of stores: " + cap.getStores()); }); } whenever I place the block that has this in its block class, I get two sets of logs like these: [13:56:19.942] [Client thread/INFO] [minecraft/Block]: onBlockPlacedBY [13:56:19.942] [Client thread/INFO] [minecraft/Block]: world.isRemote = true, number of stores: 1 [13:56:19.944] [Server thread/INFO] [minecraft/Block]: onBlockPlacedBY [13:56:19.944] [Server thread/INFO] [minecraft/Block]: world.isRemote = false, number of stores: 16 now that I look at it though, I see that it's on the client thread that the number is resetting. If it's on the "Client thread" thread, why does it say the world is remote? does that mean that even when I'm playing on my own, the world is always considered remote from the client side? I had assumed that when the world is remote, the code being run was on the server side. should I just ignore the client side information?
  6. I registered it in my main mod class. search "banana" to find the lines: package com.Garrett.backtobasics; import com.Garrett.backtobasics.blocks.*; import com.Garrett.backtobasics.capabilities.BackToBasicsEventHandler; import com.Garrett.backtobasics.capabilities.BlockPopulation; import com.Garrett.backtobasics.capabilities.BlockPopulationStorage; import com.Garrett.backtobasics.capabilities.IBlockPopulation; import com.Garrett.backtobasics.items.*; import com.Garrett.backtobasics.world.OreGeneration; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.extensions.IForgeContainerType; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.Garrett.backtobasics.setup.ModSetup; import com.Garrett.backtobasics.setup.*; import java.util.stream.Collectors; // The value here should match an entry in the META-INF/mods.toml file @Mod("backtobasics") public class BackToBasics { public static final String MODID = "backtobasics"; public static ModSetup setup = new ModSetup(); public static IProxy proxy = DistExecutor.runForDist(() -> () -> new ClientProxy(), () -> () -> new ServerProxy()); // Directly reference a log4j logger. private static final Logger LOGGER = LogManager.getLogger(); public BackToBasics() { // Register the setup method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); // Register the enqueueIMC method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC); // Register the processIMC method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC); // Register the doClientStuff method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff); // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); // BTB Register my custom events BackToBasicsEventHandler backToBasicsEventHandler = new BackToBasicsEventHandler(); MinecraftForge.EVENT_BUS.register(backToBasicsEventHandler); // banana } private void setup(final FMLCommonSetupEvent event) { // some preinit code setup.init(); proxy.init(); LOGGER.info("HELLO FROM PREINIT"); LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName()); // BTB OreGeneration.setupOreGeneration(); // BTB CapabilityManager.INSTANCE.register(IBlockPopulation.class, new BlockPopulationStorage(), BlockPopulation::new); // banana } private void doClientStuff(final FMLClientSetupEvent event) { // do something that can only be done on the client LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().gameSettings); } private void enqueueIMC(final InterModEnqueueEvent event) { // some example code to dispatch IMC to another mod InterModComms.sendTo("backtobasics", "helloworld", () -> { LOGGER.info("Hello world from the MDK"); return "Hello world";}); } private void processIMC(final InterModProcessEvent event) { // some example code to receive and process InterModComms from other mods LOGGER.info("Got IMC {}", event.getIMCStream(). map(m->m.getMessageSupplier().get()). collect(Collectors.toList())); } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(FMLServerStartingEvent event) { // do something when the server starts LOGGER.info("HELLO from server starting"); } // You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD // Event bus for receiving Registry Events) @Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD) public static class RegistryEvents { @SubscribeEvent public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent) { // register a new block here LOGGER.info("HELLO from Register Block"); blockRegistryEvent.getRegistry().register(new AutoMiner()); blockRegistryEvent.getRegistry().register(new Store()); blockRegistryEvent.getRegistry().register(new DiamondVein()); blockRegistryEvent.getRegistry().register(new GoldVein()); blockRegistryEvent.getRegistry().register(new IronVein()); blockRegistryEvent.getRegistry().register(new RedstoneVein()); } @SubscribeEvent public static void onItemRegistry(final RegistryEvent.Register<Item> ItemRegistryEvent) { // register a new item here Item.Properties properties = new Item.Properties() .group(setup.itemGroup); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.AUTO_MINER, properties).setRegistryName("backtobasics:auto_miner")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.STORE, properties).setRegistryName("backtobasics:store")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.DIAMOND_VEIN, properties).setRegistryName("backtobasics:diamond_vein")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.GOLD_VEIN, properties).setRegistryName("backtobasics:gold_vein")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.IRON_VEIN, properties).setRegistryName("backtobasics:iron_vein")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.REDSTONE_VEIN, properties).setRegistryName("backtobasics:redstone_vein")); ItemRegistryEvent.getRegistry().register(new UnrefinedIron()); ItemRegistryEvent.getRegistry().register(new UnrefinedIronBits()); ItemRegistryEvent.getRegistry().register(new UnrefinedGold()); ItemRegistryEvent.getRegistry().register(new UnrefinedGoldBits()); ItemRegistryEvent.getRegistry().register(new DiamondBits()); ItemRegistryEvent.getRegistry().register(new RedstoneBits()); //LOGGER.info("banana"); //LOGGER.info(ItemRegistryEvent.getRegistry().getValues()); } @SubscribeEvent public static void onTileEntityRegistry(final RegistryEvent.Register<TileEntityType<?>> event) { event.getRegistry().register(TileEntityType.Builder.create(AutoMinerTileEntity::new, ModBlocks.AUTO_MINER).build(null).setRegistryName("auto_miner")); event.getRegistry().register(TileEntityType.Builder.create(StoreTileEntity::new, ModBlocks.STORE).build(null).setRegistryName("store")); } @SubscribeEvent public static void onContainerRegistry(final RegistryEvent.Register<ContainerType<?>> event) { event.getRegistry().register(IForgeContainerType.create((windowId, inv, data) -> { BlockPos pos = data.readBlockPos(); return new AutoMinerContainer(windowId, BackToBasics.proxy.getClientWorld(), pos, inv, BackToBasics.proxy.getClientPlayer()); }).setRegistryName("auto_miner")); event.getRegistry().register(IForgeContainerType.create((windowId, inv, data) -> { BlockPos pos = data.readBlockPos(); return new StoreContainer(windowId, BackToBasics.proxy.getClientWorld(), pos, inv, BackToBasics.proxy.getClientPlayer()); }).setRegistryName("store")); } } } here is where I attach the capabiltiy: package com.Garrett.backtobasics.capabilities; import com.Garrett.backtobasics.BackToBasics; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; /** * Event handler */ public class BackToBasicsEventHandler { public static final ResourceLocation BLOCK_POPULATION_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "block_population"); @SubscribeEvent public void attachCapability(AttachCapabilitiesEvent<World> event) { if (!(event.getObject() instanceof World)) return; event.addCapability(BLOCK_POPULATION_CAPABILITY, new BlockPopulationProvider()); } }
  7. oooooooooh, I thought you meant something else, lol. I know that that is. I put them in the "writeNBT" method as well as the "readNBT" method. it only seems to be happening on the client. maybe it has something to do with how I registered it in my main mod class? CapabilityManager.INSTANCE.register(IBlockPopulation.class, new BlockPopulationStorage(), BlockPopulation::new);
  8. are you talking about this one in BlockPopulationStorage? @Nullable @Override public INBT writeNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side) { return new IntNBT(instance.getStores()); }
  9. every time I load up one of my worlds, my "BlockPopulation" capability on the server side seems to reset back to zero. I suspect that it's creating a new instance of the capability every time I load the world, but only on the server side. I think it has something to do with my capability storage class. [SOLUTION] I thought that if code was being executed on the client side that (World.isRemote) would return false, but it's the other way around. This led me to think there was a problem when actually there wasn't. BlockPopulationStorage package com.Garrett.backtobasics.capabilities; import net.minecraft.nbt.INBT; import net.minecraft.nbt.IntNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; /** * This class is responsible for saving and reading block population data from/to the server */ public class BlockPopulationStorage implements Capability.IStorage<IBlockPopulation> { private static final Logger LOGGER = LogManager.getLogger(); @Nullable @Override public INBT writeNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side) { return new IntNBT(instance.getStores()); } @Override public void readNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side, INBT nbt) { instance.setStores(((IntNBT) nbt).getInt()); } } Here is where I change the values in my BlockPopulation capability (in the "onBlockPlacedBy" method): package com.Garrett.backtobasics.blocks; import com.Garrett.backtobasics.capabilities.BlockPopulationProvider; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.fml.network.NetworkHooks; import javax.annotation.Nullable; public class AutoMiner extends Block { public AutoMiner() { super(Properties .create(Material.IRON) .sound(SoundType.METAL) .hardnessAndResistance(10, 15) .lightValue(0) .harvestLevel(0) ); setRegistryName("backtobasics:auto_miner"); } @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { LOGGER.info("onBlockPlacedBY"); LOGGER.info("world.isRemote = " + worldIn.isRemote); worldIn.getCapability(BlockPopulationProvider.BLOCK_POPULATION_CAPABILITY).ifPresent(h -> { h.addStore(); LOGGER.info("number of stores: " + h.getStores()); }); } @Override public boolean hasTileEntity(BlockState state) { return true; } @Nullable @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new AutoMinerTileEntity(); } // tells block what way to face when placed @Nullable @Override public BlockState getStateForPlacement(BlockItemUseContext context) { BlockState blockstate = super.getStateForPlacement(context); if (blockstate != null) { blockstate = blockstate.with(BlockStateProperties.FACING, context.getNearestLookingDirection()); } return blockstate; } @Override public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult result) { if (!world.isRemote) { TileEntity tileEntity = world.getTileEntity(pos); if (tileEntity instanceof INamedContainerProvider) { NetworkHooks.openGui((ServerPlayerEntity) player, (INamedContainerProvider) tileEntity, tileEntity.getPos()); } else { throw new IllegalStateException("Our named container provider is missing!"); } return true; } return super.onBlockActivated(state, world, pos, player, hand, result); } // adds support for "facing" property in block states json files @Override protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) { builder.add(BlockStateProperties.FACING); } } here are the other classes that are involved, in case they are needed: BlockPopulationProvider package com.Garrett.backtobasics.capabilities; 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 BlockPopulationProvider implements ICapabilitySerializable<INBT> { @CapabilityInject(IBlockPopulation.class) public static Capability<IBlockPopulation> BLOCK_POPULATION_CAPABILITY = null; private final LazyOptional<IBlockPopulation> holder = LazyOptional.of(BlockPopulation::new); @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return cap == BLOCK_POPULATION_CAPABILITY ? holder.cast() : LazyOptional.empty(); } @Override public INBT serializeNBT() { NonNullSupplier<IBlockPopulation> nonNullSupplier = new NonNullSupplier<IBlockPopulation>() { @Nonnull @Override public IBlockPopulation get() { return null; } }; return BLOCK_POPULATION_CAPABILITY.getStorage().writeNBT(BLOCK_POPULATION_CAPABILITY, holder.orElseGet(nonNullSupplier), null); } @Override public void deserializeNBT(INBT nbt) { NonNullSupplier<IBlockPopulation> nonNullSupplier = new NonNullSupplier<IBlockPopulation>() { @Nonnull @Override public IBlockPopulation get() { return null; } }; BLOCK_POPULATION_CAPABILITY.getStorage().readNBT(BLOCK_POPULATION_CAPABILITY, holder.orElseGet(nonNullSupplier), null, nbt); } } BackToBasicsEventHandler package com.Garrett.backtobasics.capabilities; import com.Garrett.backtobasics.BackToBasics; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; /** * Event handler */ public class BackToBasicsEventHandler { public static final ResourceLocation BLOCK_POPULATION_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "block_population"); @SubscribeEvent public void attachCapability(AttachCapabilitiesEvent<World> event) { if (!(event.getObject() instanceof World)) return; event.addCapability(BLOCK_POPULATION_CAPABILITY, new BlockPopulationProvider()); } }
  10. why might I want to use a static event handler vs a non-static event handler?
  11. ♥♥♥yup, that was it. Thanks for all the help!♥♥♥
  12. just checked to see if the capability is present in the onBlockPlaced method for the AutoMiner block, and it never is. wish I had more time to work on this but I must sleep
  13. I was able to get everything set up so that there are no errors, but something still isn't right. I'm not sure if it's something to do with how I subscribed the event or how I'm using the capability. I'm testing it out on one of my blocks in it's onBlockPlacedBy method. nothing seems to happen inside the the lambda expression where I placed: h.addStore(); LOGGER.info("number of stores: " + h.getStores());. Intellij also tells me that when I use "worldIn.getCapability(BlockPopulationProvider.BLOCK_POPULATION_CAPABILITY)..." I am "passing null argument to parameter annotated as @NonNull." package com.Garrett.backtobasics.blocks; import com.Garrett.backtobasics.capabilities.BlockPopulationProvider; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.fml.network.NetworkHooks; import javax.annotation.Nullable; public class AutoMiner extends Block { public AutoMiner() { super(Properties .create(Material.IRON) .sound(SoundType.METAL) .hardnessAndResistance(10, 15) .lightValue(0) .harvestLevel(0) ); setRegistryName("backtobasics:auto_miner"); } @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { LOGGER.info("onBlockPlacedBY"); worldIn.getCapability(BlockPopulationProvider.BLOCK_POPULATION_CAPABILITY).ifPresent(h -> { h.addStore(); LOGGER.info("number of stores: " + h.getStores()); }); } @Override public boolean hasTileEntity(BlockState state) { return true; } @Nullable @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new AutoMinerTileEntity(); } // tells block what way to face when placed @Nullable @Override public BlockState getStateForPlacement(BlockItemUseContext context) { BlockState blockstate = super.getStateForPlacement(context); if (blockstate != null) { blockstate = blockstate.with(BlockStateProperties.FACING, context.getNearestLookingDirection()); } return blockstate; } @Override public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult result) { if (!world.isRemote) { TileEntity tileEntity = world.getTileEntity(pos); if (tileEntity instanceof INamedContainerProvider) { NetworkHooks.openGui((ServerPlayerEntity) player, (INamedContainerProvider) tileEntity, tileEntity.getPos()); } else { throw new IllegalStateException("Our named container provider is missing!"); } return true; } return super.onBlockActivated(state, world, pos, player, hand, result); } // adds support for "facing" property in block states json files @Override protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) { builder.add(BlockStateProperties.FACING); } } Here's where I subscribed the event: package com.Garrett.backtobasics.capabilities; import com.Garrett.backtobasics.BackToBasics; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; /** * Event handler */ public class BackToBasicsEventHandler { public static final ResourceLocation BLOCK_POPULATION_CAPABILITY = new ResourceLocation(BackToBasics.MODID, "block_population"); @SubscribeEvent public void attachCapability(AttachCapabilitiesEvent<World> event) { if (!(event.getObject() instanceof World)) return; event.addCapability(BLOCK_POPULATION_CAPABILITY, new BlockPopulationProvider()); } } Finally, here is how I registered the event handler in my main mod class in it's constructer. "MinecraftForge.EVENT_BUS.register(BackToBasicsEventHandler.class);" package com.Garrett.backtobasics; import com.Garrett.backtobasics.blocks.*; import com.Garrett.backtobasics.capabilities.BackToBasicsEventHandler; import com.Garrett.backtobasics.capabilities.BlockPopulation; import com.Garrett.backtobasics.capabilities.BlockPopulationStorage; import com.Garrett.backtobasics.capabilities.IBlockPopulation; import com.Garrett.backtobasics.items.*; import com.Garrett.backtobasics.world.OreGeneration; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.extensions.IForgeContainerType; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.Garrett.backtobasics.setup.ModSetup; import com.Garrett.backtobasics.setup.*; import java.util.stream.Collectors; // The value here should match an entry in the META-INF/mods.toml file @Mod("backtobasics") public class BackToBasics { public static final String MODID = "backtobasics"; public static ModSetup setup = new ModSetup(); public static IProxy proxy = DistExecutor.runForDist(() -> () -> new ClientProxy(), () -> () -> new ServerProxy()); // Directly reference a log4j logger. private static final Logger LOGGER = LogManager.getLogger(); public BackToBasics() { // Register the setup method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); // Register the enqueueIMC method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC); // Register the processIMC method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC); // Register the doClientStuff method for modloading FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff); // Register ourselves for server and other game events we are interested in MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(BackToBasicsEventHandler.class); } private void setup(final FMLCommonSetupEvent event) { // some preinit code setup.init(); proxy.init(); LOGGER.info("HELLO FROM PREINIT"); LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName()); OreGeneration.setupOreGeneration(); CapabilityManager.INSTANCE.register(IBlockPopulation.class, new BlockPopulationStorage(), BlockPopulation::new); } private void doClientStuff(final FMLClientSetupEvent event) { // do something that can only be done on the client LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().gameSettings); } private void enqueueIMC(final InterModEnqueueEvent event) { // some example code to dispatch IMC to another mod InterModComms.sendTo("backtobasics", "helloworld", () -> { LOGGER.info("Hello world from the MDK"); return "Hello world";}); } private void processIMC(final InterModProcessEvent event) { // some example code to receive and process InterModComms from other mods LOGGER.info("Got IMC {}", event.getIMCStream(). map(m->m.getMessageSupplier().get()). collect(Collectors.toList())); } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent public void onServerStarting(FMLServerStartingEvent event) { // do something when the server starts LOGGER.info("HELLO from server starting"); } // You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD // Event bus for receiving Registry Events) @Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD) public static class RegistryEvents { @SubscribeEvent public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent) { // register a new block here LOGGER.info("HELLO from Register Block"); blockRegistryEvent.getRegistry().register(new AutoMiner()); blockRegistryEvent.getRegistry().register(new Store()); blockRegistryEvent.getRegistry().register(new DiamondVein()); blockRegistryEvent.getRegistry().register(new GoldVein()); blockRegistryEvent.getRegistry().register(new IronVein()); blockRegistryEvent.getRegistry().register(new RedstoneVein()); } @SubscribeEvent public static void onItemRegistry(final RegistryEvent.Register<Item> ItemRegistryEvent) { // register a new item here Item.Properties properties = new Item.Properties() .group(setup.itemGroup); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.AUTO_MINER, properties).setRegistryName("backtobasics:auto_miner")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.STORE, properties).setRegistryName("backtobasics:store")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.DIAMOND_VEIN, properties).setRegistryName("backtobasics:diamond_vein")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.GOLD_VEIN, properties).setRegistryName("backtobasics:gold_vein")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.IRON_VEIN, properties).setRegistryName("backtobasics:iron_vein")); ItemRegistryEvent.getRegistry().register(new BlockItem(ModBlocks.REDSTONE_VEIN, properties).setRegistryName("backtobasics:redstone_vein")); ItemRegistryEvent.getRegistry().register(new UnrefinedIron()); ItemRegistryEvent.getRegistry().register(new UnrefinedIronBits()); ItemRegistryEvent.getRegistry().register(new UnrefinedGold()); ItemRegistryEvent.getRegistry().register(new UnrefinedGoldBits()); ItemRegistryEvent.getRegistry().register(new DiamondBits()); ItemRegistryEvent.getRegistry().register(new RedstoneBits()); //LOGGER.info("banana"); //LOGGER.info(ItemRegistryEvent.getRegistry().getValues()); } @SubscribeEvent public static void onTileEntityRegistry(final RegistryEvent.Register<TileEntityType<?>> event) { event.getRegistry().register(TileEntityType.Builder.create(AutoMinerTileEntity::new, ModBlocks.AUTO_MINER).build(null).setRegistryName("auto_miner")); event.getRegistry().register(TileEntityType.Builder.create(StoreTileEntity::new, ModBlocks.STORE).build(null).setRegistryName("store")); } @SubscribeEvent public static void onContainerRegistry(final RegistryEvent.Register<ContainerType<?>> event) { event.getRegistry().register(IForgeContainerType.create((windowId, inv, data) -> { BlockPos pos = data.readBlockPos(); return new AutoMinerContainer(windowId, BackToBasics.proxy.getClientWorld(), pos, inv, BackToBasics.proxy.getClientPlayer()); }).setRegistryName("auto_miner")); event.getRegistry().register(IForgeContainerType.create((windowId, inv, data) -> { BlockPos pos = data.readBlockPos(); return new StoreContainer(windowId, BackToBasics.proxy.getClientWorld(), pos, inv, BackToBasics.proxy.getClientPlayer()); }).setRegistryName("store")); } } }
  14. I'm trying to create my own custom capability to store data described here and using this guide. There are a few things I need help with: 1. in the guide he says " You need to register this event handler to MinecraftForge.EVENT_BUS in your common proxy." I'm guessing "common proxy" is from 1.12-1.13 and I would need to register the event in my main mod class in the same area as I register blocks, item, and tile entities. if so, how, and if not where would I register the event? 2. in my "BlockPopulationStorage" class, I'm not sure if NBTPrimitive (copied from said guide) is from and older version of forge or what. I can't seem to find it in 1.14. 3. in my "BlockPopulationProvider" class, I'm not sure what to replace "this.instance" with in both the "serializeNBT" and "deserializeNBT" methods. in this post diesieben07 suggests removing the instance field. BlockPopulationStorage class package com.Garrett.backtobasics.capabilities; import net.minecraft.nbt.INBT; import net.minecraft.nbt.IntNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import javax.annotation.Nullable; /** * This class is responsible for saving and reading block population data from or to server */ public class BlockPopulationStorage implements Capability.IStorage<IBlockPopulation> { @Nullable @Override public INBT writeNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side) { return new IntNBT(instance.getStores()); } @Override public void readNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side, INBT nbt) { instance.setStores(((NBTPrimitive) nbt).getInt()); } } BlockPopulationProvider class package com.Garrett.backtobasics.capabilities; 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 javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockPopulationProvider implements ICapabilitySerializable<INBT> { @CapabilityInject(IBlockPopulation.class) private static final Capability<IBlockPopulation> BLOCK_POPULATION_CAPABILITY = null; //private IBlockPopulation instance = BLOCK_POPULATION_CAPABILITY.getDefaultInstance(); private final LazyOptional<IBlockPopulation> holder = LazyOptional.of(BlockPopulation::new); @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return cap == BLOCK_POPULATION_CAPABILITY ? holder.cast() : LazyOptional.empty(); } @Override public INBT serializeNBT() { return BLOCK_POPULATION_CAPABILITY.getStorage().writeNBT(BLOCK_POPULATION_CAPABILITY, this.instance, null); } @Override public void deserializeNBT(INBT nbt) { BLOCK_POPULATION_CAPABILITY.getStorage().readNBT(BLOCK_POPULATION_CAPABILITY, this.instance, null, nbt); } } [SOLUTION]------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1. You should use @EventBusSubscriber to register your event handlers. Read the documentation about events. 2. in my case I needed to use "IntNBT". for a full list of nbt types look in net.minecraft.nbt.INBT. 3. I'm not sure I'm doing this the right way, but it seems to work: I created a "NonNullSupplier": NonNullSupplier<IBlockPopulation> nonNullSupplier = new NonNullSupplier<IBlockPopulation>() { @Nonnull @Override public IBlockPopulation get() { return null; } }; then I used holder.orElseGet(nonNullSupplier) in place of "this.instance" BlockPopulationStorage class package com.Garrett.backtobasics.capabilities; import net.minecraft.nbt.INBT; import net.minecraft.nbt.IntNBT; import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import javax.annotation.Nullable; /** * This class is responsible for saving and reading block population data from or to server */ public class BlockPopulationStorage implements Capability.IStorage<IBlockPopulation> { @Nullable @Override public INBT writeNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side) { return new IntNBT(instance.getStores()); } @Override public void readNBT(Capability<IBlockPopulation> capability, IBlockPopulation instance, Direction side, INBT nbt) { instance.setStores(((IntNBT) nbt).getInt()); } } BlockPopulationProvider class package com.Garrett.backtobasics.capabilities; 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 BlockPopulationProvider implements ICapabilitySerializable<INBT> { @CapabilityInject(IBlockPopulation.class) public static Capability<IBlockPopulation> BLOCK_POPULATION_CAPABILITY = null; private final LazyOptional<IBlockPopulation> holder = LazyOptional.of(BlockPopulation::new); @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return cap == BLOCK_POPULATION_CAPABILITY ? holder.cast() : LazyOptional.empty(); } @Override public INBT serializeNBT() { NonNullSupplier<IBlockPopulation> nonNullSupplier = new NonNullSupplier<IBlockPopulation>() { @Nonnull @Override public IBlockPopulation get() { return null; } }; return BLOCK_POPULATION_CAPABILITY.getStorage().writeNBT(BLOCK_POPULATION_CAPABILITY, holder.orElseGet(nonNullSupplier), null); } @Override public void deserializeNBT(INBT nbt) { NonNullSupplier<IBlockPopulation> nonNullSupplier = new NonNullSupplier<IBlockPopulation>() { @Nonnull @Override public IBlockPopulation get() { return null; } }; BLOCK_POPULATION_CAPABILITY.getStorage().readNBT(BLOCK_POPULATION_CAPABILITY, holder.orElseGet(nonNullSupplier), null, nbt); } }
  15. oh, I assumed WorldSavedData was in some way connected to capabilities.
  16. It's True that capabilities are still the answer, but the explanation on how to use them is no longer completely accurate, at least when it comes to saving data to the world. for example in the section about worldSavedData, there is an example given for creating a static get method. in the method they use "world.getMapStorage()" and "world.getPerWorldStorage()". neither exist in 1.14.4. MapStorage is used, but doesn't exist in 1.14.4. I'm sure there are other such examples, but you get the point. Things have changed. is there any documentation for 1.14 anywhere?
  17. the documentation on capabilities you linked is for 1.13 and doesn't seem to be accurate anymore. you wouldn't happen to have a link to either an example or a guide? I'm struggling to figure this out simply by looking at the classes.
  18. I'm going to create something like Equivalent Exchange's Equal-Matter Currency (EMC). For those who never used EE, it has an EMC value for each item. this EMC value is used for transmuting one type of item to another like cobblestone into iron. is there any inbuilt system like that in forge? is there any universal system that most modders use?
  19. it does. turns out the problem was that I was working with a block that was placed before I changed the iitemhandler size from 1 to 16. once I placed a new block, it worked perfectly. Thanks for the input.
  20. I'm trying to create a block with a 16 slot inventory. I have no trouble adding one slot using mcjty's tutorial, but after that I get all kinds of problems. on line 39 I try to add another slot. if I set the index to 0, it simply mirrors the first slot. it has the same item in it. if I use any number other than 0 for the index, for example 4, I get: java.lang.RuntimeException: Slot 4 not in valid range - [0,1) package com.Garrett.backtobasics.blocks; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; 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.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; public class StoreContainer extends Container { private TileEntity tileEntity; private PlayerEntity playerEntity; private IItemHandler playerInventory; 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); tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { addSlot(new SlotItemHandler(h, 0, 8, 23)); addSlot(new SlotItemHandler(h, 1, 26, 23)); }); layoutPlayerInventorySlots(20, 138); } @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, 25, leftCol, topRow, 9, 18, 3, 18); // Hotbar topRow += 58; addSlotRange(playerInventory, 16, leftCol, topRow, 9, 18); } /* * Handle 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) { ItemStack itemstack = ItemStack.EMPTY; Slot slot = this.inventorySlots.get(index); if (slot != null && slot.getHasStack()) { ItemStack itemstack1 = slot.getStack(); itemstack = itemstack1.copy(); if (index == 0) { if (!this.mergeItemStack(itemstack1, 1, this.inventorySlots.size(), true)) { return ItemStack.EMPTY; } } else if (!this.mergeItemStack(itemstack1, 0, 1, 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) { for (int i = 0; i < columns; i++) { for (int j = 0; j < rows; j++) { } } } */ } [SOLUTION] the problem was that I was working with a block that was placed before I changed the IItemHandler size from 1 to 16
  21. After some fiddling, I was able to use ChestContainer#transferStackInSlot. Check solution at the top of the post for what I did. good luck with the youtube tutorials btw.
  22. every time I shift click an item in my custom blocks inventory, "slotClick" gets stuck in a loop. at line 170 where "transferStackInSlot" is used, there is a for loop whose termination condition always returns true. the condition is (!itemstack7.isEmpty() && ItemStack.areItemsEqual(slot5.getStack(), itemstack7)). I'm guessing that the line (itemstack = itemstack7.copy();) is supposed to make (ItemStack.areItemsEqual(slot5.getStack(), itemstack7)) false, but its not. not sure how to proceed. any help is greatly appreciated. package com.Garrett.backtobasics.blocks; import com.google.common.collect.Sets; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ClickType; import net.minecraft.inventory.container.Container; 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.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.AUTO_MINER_CONTAINER; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Set; public class AutoMinerContainer extends Container { private TileEntity tileEntity; private PlayerEntity playerEntity; private IItemHandler playerInventory; private static final Logger LOGGER = LogManager.getLogger(); private int dragMode = -1; private int dragEvent; private final Set<Slot> dragSlots = Sets.newHashSet(); public AutoMinerContainer(int windowId, World world, BlockPos pos, PlayerInventory PlayerInventory, PlayerEntity player) { super(AUTO_MINER_CONTAINER, windowId); tileEntity = world.getTileEntity(pos); this.playerEntity = player; this.playerInventory = new InvWrapper(PlayerInventory); tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { addSlot(new SlotItemHandler(h, 0, 82, 24)); // x and y positions should be multiples of 8 }); layoutPlayerInventorySlots(10, 70); } @Override public boolean canInteractWith(PlayerEntity playerIn) { return isWithinUsableDistance(IWorldPosCallable.of(tileEntity.getWorld(), tileEntity.getPos()), playerEntity, ModBlocks.AUTO_MINER); } 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); } @Nonnull @Override public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { Slot slot = this.inventorySlots.get(index); return slot != null ? slot.getStack() : ItemStack.EMPTY; } @Override public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, PlayerEntity player) { ItemStack itemstack = ItemStack.EMPTY; PlayerInventory playerinventory = player.inventory; if (clickTypeIn == ClickType.QUICK_CRAFT) { int j1 = this.dragEvent; this.dragEvent = getDragEvent(dragType); if ((j1 != 1 || this.dragEvent != 2) && j1 != this.dragEvent) { this.resetDrag(); } else if (playerinventory.getItemStack().isEmpty()) { this.resetDrag(); } else if (this.dragEvent == 0) { this.dragMode = extractDragMode(dragType); if (isValidDragMode(this.dragMode, player)) { this.dragEvent = 1; this.dragSlots.clear(); } else { this.resetDrag(); } } else if (this.dragEvent == 1) { Slot slot7 = this.inventorySlots.get(slotId); ItemStack itemstack12 = playerinventory.getItemStack(); if (slot7 != null && canAddItemToSlot(slot7, itemstack12, true) && slot7.isItemValid(itemstack12) && (this.dragMode == 2 || itemstack12.getCount() > this.dragSlots.size()) && this.canDragIntoSlot(slot7)) { this.dragSlots.add(slot7); } } else if (this.dragEvent == 2) { if (!this.dragSlots.isEmpty()) { ItemStack itemstack9 = playerinventory.getItemStack().copy(); int k1 = playerinventory.getItemStack().getCount(); for(Slot slot8 : this.dragSlots) { ItemStack itemstack13 = playerinventory.getItemStack(); if (slot8 != null && canAddItemToSlot(slot8, itemstack13, true) && slot8.isItemValid(itemstack13) && (this.dragMode == 2 || itemstack13.getCount() >= this.dragSlots.size()) && this.canDragIntoSlot(slot8)) { ItemStack itemstack14 = itemstack9.copy(); int j3 = slot8.getHasStack() ? slot8.getStack().getCount() : 0; computeStackSize(this.dragSlots, this.dragMode, itemstack14, j3); int k3 = Math.min(itemstack14.getMaxStackSize(), slot8.getItemStackLimit(itemstack14)); if (itemstack14.getCount() > k3) { itemstack14.setCount(k3); } k1 -= itemstack14.getCount() - j3; slot8.putStack(itemstack14); } } itemstack9.setCount(k1); playerinventory.setItemStack(itemstack9); } this.resetDrag(); } else { this.resetDrag(); } } else if (this.dragEvent != 0) { this.resetDrag(); } else if ((clickTypeIn == ClickType.PICKUP || clickTypeIn == ClickType.QUICK_MOVE) && (dragType == 0 || dragType == 1)) { if (slotId == -999) { if (!playerinventory.getItemStack().isEmpty()) { if (dragType == 0) { player.dropItem(playerinventory.getItemStack(), true); playerinventory.setItemStack(ItemStack.EMPTY); } if (dragType == 1) { player.dropItem(playerinventory.getItemStack().split(1), true); } } } else if (clickTypeIn == ClickType.QUICK_MOVE) { if (slotId < 0) { return ItemStack.EMPTY; } Slot slot5 = this.inventorySlots.get(slotId); if (slot5 == null || !slot5.canTakeStack(player)) { return ItemStack.EMPTY; } for(ItemStack itemstack7 = this.transferStackInSlot(player, slotId); !itemstack7.isEmpty() && ItemStack.areItemsEqual(slot5.getStack(), itemstack7); itemstack7 = this.transferStackInSlot(player, slotId)) { LOGGER.info("for loop"); LOGGER.info( !itemstack7.isEmpty() && ItemStack.areItemsEqual(slot5.getStack(), itemstack7)); itemstack = itemstack7.copy(); } } else { if (slotId < 0) { return ItemStack.EMPTY; } Slot slot6 = this.inventorySlots.get(slotId); if (slot6 != null) { ItemStack itemstack8 = slot6.getStack(); ItemStack itemstack11 = playerinventory.getItemStack(); if (!itemstack8.isEmpty()) { itemstack = itemstack8.copy(); } if (itemstack8.isEmpty()) { if (!itemstack11.isEmpty() && slot6.isItemValid(itemstack11)) { int j2 = dragType == 0 ? itemstack11.getCount() : 1; if (j2 > slot6.getItemStackLimit(itemstack11)) { j2 = slot6.getItemStackLimit(itemstack11); } slot6.putStack(itemstack11.split(j2)); } } else if (slot6.canTakeStack(player)) { if (itemstack11.isEmpty()) { if (itemstack8.isEmpty()) { slot6.putStack(ItemStack.EMPTY); playerinventory.setItemStack(ItemStack.EMPTY); } else { int k2 = dragType == 0 ? itemstack8.getCount() : (itemstack8.getCount() + 1) / 2; playerinventory.setItemStack(slot6.decrStackSize(k2)); if (itemstack8.isEmpty()) { slot6.putStack(ItemStack.EMPTY); } slot6.onTake(player, playerinventory.getItemStack()); } } else if (slot6.isItemValid(itemstack11)) { if (areItemsAndTagsEqual(itemstack8, itemstack11)) { int l2 = dragType == 0 ? itemstack11.getCount() : 1; if (l2 > slot6.getItemStackLimit(itemstack11) - itemstack8.getCount()) { l2 = slot6.getItemStackLimit(itemstack11) - itemstack8.getCount(); } if (l2 > itemstack11.getMaxStackSize() - itemstack8.getCount()) { l2 = itemstack11.getMaxStackSize() - itemstack8.getCount(); } itemstack11.shrink(l2); itemstack8.grow(l2); } else if (itemstack11.getCount() <= slot6.getItemStackLimit(itemstack11)) { slot6.putStack(itemstack11); playerinventory.setItemStack(itemstack8); } } else if (itemstack11.getMaxStackSize() > 1 && areItemsAndTagsEqual(itemstack8, itemstack11) && !itemstack8.isEmpty()) { int i3 = itemstack8.getCount(); if (i3 + itemstack11.getCount() <= itemstack11.getMaxStackSize()) { itemstack11.grow(i3); itemstack8 = slot6.decrStackSize(i3); if (itemstack8.isEmpty()) { slot6.putStack(ItemStack.EMPTY); } slot6.onTake(player, playerinventory.getItemStack()); } } } slot6.onSlotChanged(); } } } else if (clickTypeIn == ClickType.SWAP && dragType >= 0 && dragType < 9) { Slot slot4 = this.inventorySlots.get(slotId); ItemStack itemstack6 = playerinventory.getStackInSlot(dragType); ItemStack itemstack10 = slot4.getStack(); if (!itemstack6.isEmpty() || !itemstack10.isEmpty()) { if (itemstack6.isEmpty()) { if (slot4.canTakeStack(player)) { playerinventory.setInventorySlotContents(dragType, itemstack10); //slot4.onSwapCraft(itemstack10.getCount()); slot4.putStack(ItemStack.EMPTY); slot4.onTake(player, itemstack10); } } else if (itemstack10.isEmpty()) { if (slot4.isItemValid(itemstack6)) { int l1 = slot4.getItemStackLimit(itemstack6); if (itemstack6.getCount() > l1) { slot4.putStack(itemstack6.split(l1)); } else { slot4.putStack(itemstack6); playerinventory.setInventorySlotContents(dragType, ItemStack.EMPTY); } } } else if (slot4.canTakeStack(player) && slot4.isItemValid(itemstack6)) { int i2 = slot4.getItemStackLimit(itemstack6); if (itemstack6.getCount() > i2) { slot4.putStack(itemstack6.split(i2)); slot4.onTake(player, itemstack10); if (!playerinventory.addItemStackToInventory(itemstack10)) { player.dropItem(itemstack10, true); } } else { slot4.putStack(itemstack6); playerinventory.setInventorySlotContents(dragType, itemstack10); slot4.onTake(player, itemstack10); } } } } else if (clickTypeIn == ClickType.CLONE && player.abilities.isCreativeMode && playerinventory.getItemStack().isEmpty() && slotId >= 0) { Slot slot3 = this.inventorySlots.get(slotId); if (slot3 != null && slot3.getHasStack()) { ItemStack itemstack5 = slot3.getStack().copy(); itemstack5.setCount(itemstack5.getMaxStackSize()); playerinventory.setItemStack(itemstack5); } } else if (clickTypeIn == ClickType.THROW && playerinventory.getItemStack().isEmpty() && slotId >= 0) { Slot slot2 = this.inventorySlots.get(slotId); if (slot2 != null && slot2.getHasStack() && slot2.canTakeStack(player)) { ItemStack itemstack4 = slot2.decrStackSize(dragType == 0 ? 1 : slot2.getStack().getCount()); slot2.onTake(player, itemstack4); player.dropItem(itemstack4, true); } } else if (clickTypeIn == ClickType.PICKUP_ALL && slotId >= 0) { Slot slot = this.inventorySlots.get(slotId); ItemStack itemstack1 = playerinventory.getItemStack(); if (!itemstack1.isEmpty() && (slot == null || !slot.getHasStack() || !slot.canTakeStack(player))) { int i = dragType == 0 ? 0 : this.inventorySlots.size() - 1; int j = dragType == 0 ? 1 : -1; for(int k = 0; k < 2; ++k) { for(int l = i; l >= 0 && l < this.inventorySlots.size() && itemstack1.getCount() < itemstack1.getMaxStackSize(); l += j) { Slot slot1 = this.inventorySlots.get(l); if (slot1.getHasStack() && canAddItemToSlot(slot1, itemstack1, true) && slot1.canTakeStack(player) && this.canMergeSlot(itemstack1, slot1)) { ItemStack itemstack2 = slot1.getStack(); if (k != 0 || itemstack2.getCount() != itemstack2.getMaxStackSize()) { int i1 = Math.min(itemstack1.getMaxStackSize() - itemstack1.getCount(), itemstack2.getCount()); ItemStack itemstack3 = slot1.decrStackSize(i1); itemstack1.grow(i1); if (itemstack3.isEmpty()) { slot1.putStack(ItemStack.EMPTY); } slot1.onTake(player, itemstack3); } } } } } this.detectAndSendChanges(); } return itemstack; } } [SOLUTION] I needed to implement transferStackInSlot correctly. I used ChestContainer#transferStackInSlot. // copied from ChestContainer @Nonnull @Override public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { ItemStack itemstack = ItemStack.EMPTY; Slot slot = this.inventorySlots.get(index); if (slot != null && slot.getHasStack()) { ItemStack itemstack1 = slot.getStack(); itemstack = itemstack1.copy(); if (index == 0) { if (!this.mergeItemStack(itemstack1, 1, this.inventorySlots.size(), true)) { return ItemStack.EMPTY; } } else if (!this.mergeItemStack(itemstack1, 0, 1, false)) { return ItemStack.EMPTY; } if (itemstack1.isEmpty()) { slot.putStack(ItemStack.EMPTY); } else { slot.onSlotChanged(); } } return itemstack; }
  23. I'm thinking about doing something I would assume requires storing data in the world somehow, but I'm really not sure. I want to create a block that can only be crafted a certain amount of times per player. I also want to create blocks that are effected by how many are in the world. both would seem to require storing data somewhere. Where should I store this data?
  24. I think I got it... again. package com.Garrett.backtobasics.blocks; import net.minecraft.block.Block; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.INBTSerializable; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemStackHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import static net.minecraft.util.Direction.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import static com.Garrett.backtobasics.blocks.ModBlocks.AUTO_MINER_TILE_ENTITY; public class AutoMinerTileEntity extends TileEntity implements ITickableTileEntity, INamedContainerProvider { private static final Logger LOGGER = LogManager.getLogger(); private LazyOptional<IItemHandler> handler = LazyOptional.of(this::createHandler); private int tickCounter = 0; private ArrayList<String> veinBlockList = new ArrayList<>(); public AutoMinerTileEntity() { super(AUTO_MINER_TILE_ENTITY); veinBlockList.add("backtobasics:diamond_vein"); veinBlockList.add("backtobasics:gold_vein"); veinBlockList.add("backtobasics:iron_vein"); veinBlockList.add("backtobasics:redstone_vein"); } // 20 ticks per second @Override public void tick() { tickCounter++; if (tickCounter >= 60) { tickCounter = 0; mineBlock(); } } // the lazy handler postpones execution of code until it is needed for the first time and cashes it // so it won't be recreated every time it is used. private ItemStackHandler createHandler () { return new ItemStackHandler(1); } // reads inventory from world file on load @Override public void read(CompoundNBT tag) { CompoundNBT invTag = tag.getCompound("inv"); handler.ifPresent(h -> ((INBTSerializable<CompoundNBT>) h).deserializeNBT(invTag)); createHandler().deserializeNBT(invTag); super.read(tag); } // writes inventory to world file whenever world is saved @Override public CompoundNBT write(CompoundNBT tag) { handler.ifPresent(h -> { CompoundNBT compound = ((INBTSerializable<CompoundNBT>) h).serializeNBT(); tag.put("inv", compound); }); return super.write(tag); } // Capabilities add funcionality to blocks and items. @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { return handler.cast(); } return super.getCapability(cap, side); } @Override public ITextComponent getDisplayName() { return new StringTextComponent(getType().getRegistryName().getPath()); } @Nullable @Override public Container createMenu(int i, PlayerInventory playerInventory, PlayerEntity playerEntity) { return new AutoMinerContainer(i, world, pos, playerInventory, playerEntity); } private void mineBlock() { if (world != null) { if (world.getServer() != null) { Block block = getBlockToMine(); BlockPos blockPos = getBlockToMinePosition(); handler.ifPresent(h -> { ItemStack stack = h.getStackInSlot(0); int stackSize = stack.getCount(); int stackLimit = h.getSlotLimit(0); ServerWorld serverWorld = world.getServer().getWorld(world.dimension.getType()); List<ItemStack> drops = Block.getDrops(block.getDefaultState(), serverWorld, blockPos, super.getTileEntity()); for (ItemStack item: drops) { if ((stackSize < stackLimit && item.getItem() == stack.getItem()) || stack.isEmpty()) { h.insertItem(0, item, false); if (!veinBlockList.contains(block.getRegistryName().toString())) { world.destroyBlock(blockPos, false); } } } }); } } } // gets block connected to the "drill face" private Block getBlockToMine() { if (getBlockState().getValues().containsValue(UP)) { return world.getBlockState(getPos().up()).getBlock(); } else if (getBlockState().getValues().containsValue(DOWN)) { return world.getBlockState(getPos().down()).getBlock(); } else if (getBlockState().getValues().containsValue(NORTH)) { return world.getBlockState(getPos().north()).getBlock(); } else if (getBlockState().getValues().containsValue(SOUTH)) { return world.getBlockState(getPos().south()).getBlock(); } else if (getBlockState().getValues().containsValue(EAST)) { return world.getBlockState(getPos().east()).getBlock(); } else { return world.getBlockState(getPos().west()).getBlock(); } } // gets block connected to the "drill face" private BlockPos getBlockToMinePosition() { if (getBlockState().getValues().containsValue(UP)) { return getPos().up(); } else if (getBlockState().getValues().containsValue(DOWN)) { return getPos().down(); } else if (getBlockState().getValues().containsValue(NORTH)) { return getPos().north(); } else if (getBlockState().getValues().containsValue(SOUTH)) { return getPos().south(); } else if (getBlockState().getValues().containsValue(EAST)) { return getPos().east(); } else { return getPos().west(); } } }
×
×
  • Create New...

Important Information

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