Jump to content

1.7.10 Adding a delay to setting a block within a Tile Entity


Recommended Posts

Posted

My latest project has been to make an Elevator for Minecraft.  Have learned a lot doing so with respect to Tile entities, packet handling, and gui's and I know that I can learn more.  Everything works well but one thing.  The floor movement up and down moves too fast.  I would like to slow it down, so it feels like a real elevator moving up and down.  Attached is my TE that has all the movement code in it.  I am looking for some suggestions on how to place a few second delay between each step of the Y axis movement as the floor and players move up and down.  The method startFloorCall is at the bottom of the code.  The method is called from within the updateEntity() method when floorCall = true.

1.  Tried just a simple counter loop.  No change.

2.  Tried a tick handler server side.  Seemed to work for the floor, but not the players.  Are player movements client side, server side, or both.  If client side, would explain why this did not work.

3.  Tried to add a timer to the updateEntity() in the TE, but the timer would never update when I was within my method.  If I could get this to work, would be best for cpu time.

 

package com.eractnod.elevator.tileentity;

import java.util.List;

import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;

public class TileEntityCreateElevator extends TileEntity implements IInventory{

private ItemStack[] inv;
private String customName;
public String numberOfFloors;
public String numberBetweenFloors;
public String direction;
private boolean floors = false;
public int[] floorX = new int[16];
public int[] floorY = new int[16];
public int[] floorZ = new int[16];
public int[] floorNum = new int[16];
public int currentFloor;
public int calledFloor;
public boolean performCall = false;
public boolean floorCall = false;


public TileEntityCreateElevator(){
	inv = new ItemStack[2];
}
@Override
public int getSizeInventory() {
	return inv.length;
}

@Override
public ItemStack getStackInSlot(int slot) {
	return inv[slot];
}

@Override
public ItemStack decrStackSize(int slot, int amount) {
	ItemStack stack = getStackInSlot(slot);

	if (stack != null) {

		if (stack.stackSize <= amount) {
			setInventorySlotContents(slot, null);
		} 
		else {
			stack = stack.splitStack(amount);

			if (stack.stackSize == 0) {
				setInventorySlotContents(slot, null);
			}
		}
	}

	return stack;
}

@Override
public ItemStack getStackInSlotOnClosing(int slot) {
	ItemStack stack = getStackInSlot(slot);

	if (stack != null) {
		setInventorySlotContents(slot, null);
	}
	return stack;
}

@Override
public void setInventorySlotContents(int slot, ItemStack stack) {

	inv[slot] = stack;

	if (stack != null && stack.stackSize > getInventoryStackLimit()) 
	{
		stack.stackSize = getInventoryStackLimit();

	}
}

@Override
public String getInventoryName() {
	return null;
}

@Override
public boolean hasCustomInventoryName() {
	return false;
}

@Override
public int getInventoryStackLimit() {
	return 1;

}

@Override
public boolean isUseableByPlayer(EntityPlayer player) {
	return worldObj.getTileEntity(xCoord, yCoord, zCoord) == this && player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64;
}

@Override
public void openInventory() {

}

@Override
public void closeInventory() {
}

@Override
public boolean isItemValidForSlot(int slot, ItemStack stack) {

	return true;
}

public void updateEntity(){


		if (performCall){
			System.out.println("yobo");
			startCall(calledFloor, worldObj);
			this.setCurrent(calledFloor);
			this.currentFloor = calledFloor;
			performCall = false;
			worldObj.markBlockForUpdate(floorX[0], floorY[0], floorZ[0]);
		}

		if(!worldObj.isRemote){
			if (floorCall){
				System.out.println("yobo2");
				startFloorCall(calledFloor, worldObj);
				this.setCurrent(calledFloor);
				floorCall = false;
				worldObj.markBlockForUpdate(floorX[0], floorY[0], floorZ[0]);
			}
		}


}

public void setFloors(String a, String b, String c){
	numberOfFloors = a;
	numberBetweenFloors = b;
	direction = c;
}

public ItemStack getFloorItemStack(){
	return inv[0];
}

public String getFloors(){
	return numberOfFloors;
}

public String getBetween(){
	return numberBetweenFloors;
}

public String getDirection(){
	return direction;
}

public void setFloorLocations(int x, int y, int z, int metaCall) {
	System.out.println("x " + x + " y " + y + " z " + z + " meta " + metaCall);
	this.floorX[metaCall] = x;
	this.floorY[metaCall] = y;
	this.floorZ[metaCall] = z;

}

public void setCurrent(int meta){

	this.currentFloor = meta;

}

public int getCurrent(){
	return currentFloor;
}

public void setPerformCall(int calledFloor, boolean performCall, boolean floorCall) {
	this.calledFloor = calledFloor;
	this.performCall = performCall;
	this.floorCall = floorCall;

}
public int getFloorCalled(){
	return this.calledFloor;
}
public boolean getPerformCall(){
	return this.performCall;
}
public boolean getNextFloor(){
	return this.floorCall;
}
 /**
     * Reads a tile entity from NBT.
     */
    public void readFromNBT(NBTTagCompound nbt)
    {
        super.readFromNBT(nbt);
        NBTTagList nbttaglist = nbt.getTagList("Items", 10);
        this.inv = new ItemStack[this.getSizeInventory()];

        if (nbt.hasKey("NumberFloors")){
        	numberOfFloors = nbt.getString("NumberFloors");
        }
        if (nbt.hasKey("NumberBetween")){
        	numberBetweenFloors = nbt.getString("NumberBetween");
        }
        if (nbt.hasKey("Direction")){
        	direction = nbt.getString("Direction");
        }
        if (nbt.hasKey("name"))
        {
            this.customName = nbt.getString("name");
        }

        for (int i = 0; i < nbttaglist.tagCount(); ++i)
        {
            NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.getCompoundTagAt(i);
            int j = nbttagcompound1.getByte("Slot") & 255;

            if (j >= 0 && j < this.inv.length)
            {
                this.inv[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
            }
        }
        
        for (int i = 0; i < floorX.length; i++){
        	this.floorX[i] = nbt.getInteger("floorX" + i);
        	this.floorY[i] = nbt.getInteger("floorY" + i);
        	this.floorZ[i] = nbt.getInteger("floorZ" + i);
        }
        this.currentFloor = nbt.getInteger("current");
        this.calledFloor = nbt.getInteger("calledfloor");
        this.performCall = nbt.getBoolean("performcall");
        this.floorCall = nbt.getBoolean("floorcall");
    }
    
    /**
     * Writes a tile entity to NBT.
     */
    public void writeToNBT(NBTTagCompound nbt)
    {
        super.writeToNBT(nbt);
        NBTTagList nbttaglist = new NBTTagList();

        for (int i = 0; i < this.inv.length; ++i)
        {
            if (this.inv[i] != null)
            {
                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
                nbttagcompound1.setByte("Slot", (byte)i);
                this.inv[i].writeToNBT(nbttagcompound1);
                nbttaglist.appendTag(nbttagcompound1);
            }
        }

        nbt.setTag("Items", nbttaglist);

        if (this.hasCustomInventoryName())
        {
            nbt.setString("name", this.customName);
        }
        if (numberOfFloors != null){
        	nbt.setString("NumberFloors", numberOfFloors);
        }
        if (numberBetweenFloors != null){
        	nbt.setString("NumberBetween", numberBetweenFloors);
        }
        if (direction != null){
        	nbt.setString("Direction", direction);
        }
        for (int i = 0; i < floorX.length; i++){
        	nbt.setInteger("floorX" + i, this.floorX[i]);
        	nbt.setInteger("floorY" + i, this.floorY[i]);
        	nbt.setInteger("floorZ" + i, this.floorZ[i]);
        }
        nbt.setInteger("current", currentFloor);
        nbt.setInteger("calledfloor", calledFloor);
        nbt.setBoolean("performcall", performCall);
        nbt.setBoolean("floorcall", floorCall);
    }

    /**
     * Called when you receive a TileEntityData packet for the location this
     * TileEntity is currently in. On the client, the NetworkManager will always
     * be the remote server. On the server, it will be whomever is responsible for
     * sending the packet.
     *
     * @param net The NetworkManager the packet originated from
     * @param pkt The data packet
     */
// Client Server Sync
    @Override
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
    NBTTagCompound nbt = pkt.func_148857_g();
    numberOfFloors = nbt.getString("NumberFloors");
    numberBetweenFloors = nbt.getString("NumberBetween");
    direction = nbt.getString("Direction");
    
    for (int i = 0; i < floorX.length; i++){
    	floorX[i] = nbt.getInteger("floorX" + i);
    	floorY[i] = nbt.getInteger("floorY" + i);
    	floorZ[i] = nbt.getInteger("floorZ" + i);
    }
    this.currentFloor = nbt.getInteger("current");
    this.calledFloor = nbt.getInteger("calledfloor");
    this.performCall = nbt.getBoolean("performcall");
    this.floorCall = nbt.getBoolean("floorcall");

    }

    @Override
    public Packet getDescriptionPacket() {
    NBTTagCompound nbt = new NBTTagCompound();
    if (numberOfFloors != null){
    	nbt.setString("NumberFloors", numberOfFloors);
    }
    if (numberBetweenFloors != null){
    	nbt.setString("NumberBetween", numberBetweenFloors);
    }
    if (direction != null){
    	nbt.setString("Direction", direction);
    }
    
    for (int i = 0; i < floorX.length; i++){
    	nbt.setInteger("floorX" + i, floorX[i]);
    	nbt.setInteger("floorY" + i, floorY[i]);
    	nbt.setInteger("floorZ" + i, floorZ[i]);
    }
    nbt.setInteger("current", currentFloor);
    nbt.setInteger("calledfloor", calledFloor);
    nbt.setBoolean("performcall", performCall);
    nbt.setBoolean("floorcall", floorCall);

    return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, this.blockMetadata, nbt);
    }
    
    public Block getFloorBlock(World world){
    	Block floorBlock = Blocks.stone;
    	TileEntityCreateElevator te = (TileEntityCreateElevator) world.getTileEntity(floorX[0], floorY[0], floorZ[0]);
    	ItemStack stack = te.getStackInSlot(0);
    	if (stack != null){
		if (stack.getItem() instanceof ItemBlock){
			Item floorItem = stack.getItem();
			int meta0 = stack.getItemDamage();
			floorBlock = Block.getBlockFromItem(floorItem);
			return floorBlock;
		}
    	}
    	
    	return floorBlock;
    }
    public int getFloorBlockMeta(World world){
    	Block floorBlock = Blocks.stone;
    	TileEntityCreateElevator te = (TileEntityCreateElevator) world.getTileEntity(floorX[0], floorY[0], floorZ[0]);
    	ItemStack stack = te.getStackInSlot(0);
    	if (stack != null){
		if (stack.getItem() instanceof ItemBlock){
			Item floorItem = stack.getItem();
			int meta0 = stack.getItemDamage();
			floorBlock = Block.getBlockFromItem(floorItem);
			return meta0;
		}
    	}
    	
    	return 0;
    }
public void startCall(int meta, World world) {
	Block floorBlock = this.getFloorBlock(world);
	int floorMeta = this.getFloorBlockMeta(world);
	int currentFloor = this.getCurrent();
	int x = this.floorX[currentFloor];
	int y = this.floorY[currentFloor];
	int z = this.floorZ[currentFloor];
	//Current floor below called floor Move UP
	if (currentFloor < meta){
		for (int y2 = y; y2 != floorY[meta]; y2++){
			for (int x11 = -1; x11 <=1; x11++){
				for (int z11 = -1; z11 <=1; z11++){
					world.setBlock(x + x11, y2, z + z11, Blocks.air);
					world.setBlock(x + x11, y2 + 1, z + z11, floorBlock, floorMeta, 2);
				}
			}


		}

	}
	//Current floor above called floor Move DOWN
	if (currentFloor > meta){
		for (int y2 = y; y2 != floorY[meta]; y2--){
			for (int x11 = -1; x11 <=1; x11++){
				for (int z11 = -1; z11 <=1; z11++){
					world.setBlock(x + x11, y2, z + z11, Blocks.air);
					world.setBlock(x + x11, y2 - 1, z + z11, floorBlock, floorMeta, 2);
				}
			}


		}

	}

}

private void startFloorCall(int calledFloor2, World world) {
	int numberFloors = Integer.parseInt(numberOfFloors);
	//EntityPlayer player = this.worldObj.getClosestPlayer(this.floorX[currentFloor], this.floorY[currentFloor], this.floorZ[currentFloor], 10);
	List listPlayer = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, AxisAlignedBB.getBoundingBox(this.floorX[0]-2,this.floorY[0],this.floorZ[0]-2,this.floorX[numberFloors]+2,this.floorY[numberFloors]+2,this.floorZ[numberFloors]+2));
	System.out.println("List " + listPlayer);
	if (!listPlayer.isEmpty()){
		Block floorBlock = this.getFloorBlock(world);
		int floorMeta = this.getFloorBlockMeta(world);
		int currentFloor = this.getCurrent();
		int x = this.floorX[currentFloor];
		int y = this.floorY[currentFloor];
		int z = this.floorZ[currentFloor];
		//Current floor below called floor Move UP
		if (currentFloor < calledFloor2){
			for (int y2 = y; y2 != floorY[calledFloor2]; y2++){
				for (int x11 = -1; x11 <=1; x11++){
					for (int z11 = -1; z11 <=1; z11++){

						/** Need delay here
						 * 
						 * 
						 * 
						 */												
						world.setBlock(x + x11, y2, z + z11, Blocks.air);
						world.setBlock(x + x11, y2 + 1, z + z11, floorBlock, floorMeta, 2);
						for (int i = 0; i < listPlayer.size(); i++){
							EntityPlayer p = (EntityPlayer) listPlayer.get(i);
							p.setPositionAndUpdate(x + x11, y2 + 2, z + z11);
						}
						//player.setPositionAndUpdate(x + x11, y2 + 2, z + z11);

					}

				}

			}
		}
		//Current floor above called floor Move DOWN
		if (currentFloor > calledFloor2){
			for (int y2 = y; y2 != floorY[calledFloor2]; y2--){
				for (int x11 = -1; x11 <=1; x11++){
					for (int z11 = -1; z11 <=1; z11++){

						/** Need delay here
						 * 
						 * 
						 * 
						 */						
						world.setBlock(x + x11, y2, z + z11, Blocks.air);
						world.setBlock(x + x11, y2 - 1, z + z11, floorBlock, floorMeta, 2);
						for (int i = 0; i < listPlayer.size(); i++){
							EntityPlayer p = (EntityPlayer) listPlayer.get(i);
							p.setPositionAndUpdate(x + x11, y2, z + z11);
						}
						//player.setPositionAndUpdate(x + x11, y2, z + z11);

					}

				}

			}
		}
	}
}

}

Posted

have you tried a CD int? you tried a counter loop, I think you had the right idea? or did exactly what I'm going to tell you:

 

int CD_TIME = 45;

int coolDown = CD_TIME;

 

@Override

public void updateEntity()

{

 

if (coolDown == 0)

{

coolDown = CD_TIME;

//put delayed commands in here

}

else coolDown --;

}

 

I think someone asked me why I did that and it's because some of my tile Entities have some large CPU hungry commands that they don't need to run every tick, just every now and then (to make sure things are going ok) one day I'll re-factor to something nicer and more intelligent but I just use my manual counters, since a tile Entity and other entities update every tick (that's what 100 times a second?) so the delay would be every 45 ticks. This is just my really dumb workaround. Maybe someone will come along with a better more efficient solution

Posted

Thank you for the replies.  Between the two answers I was able to get my ServerTickHandler to work to add the delay.  However I have come to the conclusion that the jerky movement would cause too many headaches. So will do without until I can figure out 1/4 or 1/8 block steps.  Would make the movement less choppy.

Now to add Elevator music while you are in the elevator.

 

Tickhandler code

public class ServerTickHandler {

public int timer;

public ServerTickHandler(){
	this.timer = 12000;
}

@SubscribeEvent
public int onServerTick(TickEvent.ServerTickEvent event){
	timer--;
	if (timer == 0){
		timer = 12000;
	}
	return timer;
}


}

 

And what I added to the TE.

 

		ServerTickHandler handler = new ServerTickHandler();
	int tick;

						do{
							tick = handler.onServerTick(null);
						}while (tick != 1);

Posted

Hi

 

Your tile Entity can render anywhere, so you can render it in 1/8 block steps if you want.  I imagine your lift shaft is rendered using blocks, and your elevator using the TileEntitySpecialRenderer, which gives you lots of flexibility?

 

The server doesn't need to do much - just to communicate to the client what the elevator state is (moving, to which floor, etc); the smooth movement needs to happen on the client.

 

On the client, every tick, update the elevator position based on the speed.

For example

 

float currentYpos = lastTickYPos + currentSpeedBlocksPerTick;

 

Then render the elevator at the fractional y position (and update the player position if they are inside the elevator - you will need to figure out how to temporarily ignore server updates of the player position to avoid rubber banding - I have done that before, don't remember off hand since I don't have my code to hand - let us know if you need help with that).

 

-TGG

 

 

 

 

Posted

I was thinking about going that route.  Make the floor into a 9 block entity that mimic's the boat or minecart, then set ridable to true.  That would mean a 3rd re-write of this mod.  (and of coarse I am most likely going to do it as it would mean learning something new), but not at this time.

The first writing was with 2 tile entitys.  One for the elevator shaft and one placed upto 15 times for making the call and floor buttons. Started to be a nightmare syncing all the data between the two tile entities.

The second writing removed the second tile entity and now just places a block with meta data, and this block then calls the gui for call and floor buttons.  Everything is then stored in the one tile entity.  Made it easier to set and save each floor location during the build of the shaft.

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.