uncleofbob Posted January 11, 2018 Posted January 11, 2018 (edited) ------------------------------------------------------------------------------------------------------------------- SOLVED: Long story short, I messed up accessing the Tile Entity Pos for each instance. The solution was to scrap the setPos() method (which I first of all should have renamed), and use this.getPos() whenever I needed the Tile Entity pos. I already knew about getPos() but it seems I implemented it wrong, cause it always returned BlockPos(0,0,0). In Block I removed everything inside onBlockPlacedBy In Tile Entity I removed the setPos() method and the posB field. And as example I now use: mapQuarry(5, this.getPos()) --------------------------------------------------------------------------------------------------------------------- Hi! I'm very new to modding in Minecraft. I got stuck when changing from calling TE-method from the Block's "onBlockActivated", to using update() instead. The goal is to "world.destroyBlock" at BlockPos specified in AREA<BlockPos> every 20 ticks. This worked if I just called a TE-method from onBlockActivated and looped through AREA (although this happens instantly). I'm obviously missing something, as update() runs pretty randomly when i restart the game. I'll be happy if i just get the world.destroyBlock to start removing blocks in update(). Block class: package com.jolge.derpworld.block; import java.util.Random; import com.jolge.derpworld.DerpWorld; import com.jolge.derpworld.init.BlockInit; import com.jolge.derpworld.init.ItemInit; import com.jolge.derpworld.tileentity.JdwOSDigger; import com.jolge.derpworld.util.IHasModel; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.stats.StatList; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class JdwBlockBitumen extends Block implements IHasModel{ public JdwBlockBitumen(String name, Material material) { super(material); setUnlocalizedName(name); setRegistryName(name); setCreativeTab(CreativeTabs.MISC); setHarvestLevel("pick_axe", 1); BlockInit.BLOCKS.add(this); ItemInit.ITEMS.add(new ItemBlock(this).setRegistryName(this.getRegistryName())); } @Override public boolean hasTileEntity(IBlockState state) { return true; } @Override public TileEntity createTileEntity(final World worldIn, final IBlockState state) { return new JdwOSDigger(); } @Override public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state) { } @Override public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) { if (!worldIn.isRemote ) { final JdwOSDigger tileEntity = (JdwOSDigger) worldIn.getTileEntity(pos); if(tileEntity != null) { tileEntity.toggleActive(); } } return true; } @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { TileEntity tileentity = worldIn.getTileEntity(pos); if (tileentity instanceof JdwOSDigger) { ((JdwOSDigger)tileentity).setPos(pos); } } @Override public void registerModels() { DerpWorld.proxy.registerItemRenderer(Item.getItemFromBlock(this), 0, "inventory"); } } Tile Entity class: package com.jolge.derpworld.tileentity; import java.util.ArrayList; import java.util.List; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.BlockDirt; import net.minecraft.block.BlockGrass; import net.minecraft.block.state.IBlockState; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ITickable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import scala.actors.threadpool.Arrays; public class JdwOSDigger extends TileEntity implements ITickable{ public boolean isActivated; public BlockPos posB; public List<BlockPos> AREA = new ArrayList<BlockPos>(); public int radi = 0; public int index = 0; public int tickCounter = 0; public JdwOSDigger() { super(); } public void setPos(BlockPos pos) { this.posB = pos; } @Override public void update() { if (!world.isRemote){ if(isActivated) { tickCounter++; if (tickCounter==20) { world.destroyBlock(AREA.get(index), false); System.out.println("Destroyed block at: " + AREA.get(index) ); index++; tickCounter = 0; } } } } public void toggleActive() { if (this.isActivated) { this.isActivated = false; } else { this.isActivated = true; mapQuarry(5, this.posB); } } public void mapQuarry (int radi, BlockPos pos) { List<BlockPos> l = new ArrayList<BlockPos>(); int[] squares = new int[radi]; BlockPos qC = null; //Quadrant Center int bx, by, bz = 0; for(int k = 0; k<4; k++) { switch(k){ case 0: qC = pos.add(radi+1, 0, radi+1); //+X+Z = NorthEast = 1 break; case 1: qC = pos.add(-(radi+1), 0, radi+1); //-X+Z = NorthWest = 2 break; case 2: qC = pos.add(radi+1, 0, -(radi+1)); //+X-Z = SouthEast = 3 break; case 3: qC = pos.add(-(radi+1), 0, -(radi+1)); //-X-Z = SouthWest = 4 break; } for(int e = 0; e<radi/2; e++) { for(int i = -radi+e; i <= radi-e; i++) { for (int j = -radi+e; j<=radi-e; j++) { bx = qC.getX() + i; bz = qC.getZ() + j; by = qC.getY() - 1 - e; BlockPos pos2 = new BlockPos( bx , by, bz ); l.add(pos2); } } } } AREA.addAll(l); } } Edited January 17, 2018 by uncleofbob Quote
Draco18s Posted January 11, 2018 Posted January 11, 2018 You don't implement writeToNBT and readFromNBT. Quote Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 I have done some tests with the NBT methods. update() still doesn't seem to run. Should NBT be the case when I create a new world and update() doesn't work? public void readFromNBT(NBTTagCompound compound) { super.readFromNBT(compound); //his.note = compound.getByte("note"); this.isActivated = compound.getBoolean("Status"); this.tickCounter = compound.getInteger("count"); this.index = compound.getInteger("indexz"); } public NBTTagCompound writeToNBT(NBTTagCompound compound) { super.writeToNBT(compound); //compound.setByte(); compound.setInteger("indexz", this.index); compound.setInteger("count", this.tickCounter); compound.setBoolean("Status", this.isActivated); return compound; } Quote
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 Thanks for the quick replies! I think the tile entity gets registered. I can call methods from onBlockActivated which works fine. Is there something wrong with the tile entity constructor maybe? My RegistryHandler.class : Should I register right after Blocks instead? package com.jolge.derpworld.util; import com.jolge.derpworld.init.BlockInit; import com.jolge.derpworld.init.ItemInit; import com.jolge.derpworld.tileentity.JdwOSDigger; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.registries.IForgeRegistry; @EventBusSubscriber public class RegistryHandler { @SubscribeEvent public static void onBlockRegister(RegistryEvent.Register<Block> event) { event.getRegistry().registerAll(BlockInit.BLOCKS.toArray(new Block[0])); } @SubscribeEvent public static void onItemRegister(RegistryEvent.Register<Item> event) { event.getRegistry().registerAll(ItemInit.ITEMS.toArray(new Item[0])); registerTileEntities(); } @SubscribeEvent public static void onModelRegister(ModelRegistryEvent event) { for(Item item : ItemInit.ITEMS) { if(item instanceof IHasModel) { ((IHasModel)item).registerModels(); } } for(Block block : BlockInit.BLOCKS) { if(block instanceof IHasModel) { ((IHasModel)block).registerModels(); } } } public static void registerTileEntities() { GameRegistry.registerTileEntity(JdwOSDigger.class, Reference.MODID + "oil_sand_digger"); System.out.println("Registered: oil_sand_digger"); } Quote
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 I sort of copied the way its done in TestMod3: https://github.com/Choonster-Minecraft-Mods/TestMod3/blob/1.12.2/src/main/java/choonster/testmod3/init/ModBlocks.java Changed to preInit now, but still no update() running. Quote
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 (edited) Found the problem! Forgot to Override Block#updateTick in the block class THx for all responses! EDIT: MY BAD NO FIX! Edited January 12, 2018 by uncleofbob Quote
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 My bad! Seems when i refresh or do some changes to the block class it works the first time I start a new world. hmm.. Quote
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 Now I'm doing it like this: @EventHandler public void preinit(FMLPreInitializationEvent event) { GameRegistry.registerTileEntity(JdwOSDigger.class, Reference.MODID + "oilsanddigger"); } Quote
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 Could it be related to my tile entity class? Maybe the instantiation of the tile entity ? Quote
Choonster Posted January 12, 2018 Posted January 12, 2018 (edited) 1 hour ago, uncleofbob said: I sort of copied the way its done in TestMod3: https://github.com/Choonster-Minecraft-Mods/TestMod3/blob/1.12.2/src/main/java/choonster/testmod3/init/ModBlocks.java Changed to preInit now, but still no update() running. That's actually a mistake, I intended to do that in RegistryEvent.Register<Block> rather RegistryEvent.Register<Item>. LexManos recommended this here. The two events are fired at roughly the same time, but it makes more sense to register TileEntities with Blocks rather than with Items. Edit: Fixed. Edited January 12, 2018 by Choonster Quote Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
uncleofbob Posted January 12, 2018 Author Posted January 12, 2018 Now I register the Block, ItemBlock and TileEntity directly in RegistryHandler. Update() still won't run. Guess I'll have to dig deeper ! Quote
KittenKoder Posted January 12, 2018 Posted January 12, 2018 Digging through the Forge and Minecraft sourcecode, registering a tile entity does not automatically register tickers when registering through the registerTileEntity. I find no other references to the list. public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String key) { TileEntity.register(key, tileEntityClass); } public static void register(String id, Class <? extends TileEntity > clazz) { REGISTRY.putObject(new ResourceLocation(id), clazz); } public void putObject(K key, V value) { Validate.notNull(key); Validate.notNull(value); this.values = null; if (this.registryObjects.containsKey(key)) { LOGGER.debug("Adding duplicate key '{}' to registry", key); } this.registryObjects.put(key, value); } So far I cannot find when they are registered for the vanilla items. I'm digging into the source code to see if I can find where they are registered as tickables because it isn't happening there. Quote
KittenKoder Posted January 13, 2018 Posted January 13, 2018 From what I see, the problem is that the vanilla engine is not recognizing the modded tickable blocks until they are effected by certain events. The ITickable interface isn't checked until chunk loading, and then added to a special list. But those changes do not seem to take effect immediately after chunk loading for the version I am compiling against either. The only work around I can see is by using scheduleBlockUpdate. If the delay is high enough though, I see no issues that could hurt the mod in any way. 1 Quote
uncleofbob Posted January 13, 2018 Author Posted January 13, 2018 Thx ! So its schedualBlockUpdate in onBlockAdded, and override the updateTick method? Currently Im testing with every 20 ticks, but it may even be slower. Thx again! Quote
jabelar Posted January 13, 2018 Posted January 13, 2018 (edited) World#updateEntities() runs every tick and iterates through the entire tickableTileEntitiesList and calls their update() method. So the update() method should be called EVERY tick for any ITickable tile entity (provided it is in the tickableTileEntitiesList). To get on the tickableTileEntitiesList, that happens in the World#addTileEntity() method so long as it is in the loadedTileEntityList and also instanceof ITickable. I suppose it is possilble that there is some cases where the loadedTileEntity list isn't updated by the time the addTileEntity() method is called. The updateEntities() method goes through these general steps in this exact order: 1. Iterates through tileEntitiesToBeRemovedList and runs onChunkUnload() method, removes them from the tickableTileEntitiesList and then removes them from the loadedTileEntitiesList. 2. Iterates through tickableTileEntitiesList and if the tile entity is valid and hasWorld() are true, checks that the block in that position is loaded and inside the world border. If the tile entity is invalid it is removed from the loadeTileEntitiesList and also from the chunk's tile entity association to that BlockPos. Interestingly it is not removed from the tickableTileEntitiesList at this time. 3. Iterates through the addedTileEntitiesList. I find it interesting that it does the adding at the end, but probably an attempt to make sure all these lists are in sync. But it means that there is one tick between adding the tile entity and the first time it is ticked. Basically the tile entity is checked to be valid and then added to the loadedTileEntitiesList. Then it separately checks if the block is loaded and associates it to the chunk's block position including calling a notifyBlockUpdate(). Basically, there are a lot of things that need to be synced and in common Minecraft fashion the coding isn't super organized leaving suspicion related to logical holes. In fact there are comments already in this code such as: //Forge: Bugfix: If we set the tile entity it immediately sets it in the chunk, so we could be desynced That's about all the effort I'm interested in putting into investigating at this time, but hopefully gives you some ideas on how to debug. I would use the debugger and set breakpoints throughout the World#UpdateEntities() method and watch the order in which your tile entity is added to each list, and when it gets the update() calls. However, my main point is that the intention seems to be that within one tick from a block with tile entity being added, it should be on the loadedTileEntitiesList and if it is also ITickable should run update() every tick from then on. If yours is not, then it is a bug somewhere. Edited January 13, 2018 by jabelar 1 Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
KittenKoder Posted January 15, 2018 Posted January 15, 2018 That's some nice info jabelar, but it's not working like that. The list loaded during chunk loading does not appear to be realized until after certain events occur, one such event is GUI interaction. I am hoping someone can track down why this is the case, but for now scheduling infrequent tick updates is the only thing that works 100% of the time in all cases. On 1/13/2018 at 7:50 AM, uncleofbob said: Thx ! So its schedualBlockUpdate in onBlockAdded, and override the updateTick method? Currently Im testing with every 20 ticks, but it may even be slower. Thx again! Basically when the block is placed or the entity is loaded. onLoad for the entity, onBlockPlacedBy for the block class just because all you need is the block instance since you do have to extract the entity from the world. Which is why I wish the update calling was more reliable. This does explain a lot about Mekanisms and why that mod breaks so much, especially during multiplayer. Thankfully most of what I am doing doesn't require constant tick checks. 1 Quote
uncleofbob Posted January 15, 2018 Author Posted January 15, 2018 (edited) [IGNORE THIS POST!!]] Finally! It seems i've found the issue in my code. @diesieben07 was right stating that the tile entity didn't register properly Se comments below // I think the registered tile entity excluded ITickable when writing <?extends TileEntity> public static void registerTileEntity(final Class<?extends TileEntity> tileEntityClass, final String name) { GameRegistry.registerTileEntity(tileEntityClass, name); } // when I removed it, it seems to run as I want. I assume it just takes whatever the class extends and implements. public static void registerTileEntity(final Class tileEntityClass, final String name) { GameRegistry.registerTileEntity(tileEntityClass, name); } Edited January 15, 2018 by uncleofbob Did not solve the problem! 1 Quote
KittenKoder Posted January 15, 2018 Posted January 15, 2018 51 minutes ago, uncleofbob said: Finally! It seems i've found the issue in my code. @diesieben07 was right stating that the tile entity didn't register properly Se comments below // I think the registered tile entity excluded ITickable when writing <?extends TileEntity> public static void registerTileEntity(final Class<?extends TileEntity> tileEntityClass, final String name) { GameRegistry.registerTileEntity(tileEntityClass, name); } // when I removed it, it seems to run as I want. I assume it just takes whatever the class extends and implements. public static void registerTileEntity(final Class tileEntityClass, final String name) { GameRegistry.registerTileEntity(tileEntityClass, name); } Great, that means more manual typing of things for me. I was using a registry enum for simpler registration so if I ever need the update method I'll have to actually register them out of the loop. At least you did find a solution, kudos on sticking with it. Quote
uncleofbob Posted January 15, 2018 Author Posted January 15, 2018 And again.. There must be something wrong with my Modding environment. I restarted the game 10 times to verify that update() worked.. Only to find out it stopped working after a while... 1 Quote
uncleofbob Posted January 15, 2018 Author Posted January 15, 2018 (edited) I've now checked the lists: "tickableTileEntities" and "loadedTileEntityList" while right clicking on block. In combination I ran the Chunk.getTileEntityMap() to see if its found in the chunk. The number (id?) after the tile entity also changes when I destroy the block and place a new, which I assume states that it detects a new instance of my JdwOSDigger tile entity. [12:52:18] [..onBlockActivated:86]: from Chunk: {BlockPos{x=-125, y=66, z=224}=com.jolge.derpworld.tileentity.JdwOSDigger@af23ab1} [12:52:18] [.....onBlockActivated:90]: loadedTileEntityList[21]: com.jolge.derpworld.tileentity.JdwOSDigger@af23ab1 [12:52:18] [....onBlockActivated:97]: tickableTileEntities[21]: com.jolge.derpworld.tileentity.JdwOSDigger@af23ab1 [12:52:33] [....onBlockActivated:86]: from Chunk: {BlockPos{x=-125, y=66, z=224}=com.jolge.derpworld.tileentity.JdwOSDigger@2979b61f} [12:52:33] [....onBlockActivated:90]: loadedTileEntityList[21]: com.jolge.derpworld.tileentity.JdwOSDigger@2979b61f [12:52:33] [....onBlockActivated:97]: tickableTileEntities[21]: com.jolge.derpworld.tileentity.JdwOSDigger@2979b61f I'll import my mod to a new eclipse environment later, to see if it helps. Edited January 15, 2018 by uncleofbob Quote
uncleofbob Posted January 15, 2018 Author Posted January 15, 2018 (edited) I've added "-clean" at the first line in eclipse.ini. This wipes out some eclipse runtime cache which seem to cause the problem. I'll put the thread to [SOLVED] when I'm 100% sure. Edited January 15, 2018 by uncleofbob Nothing relevant Quote
uncleofbob Posted January 15, 2018 Author Posted January 15, 2018 (edited) -------------------------------------------- Not a solution! --------------------------------------------- So I've done like @KittenKodersuggested: Is this cheat ? @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { TileEntity tileentity = worldIn.getTileEntity(pos); if (tileentity instanceof JdwOSDigger) { ((JdwOSDigger)tileentity).setPos(pos); worldIn.scheduleBlockUpdate(pos, this, 20, 1); // schedule first update } } @Override public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand) { if(!worldIn.isRemote) { TileEntity tileentity = worldIn.getTileEntity(pos); if (tileentity instanceof JdwOSDigger){ ((JdwOSDigger)tileentity).jdwUpdate(); //call jdwupDate in tile entity worldIn.scheduleBlockUpdate(pos, this, 20, 1); //schedule next update. } } } Edited January 17, 2018 by uncleofbob 1 Quote
jabelar Posted January 16, 2018 Posted January 16, 2018 Well it is a "cheat" in the sense that ITickable should not need any such silliness. Think about it -- a furnace happily cooks something as an ITickable and any animated tile entity is happily updated every tick. You should really find the root cause of the problem. But if it works I guess use it. Something is still wrong with your implementation in my opinion though and it might bite you later. Quote Check out my tutorials here: http://jabelarminecraft.blogspot.com/
KittenKoder Posted January 16, 2018 Posted January 16, 2018 5 hours ago, jabelar said: Well it is a "cheat" in the sense that ITickable should not need any such silliness. Think about it -- a furnace happily cooks something as an ITickable and any animated tile entity is happily updated every tick. You should really find the root cause of the problem. But if it works I guess use it. Something is still wrong with your implementation in my opinion though and it might bite you later. A furnace is also recognized by vanilla code. The point at which ITickable is added to a special list is on chunk loading, it looks like it should all work, but the fact is that it doesn't work. Quote
KittenKoder Posted January 16, 2018 Posted January 16, 2018 9 hours ago, uncleofbob said: So I've done like @KittenKodersuggested: Is this cheat ? @Override public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) { TileEntity tileentity = worldIn.getTileEntity(pos); if (tileentity instanceof JdwOSDigger) { ((JdwOSDigger)tileentity).setPos(pos); worldIn.scheduleBlockUpdate(pos, this, 20, 1); // schedule first update } } @Override public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand) { if(!worldIn.isRemote) { TileEntity tileentity = worldIn.getTileEntity(pos); if (tileentity instanceof JdwOSDigger){ ((JdwOSDigger)tileentity).jdwUpdate(); //call jdwupDate in tile entity worldIn.scheduleBlockUpdate(pos, this, 20, 1); //schedule next update. } } } Don't forget the schedule update for the entity's onLoad. That is what initiates it on chunk loading. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.