Jump to content

[1.7.10][Solved] Item modifies terrain, but blocks keep changing back


UFIOES

Recommended Posts

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);

}

}

 

Link to comment
Share on other sites

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.

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

@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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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;

}

}

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

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