UFIOES Posted July 26, 2014 Share Posted July 26, 2014 I have been trying to make an item that modifies the terrain around the player as it is used. But I am having problems: the blocks look like they have changed, and middle mouse click puts the right block into the player inventory, but if the block is right clicked on (not just given a block update), it changes back into the original block. Additionally if the block is harvested in survival, it drops what the original block would have. And when I save and quit to the main menu, and then re-open the world, all of the blocks go back. Also the item (indirectly) fills bottles in the player's inventory, but when the player right clicks with the original stack of bottles, the stack goes from having 63 empty bottles to having 64, and the new filled bottle cannot be dropped in the world with 'Q.' The player's inventory also reverts to the original contents when the world is reloaded Here is the class of the item: package com.UFIOES.runicMagic.items; import java.util.Random; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.block.Block; import net.minecraft.block.BlockSapling; import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.MinecraftForge; import com.UFIOES.runicMagic.RunicMagic; import com.UFIOES.runicMagic.entities.*; public class RuneStone extends Item { private static final int ENERGY_CAPACITY = 64; private char type; private Random random = new Random(); private int storedEnergy = 0; public RuneStone() { setMaxStackSize(1); setCreativeTab(CreativeTabs.tabTools); setUnlocalizedName("blankRuneStone"); type = 'b'; } public RuneStone(String name, char type) { setMaxStackSize(1); setCreativeTab(CreativeTabs.tabTools); setUnlocalizedName(name); this.type = type; } @Override public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { if (type == 'a') { //a is the type of the RuneStone that does something when right clicked //tests for any nearby living blocks if (isBlock) { storedEnergy = 0; player.setItemInUse(stack, 2048); } } return stack; } @Override public void onUsingTick(ItemStack stack, EntityPlayer player, int count) { super.onUsingTick(stack, player, count); World world = player.worldObj; boolean test = player.isUsingItem() && player.getItemInUse().getItem().equals(RunicMagic.runeStoneAbsorb); int runeHungry = random.nextInt(7); if (test) { int radius = 3; int pX = (int) player.posX; int pY = (int) player.posY; int pZ = (int) player.posZ; boolean isBlock = false; blockFinder: for (int x=-radius; x <= radius; x++) { for (int y=-radius; y <= radius; y++) { for (int z=-radius; z <= radius; z++) { Block block = world.getBlock(pX + x, pY + y, pZ + z); if (testForLiving(world, block, pX + x, pY + y, pZ + z)) { isBlock = true; break blockFinder; } } } } if (!isBlock) { player.stopUsingItem(); } } if (test && runeHungry == 3) { int pX = (int) player.posX; int pY = (int) player.posY; int pZ = (int) player.posZ; int tries=0; while (tries < 20) { int x = random.nextInt(7) - 3; int y = random.nextInt(7) - 3; int z = random.nextInt(7) - 3; Block block = world.getBlock(pX + x, pY + y, pZ + z); if (testForLiving(world, block, pX + x, pY + y, pZ + z)) { consumeBlock(world, block, pX + x, pY + y, pZ + z); storedEnergy++; if (storedEnergy >= ENERGY_CAPACITY) { player.stopUsingItem(); } break; } tries++; } } } @Override public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int time) { if (type == 'a' && storedEnergy != 0) { double x = player.posX - 3*Math.sin(player.rotationYaw * (Math.PI/180.0)); double y = player.posY; double z = player.posZ + 3*Math.cos(player.rotationYaw * (Math.PI/180.0)); world.spawnEntityInWorld(new ManaOrb(world, x, y, z, storedEnergy)); storedEnergy = 0; super.onPlayerStoppedUsing(stack, world, player, time); } } private boolean testForLiving(World world, Block block, int x, int y, int z) { if (block.isLeaves(world, x, y, z)) return true; if (IPlantable.class.isInstance(block)) return true; if (net.minecraft.block.BlockAir.class.isInstance(block)) return false; if (net.minecraft.block.BlockGrass.class.isInstance(block)) return true; if (net.minecraft.block.BlockDirt.class.isInstance(block)) return true; if (net.minecraft.block.BlockCactus.class.isInstance(block)) return true; if (net.minecraft.block.BlockCarrot.class.isInstance(block)) return true; // this continues for each block that is 'living' return false; } private void consumeBlock(World world, Block block, int x, int y, int z) { boolean decayToDirt = false; //tests if the block should decay to dirt if (decayToDirt) { world.setBlock(x, y, z, Blocks.dirt); return; } if (net.minecraft.block.BlockDirt.class.isInstance(block)) { world.setBlock(x, y, z, Blocks.sand); return; } if (net.minecraft.block.BlockTallGrass.class.isInstance(block)) { world.setBlock(x, y, z, Blocks.deadbush); return; } world.setBlockToAir(x, y, z); } } Quote Link to comment Share on other sites More sharing options...
larsgerrits Posted July 26, 2014 Share Posted July 26, 2014 You are doing things client side, do those server side. Hint: Use world.isRemote , that will return true if it's client and false if it's server. Quote Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support. 1.12 -> 1.13 primer by williewillus. 1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support. http://www.howoldisminecraft1710.today/ Link to comment Share on other sites More sharing options...
UFIOES Posted July 26, 2014 Author Share Posted July 26, 2014 Where / when should I test if world.isRemote? Quote Link to comment Share on other sites More sharing options...
Xcox123 Posted July 26, 2014 Share Posted July 26, 2014 public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { if(world.isRemote){ CODE } } Quote Link to comment Share on other sites More sharing options...
UFIOES Posted July 26, 2014 Author Share Posted July 26, 2014 @Xcox123 wouldn't that only run on the client side because world.isRemote is true for the client? I have tried it both ways, If it only runs on the client side, nothing changes; blocks still 'appear to change' and revert when right clicked. If it only runs on the client side, then it behaves as if there where no right click functionality at all on the item, blocks do not even 'appear to change' My current theory is that it needs to run on both client and server, and it is disagreement between them when a block is right clocked that causes one of them to assert the block it has is correct, and causing the block to change back... I have tried removing the randomness to the changes, so they will be identical when run by the client and server, but to no avail. Quote Link to comment Share on other sites More sharing options...
Xcox123 Posted July 26, 2014 Share Posted July 26, 2014 Want it to run server-side? isRemote's a boolean, so !world.isRemote will do. Quote Link to comment Share on other sites More sharing options...
UFIOES Posted July 26, 2014 Author Share Posted July 26, 2014 I think I have found the cause of the problem. I put a System.out.println(world.isRemote); into the onUsingTick method tested it, and it only ever outputted true whereas when I did the same thing to onItemRightClick it outputted true and then false. So the method that does all of the changes only runs on the client side, how do I make onUsingTick also run on the server side? Quote Link to comment Share on other sites More sharing options...
UFIOES Posted July 26, 2014 Author Share Posted July 26, 2014 I solved the problem by using the SimpleNetworkWrapper so the client could tell the server how the world changed. I would prefer a solution where EntityPlayer.class would, in it's onUpdate method, call onUsingTick on both the client and the server or offer a version that does both. It would not be very efficient to have to write two classes for every time that a method that is called on the client only, is needed to change some blocks in the world or do some stuff with items or entities. For those whom are interested, here is the working solution: Seealso: Using the Simple Network Implementation (SimpleNetworkWrapper) [1.7] at http://www.minecraftforge.net/forum/index.php/topic,20135.msg101552.html#msg101552 The item class (only the consumeBlock method was modified): public void consumeBlock(World world, Block block, int x, int y, int z) { if (!world.isRemote) { world.setBlock(x, y, z, block); return; } //tests if the block should decay to dirt if (decayToDirt) { world.setBlock(x, y, z, Blocks.dirt); RunicMagic.network.sendToServer(new RuneMessage('d', x, y, z)); return; } if (net.minecraft.block.BlockDirt.class.isInstance(block)) { world.setBlock(x, y, z, Blocks.sand); RunicMagic.network.sendToServer(new RuneMessage('s', x, y, z)); return; } if (net.minecraft.block.BlockTallGrass.class.isInstance(block)) { world.setBlock(x, y, z, Blocks.deadbush); RunicMagic.network.sendToServer(new RuneMessage('b', x, y, z)); return; } world.setBlockToAir(x, y, z); RunicMagic.network.sendToServer(new RuneMessage('a', x, y, z)); } The RuneMessage class: public class RuneMessage implements IMessage { public char myChar; public int x; public int y; public int z; public RuneMessage() {} public RuneMessage(char c, int x, int y, int z) { myChar = c; this.x = x; this.y = y; this.z = z; } @Override public void fromBytes(ByteBuf buf) { myChar = buf.readChar(); x = buf.readInt(); y = buf.readInt(); z = buf.readInt(); } @Override public void toBytes(ByteBuf buf) { buf.writeChar(myChar); buf.writeInt(x); buf.writeInt(y); buf.writeInt(z); } } and the RuneMessageHandler class: public class RuneMessageHandler implements IMessageHandler<RuneMessage, IMessage> { @Override public IMessage onMessage(RuneMessage message, MessageContext ctx) { char c = message.myChar; int x = message.x; int y = message.y; int z = message.z; Block block = Blocks.air; switch (c) { case 'd': block = Blocks.dirt; break; case 's': block = Blocks.sand; break; case 'b': block = Blocks.deadbush; break; } ((RuneStone) RunicMagic.runeStoneAbsorb).consumeBlock(ctx.getServerHandler().playerEntity.worldObj, block, x, y, z); return null; } } Quote Link to comment Share on other sites More sharing options...
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.