Jump to content

SnowyEgret

Members
  • Posts

    112
  • Joined

  • Last visited

Posts posted by SnowyEgret

  1. Is there something else I have missed? Now the block does not drop when I break it. (Same behavior when I don't override harvestBlock)

     

     

     

    @Override
    public boolean removedByPlayer(World world, BlockPos pos, EntityPlayer player, boolean willHarvest) {
    	System.out.println("willHarvest=" + willHarvest);
    	new Throwable().printStackTrace();
    	if (willHarvest) {
    		// Delay deletion of the block until after getDrops
    		return true;
    	}
    	return super.removedByPlayer(world, pos, player, willHarvest);
    }
    
    @Override
    public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, TileEntity te) {
    	System.out.println("te=" + te);
    	super.harvestBlock(world, player, pos, state, te);
    	world.setBlockToAir(pos);
    }
    

     

     

     

    Here my console. Is it normal that removeByPlayer is called twice with different values for willHarvest?

     

     

     

    [13:39:11] [server thread/INFO] [sTDOUT]: [org.snowyegret.mojo.item.spell.other.SpellSave:setText:87]: path=/tmp/Foo8418776298188150160.save
    [13:39:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:removedByPlayer:135]: willHarvest=false
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: java.lang.Throwable
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at org.snowyegret.mojo.block.BlockSaved.removedByPlayer(BlockSaved.java:136)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.multiplayer.PlayerControllerMP.onPlayerDestroyBlock(PlayerControllerMP.java:165)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.multiplayer.PlayerControllerMP.func_180511_b(PlayerControllerMP.java:252)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.Minecraft.clickMouse(Minecraft.java:1520)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.Minecraft.runTick(Minecraft.java:2127)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1088)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.Minecraft.run(Minecraft.java:376)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.main.Main.main(Main.java:117)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.lang.reflect.Method.invoke(Method.java:497)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraftforge.gradle.GradleStartCommon.launch(Unknown Source)
    [13:39:13] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at GradleStart.main(Unknown Source)
    [13:39:13] [server thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:removedByPlayer:135]: willHarvest=true
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: java.lang.Throwable
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at org.snowyegret.mojo.block.BlockSaved.removedByPlayer(BlockSaved.java:136)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.management.ItemInWorldManager.removeBlock(ItemInWorldManager.java:296)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.management.ItemInWorldManager.tryHarvestBlock(ItemInWorldManager.java:349)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.management.ItemInWorldManager.onBlockClicked(ItemInWorldManager.java:233)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.NetHandlerPlayServer.processPlayerDigging(NetHandlerPlayServer.java:552)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.play.client.C07PacketPlayerDigging.processPacket(C07PacketPlayerDigging.java:53)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.play.client.C07PacketPlayerDigging.processPacket(C07PacketPlayerDigging.java:76)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:24)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraftforge.fml.common.FMLCommonHandler.callFuture(FMLCommonHandler.java:714)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:727)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:669)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:171)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:540)
    [13:39:13] [server thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.lang.Thread.run(Thread.java:745)
    [13:39:13] [server thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:harvestBlock:146]: te=org.snowyegret.mojo.block.BlockSavedTileEntity@3209ab1
    [

     

     

     

     

  2. Here is my getDops modeled on BlockFlowerPot:

     

     

    @Override
    public List<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) {
    	List<ItemStack> itemStacks = super.getDrops(world, pos, state, fortune);
    	TileEntity te = world.getTileEntity(pos);
    	if (te == null) {
    		System.out.println("Could not write path to tag. te=" + te);
    		return itemStacks;
    	}
    
    	if (te instanceof BlockSavedTileEntity) {
    		String path = ((BlockSavedTileEntity) te).getPath();
    		ItemStack stack = new ItemStack(this);
    		NBTTagCompound tag = stack.getTagCompound();
    		((BlockSavedTileEntity) te).writeToNBT(tag);
    		System.out.println("tag=" + tag);
    		itemStacks.add(stack);
    	} else {
    		System.out.println("Could not write path to tag. TileEntity not a BlockSavedTileEntity. te=" + te);
    	}
    
    	return itemStacks;
    }
    

     

     

     

    but te is coming up null (maybe because it was broken?). Do I still need to override harvestBlock and pass string path somehow? Or is there a problem with my TileEntity?

     

     

     

    package org.snowyegret.mojo.block;
    
    import net.minecraft.block.Block;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.network.NetworkManager;
    import net.minecraft.network.Packet;
    import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
    import net.minecraft.tileentity.TileEntity;
    
    public class BlockSavedTileEntity extends TileEntity {
    
    private String path;
    
    public void setPath(String path) {
    	this.path = path;
    }
    
    public String getPath() {
    	return path;
    }
    
    @Override
    public void writeToNBT(NBTTagCompound tag) {
    	if (path == null) {
    		System.out.println("Could not write path to tag. path=" + path);
    	} else {
    		tag.setString(BlockSaved.KEY_PATH, path);
    		super.writeToNBT(tag);
    	}
    }
    
    @Override
    public void readFromNBT(NBTTagCompound tag) {
    	path = tag.getString(BlockSaved.KEY_PATH);
    	super.readFromNBT(tag);
    }
    
    @Override
    public Packet getDescriptionPacket() {
    	NBTTagCompound tag = new NBTTagCompound();
    	writeToNBT(tag);
    	super.writeToNBT(tag);
    	return new S35PacketUpdateTileEntity(pos, this.getBlockMetadata(), tag);
    }
    
    @Override
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
    	readFromNBT(pkt.getNbtCompound());
    	super.readFromNBT(pkt.getNbtCompound());
    }
    
    }
    

     

     

  3. I have a field of type String on a TileEntity provided by a block. When I break and then pick up the block, I want the string on the ItemStack in the player's inventory. My intention is to use the string when I place the block again with method

     

    	public void onBlockPlacedBy(World w, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) {
    

     

    I have overridden

    	public void harvestBlock(World worldIn, EntityPlayer playerIn, BlockPos pos, IBlockState state, TileEntity te) {
    

     

    which gives me the string, but I don't know how to put it on the ItemStack's NBT when the player picks the block up. Any help appreciated.

  4. Ok, I had understood the registering it and adding it to the list were two differents steps. I've got the reflection going and my resource pack is on the list.

     

    I have build myself a simple tool for building item models in game. Instead of using a seperate applications like MC Model Maker, I am building the model with blocks, selecting them, and then generating a json model. So far, I have this writing to a file which I relocate when I quit the game, but, if not complicated, it would be interesting to load the model at runtime.

     

     

  5. Did you get this going? I have a few questions about how this might be implemented.

     

    JSON files are loaded via the resource manager. So just register a custom resource pack (IResourcePack) and put it into Minecraft#defaultResourcePacks (you will need reflection as the field is private). Then that IResourcePack can fabricate the InputStreams for the JSON files out of "thin air". A helpful thing to do that is converting a String to an InputSteam.

     

    How do you register a custom resource pack and when does it have to be done?

     

    Could the pack be modified and a model changed at runtime? If so, how?

     

     

     

  6. I put these printlns in my tile entity's shouldRefresh():

     

    @Override
    public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) {
    	System.out.println("oldState="+oldState);
    	System.out.println("newSate="+newSate);
    	new Throwable().printStackTrace();
    	return oldState.getBlock() != newSate.getBlock();
    }
    

     

    and get this in the console:

     

    [16:26:44] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.PrevStateTileEntity:shouldRefresh:30]: oldState=mojo:block_selected
    [16:26:44] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.PrevStateTileEntity:shouldRefresh:31]: newSate=mojo:block_selected
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: java.lang.Throwable
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at org.snowyegret.mojo.block.PrevStateTileEntity.shouldRefresh(PrevStateTileEntity.java:32)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.world.chunk.Chunk.fillChunk(Chunk.java:1425)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.network.NetHandlerPlayClient.handleChunkData(NetHandlerPlayClient.java:763)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.play.server.S21PacketChunkData.processPacket(S21PacketChunkData.java:64)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.play.server.S21PacketChunkData.processPacket(S21PacketChunkData.java:152)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:24)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraftforge.fml.common.FMLCommonHandler.callFuture(FMLCommonHandler.java:714)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1078)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.Minecraft.run(Minecraft.java:376)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.client.main.Main.main(Main.java:117)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at java.lang.reflect.Method.invoke(Method.java:497)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
    [16:26:44] [Client thread/INFO] [sTDERR]: [java.lang.Throwable$WrappedPrintStream:println:748]: 	at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
    

     

    As it turns out, it is this block of code in Chunk.fillChunk() that is calling shouldRefresh():

     

            while (iterator.hasNext())
            {
                TileEntity tileentity = (TileEntity)iterator.next();
                if (tileentity.shouldRefresh(this.worldObj, tileentity.getPos(), tileentity.getBlockType().getStateFromMeta(tileentity.getBlockMetadata()), getBlockState(tileentity.getPos())))
                    invalidList.add(tileentity);
                tileentity.updateContainingBlockInfo();
            }
    
            for (TileEntity te : invalidList) te.invalidate();
    

     

    This must be where minecraft performs a sort of garbage collection by invalidating tile entities which are no longer "referenced" by a block at that position. When the block changes to one that has no new tile entity to overwite it, you don't want it left in the world. I am not sure why this decision is delegated to the tile entity, and why its default implementation returns true if the tile entity is not vanilla (from class TileEntity):

        private boolean isVanilla = getClass().getName().startsWith("net.minecraft.");
    

     

    but my guess is that the I should be keeping the check for oldState.getBlock() != newSate.getBlock() or I will be populating the world with unused tile entities.

  7. Ok, I have found a fix for my problem, but I have no idea of it's consequences, nor do I understand why it's working. Poking around in Chunk.setBlockState() I came across this block of code which removes tile entities:

     

                    if (!this.worldObj.isRemote)
                    {
                        if (iblockstate1.getBlock() != state.getBlock()) //Only fire block breaks when the block changes.
                        block1.breakBlock(this.worldObj, pos, iblockstate1);
                        TileEntity te = this.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
                        if (te != null && te.shouldRefresh(this.worldObj, pos, iblockstate1, state)) this.worldObj.removeTileEntity(pos);
                    }
                    else if (block1.hasTileEntity(iblockstate1))
                    {
                        TileEntity te = this.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
                        if (te != null && te.shouldRefresh(this.worldObj, pos, iblockstate1, state))
                        this.worldObj.removeTileEntity(pos);
                    }
    

     

    TileEntity.shouldRefresh() looks like this:

     

        /**
         * Called from Chunk.setBlockIDWithMetadata, determines if this tile entity should be re-created when the ID, or Metadata changes.
         * Use with caution as this will leave straggler TileEntities, or create conflicts with other TileEntities if not used properly.
         *
         * @param world Current world
         * @param pos Tile's world position
         * @param oldID The old ID of the block
         * @param newID The new ID of the block (May be the same)
         * @return True to remove the old tile entity, false to keep it in tact {and create a new one if the new values specify to}
         */
        public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate)
        {
            return !isVanilla || (oldState.getBlock() != newSate.getBlock());
        }
    

     

    In my tile entity class I have overidden it leaving out the test for isVanilla:

     

    @Override
    public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) {
    	return oldState.getBlock() != newSate.getBlock();
    }
    

     

    and my problem (and it has been a problem for weeks - I have tried everything) has gone away. :)

     

    Please, if anyone has some insight, please share it. I am wary of the caution in the javadoc comment.

     

  8. Something else that may be relevant. I sometimes get this warning in the console when the tile entity is coming up null:

     

    [12:47:43] [Client thread/WARN]: Needed to grow BufferBuilder buffer: Old size 524288 bytes, new size 2621440 bytes.
    

     

    Does anyone know which class is printing this warning?

  9. After I set my block (BTW, world.setBlock(pos, state, 3) without marking the position for update seems to behave identically) I need to set field prevState (type IBlockState) on the tile entity. When the tile entity is created by my block, field prevState is uninitialized:

     

    @Override
    public TileEntity createNewTileEntity(World worldIn, int meta) {
    	return new PrevStateTileEntity();
    }
    

     

     

     

  10. I have placed this line with a breakpoint after the test for a null tile entity (just gets the tile entity again)

     

    		
    world.getTileEntity(pos);
    

     

    it takes me here in class RegionRenderCache:

     

    		
        public TileEntity getTileEntity(BlockPos pos)
        {
            int i = (pos.getX() >> 4) - this.chunkX;
            int j = (pos.getZ() >> 4) - this.chunkZ;
            return this.chunkArray[i][j].getTileEntity(pos, Chunk.EnumCreateEntityType.QUEUED);
        }
    

     

    to here in class Chunk:

        public TileEntity getTileEntity(BlockPos pos, Chunk.EnumCreateEntityType p_177424_2_)
        {
            TileEntity tileentity = (TileEntity)this.chunkTileEntityMap.get(pos);
    
            if (tileentity != null && tileentity.isInvalid())
            {
                chunkTileEntityMap.remove(pos);
                tileentity = null;
            }
    
            if (tileentity == null)
            {
                if (p_177424_2_ == Chunk.EnumCreateEntityType.IMMEDIATE)
                {
                    tileentity = this.createNewTileEntity(pos);
                    this.worldObj.setTileEntity(pos, tileentity);
                }
                else if (p_177424_2_ == Chunk.EnumCreateEntityType.QUEUED)
                {
                    this.field_177447_w.add(pos);
                }
            }
    
            return tileentity;
        }
    
    

     

    tileentity comes back null from chunkTileEntityMap then when p_177424_2_ == Chunk.EnumCreateEntityType.QUEUED, the position is added to field_177447_w which is of type ConcurrentLinkedQueue.

     

     

  11. I have a block which provides a tile entity and is rendered by an ISmartBlockModel.

     

    Method handleBlockState() is overidden to lookup a model given an IBlockState which is read from an unlisted property which is in turn set from a field on the block's tile entity. This is all based on TheGreyGhost's Minecraft by Example MBE04, and works fine, most of the time.

     

    Here is my block:

     

    public class BlockSelected extends Block implements ITileEntityProvider {
    
    public static final PrevStateProperty prevStateProperty = new PrevStateProperty();
    
    public BlockSelected() {
    	super(Material.clay);
    }
    
    @Override
    public boolean isOpaqueCube() {
    	return false;
    }
    
    @SideOnly(Side.CLIENT)
    public EnumWorldBlockLayer getBlockLayer() {
    	return EnumWorldBlockLayer.CUTOUT_MIPPED;
    }
    
    @Override
    protected BlockState createBlockState() {
    	return new ExtendedBlockState(this, new IProperty[0], new IUnlistedProperty[] { prevStateProperty });
    }
    
    @Override
    public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) {
    	PrevStateTileEntity tileEntity = (PrevStateTileEntity) world.getTileEntity(pos);
    	IBlockState prevState = null;
    	if (tileEntity != null) {
    		prevState = tileEntity.getPrevState();
    	} else {
    		System.out.println("tileEntity=" + tileEntity);
    	}
    	return ((IExtendedBlockState) state).withProperty(prevStateProperty, prevState);
    }
    
    @Override
    public TileEntity createNewTileEntity(World worldIn, int meta) {
    	return new PrevStateTileEntity();
    }
    
    }
    

     

    and here is the ISmartBlockModel's relevent code:

     

    public class BlockSelectedModel implements ISmartBlockModel {
    
    private IBakedModel model;
    
    @Override
    public IBakedModel handleBlockState(IBlockState state) {
    	IBlockState s = ((IExtendedBlockState) state).getValue(BlockSelected.prevStateProperty);
    	model = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getModelForState(s);
    	return this;
    }
    }
    

     

    Here is my tile entity with its IBlockState field:

     

    public class PrevStateTileEntity extends TileEntity {
    
    private IBlockState prevState;
    private final String PREV_STATE_KEY = "b";
    
    public IBlockState getPrevState() {
    	return prevState;
    }
    
    public void setPrevState(IBlockState state) {
    	prevState = state;
    }
    
    @Override
    public void writeToNBT(NBTTagCompound tag) {
    	tag.setInteger(PREV_STATE_KEY, Block.getStateId(prevState));
    	super.writeToNBT(tag);
    }
    
    @Override
    public void readFromNBT(NBTTagCompound tag) {
    	prevState = Block.getStateById(tag.getInteger(PREV_STATE_KEY));
    	super.readFromNBT(tag);
    }
    
    @Override
    public Packet getDescriptionPacket() {
    	NBTTagCompound tag = new NBTTagCompound();
    	writeToNBT(tag);
    	super.writeToNBT(tag);
    	return new S35PacketUpdateTileEntity(pos, this.getBlockMetadata(), tag);
    }
    
    @Override
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
    	readFromNBT(pkt.getNbtCompound());
    	super.readFromNBT(pkt.getNbtCompound());
    }
    
    }
    

     

    I am placing the block in the world like this:

     

    	world.setBlockState(pos, state, 1);
    	world.markBlockForUpdate(pos);
    	PrevStateTileEntity tileEntity = (PrevStateTileEntity) world.getTileEntity(pos);
    	tileEntity.setPrevState(prevState);
    

     

    The problem occurs when the tile entity in getExtendedState() occasionally comes up null during rendering. Without the tile entity, I can not set the unlisted property and the block can't render. This always happens when I set a range of blocks, and then set another adjacent range. The first range renders properly after being set, but then their tile entities come back null after the adjacent range is set. I know the tile entity is null, because I get the println in getExtendedState().

     

    If I set the first range, then walk away into another chunk before coming back and setting the second range, things are ok, and world.getTileEntity(pos) comes back with a valid tile entity.

     

    Here is an image of the problem. The outermost ring of blocks are the new setBlockStates. The inner blocks were rendering properly before the outer ring was added. I am guessing they cross a chunk boundary which would explain why some of the inner ones are rendering properly:

     

    width=701 height=4702pjOA5N.png?1 [/img]

     

     

  12. Much better. :) Only one message to server. Testing for modifier presses on the server side only. Thanks.

     

    I still want something higher lever like this on the server side (I am wrapping player to encapsulate the mess of getting extended properties):

     

            UndoManager um = player.getUndoManager();
                    Modifiers modifiers = player.getModifiers();
    	boolean isHollow = modifiers.isPressed(Modifier.SHIFT);
    	boolean isOnSurface = modifiers.isPressed(Modifier.ALT);
    

     

    and this when I add to overlay info to explain what the modifiers do (looks up strings from lang files):

     

                     info.addModifiers(Modifier.SHIFT, Modifier.ALT);
    

     

    Also useful here:

     

    static {
    	for (Modifier m : Modifier.values()) {
    		KEYS_TO_TRACK.add(m.key);
    	}
    	// Other keys to track which are not modifiers
    	KEYS_TO_TRACK.add(Keyboard.KEY_DELETE);
    }
    

     

     

  13. This is what I am putting in my map:

     

    public enum Modifier {
    
    // Use ints to avoid Keyboard class on server side
    // http://www.minecraftforge.net/forum/index.php/topic,31059.msg161734.html#msg161734
    
    // http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
    // SHIFT(16),
    // CTRL(17),
    // ALT(18),
    // X(88),
    // Y(89),
    // Z(90),
    
    // This is what I was getting from printlns
    SHIFT(42),
    CTRL(29),
    ALT(56),
    X(45),
    Y(21),
    Z(44),
    SPACE(57);
    
    public int key;
    
    private Modifier(int key) {
    	this.key = key;
    }
    
    // For ModifierMessage.fromBytes()
    public static Modifier fromKey(int key) {
    	for (Modifier m : values()) {
    		if (m.key == key) {
    			return m;
    		}
    	}
    	return null;
    }
    
    // Convenience method for client side only
    @SideOnly(Side.CLIENT)
    public boolean isPressed() {
    	return Keyboard.isKeyDown(this.key);
    }
    }
    

     

    Can I hard code the ints instead of e.g. Keyboard.KEY_SPACE or will I run into trouble? Already I was not getting what I expected from Keyboard.getEventKey() in my KeyInputEvent handler.

     

    Also, is this the proper usage of @SidefOnly to avoid problems with isPressed() on the server side?. Method isPressed() is intended to used client side only like this:

    if (Modifier.CTRL.isPressed()) {
    

     

    If this is not recommended I will just dump it and test like this:

     

     
            if (Keyboard.isKeyDown(Modifier.CTRL.key))

  14. I like it. :) Thanks Ernio.

     

    Just one other thing. KeyInputEvent that you suggested ealier in the thread does not have a keystate property like MouseEvent has a buttonstate property. It is difficult to tell if the event is a press or a release, especially in the case of  combinations of 3 modifier keys which be pressed or released an in any order. Is there another event, possibly on the forge side, that has key and keystate properties?

  15. Thanks Ernio for pointing this out to me.

     

    I am talking about the selectionManager, pickManager, and undoManager discussed a couple of days ago in this topic:

     

    http://www.minecraftforge.net/forum/index.php/topic,30991.msg161418.html#msg161418

     

    There is one for each player. Up until now I have just been throwing them out when the player quits the game - there is no real incentive to keep their data.  I suppose I can just leave IIEP's saveNBTData(), loadNBTData(), and init() unimplemented?

  16. Something like PlayerInteractEvent.Action.MODIFIER_CTRL would have been helpful. I will use KeyInputEvent and message the server as you suggest.

     

    And yes, modifiers must be on a per player basis. Since I'm already tracking other stuff for each player which cannot be put on extended properties, I think I will stick with my class Modifiers and look it up from a Player to Modifiers map.

  17. My mouse input is all nicely picked up on the server thread. Now I would like a way to modify the clicks with a set of defined modifier keys. I need a way to replace Keyboard.isPressed(). Something like Player.isSneaking(). So far I have a class Modifier with enums for the keys I am using for modifiers - shift, click, alt, x, y, z, and spacebar, and a class Modifiers, instantiated on the server side, with a map of Modifier to Boolean and with methods setPressed(), isPressed(). I need an event preferably with a WorldServer property, which allows me to distinguish key presses from releases, so that I can set the modifier state in class Modifiers.

     

    First of all, am I completely out to lunch? :)

    Have I missed something that forge gives me for managing this?

    Is my strategy a good one?

    What is the best event for the job?

  18. Just wanted to check that there is no method like onItemUse() or onItemRightClick() for the left mouse click which would give me a remote world. I want to replace the breaking behavior for left mouse click for my Item. Currently I am subscribing to MouseEvents and messaging to the server from the client thread. Does 1.8 offer any new ways to do this?

×
×
  • Create New...

Important Information

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