Jump to content

[1.7.10] Issues with Pipe connections (mechanical)


Minothor

Recommended Posts

I catch the break block in the block class and tell the tileEntity to run the breakAllConnections() method before calling the superclass break method.

Code:

https://github.com/BackSpace47/main/blob/PowerSystem_V2/java/net/RPower/RPowermod/machines/power/cable/BlockFluxCable.java

Link to comment
Share on other sites

Does breakConnection run smoothly or you get some weird behaviour? Also, in breakAllConnections getTarget returns an object with x, y, z of the pipe this pipe connects to, right? connections.contains might be a problem, because I believe it uses equals to check if they are the same object, and they might not be for some reason. Either overwrite equals for PipeDirection or check for the coordinates individually (I suggest last one).

Check out my blog!

http://www.whov.altervista.org

Link to comment
Share on other sites

I haven't been able to test the single function yet, just the removal of a pipe with only one connection. As for the test, I overrode the equals function with a test that checks the results of each connection's toByte() method so I'm evaluating the direction rather than the object in memory.

As far as I can tell, the server and client entities desync, but the server side maintains the correct number while meaning that the pipes client side can behave in unintended ways since packets are transient and don't sync.

One solution will be to make packet handling server side only and sync the tile entities when the server ones receive a packet.

Still left with the visual artifacts client side though.

Link to comment
Share on other sites

Hang on, if it's just a tile entity sync issue this should fix it (as long as Write and Read NBT are complete). Put these in your tile entity

 

   @Override
    public Packet getDescriptionPacket() {//sends packet
    	Packet packet = super.getDescriptionPacket();
    	NBTTagCompound tag = packet != null ? ((S35PacketUpdateTileEntity)packet).func_148857_g() : new NBTTagCompound();
        writeToNBT(tag);
        return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, tag);
    }

    @Override
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {//receives the packet
        super.onDataPacket(net, pkt);
        NBTTagCompound tag = pkt.func_148857_g();
        readFromNBT(tag);
    }

Check out my blog!

http://www.whov.altervista.org

Link to comment
Share on other sites

Cheers for pointing out some of the points that I'd missed in the datapacket methods, I've also added in debug code to check the side that's desyncing and it is indeed the client-side that isn't updating it's connections list, server side it cleaning up just fine it would seem.

 

I've added in your changes in the datapacket methods, but the desync is still rearing it's ugly head I'm afraid.

 

Here's the TileEntity class as it stands currently:

 

package net.RPower.RPowermod.machines.power.cable;

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import RPower.api.power.block.I_MFSink;
import RPower.api.power.block.cable.I_MFCable;
import RPower.api.power.block.cable.I_PipeDirection;
import RPower.api.power.core.E_MFPacketType;
import RPower.api.power.core.MFHelper;
import RPower.api.power.core.MFPacket;
import net.RPower.RPowermod.core.RPCore;
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;
import net.minecraftforge.common.util.ForgeDirection;

public class TileEntityFluxCable extends TileEntity implements I_MFCable {
//Connections are an array of [up, Down, North, East, West, South]
public List<I_PipeDirection> connections;

//whether or not the cable is lossy
public boolean insulatedCable;

//maximum limit the cable can carry
public double packetSizeLimit;

//Packets awaiting processing
public Queue<MFPacket> internalBuffer;

//automatically calculated.
public double percentageLoss;

//transfer mode, unbridged connections can only cross an intersection in straight lines (may be reserved for advanced cabling)
public boolean bridgeConnections;

private double distLimit;

public TileEntityFluxCable()
{
	this(32);
}

public TileEntityFluxCable(double packetSize)
{
	this(packetSize,false);
}

public TileEntityFluxCable(double packetSize, boolean insulated)
{
	this(packetSize,insulated,true);
}
public TileEntityFluxCable(double packetSize, boolean insulated,boolean bridged)
{
	packetSizeLimit= packetSize;
	insulatedCable=insulated;
	bridgeConnections=bridged;
	connections=new LinkedList<I_PipeDirection>();
	internalBuffer=new LinkedList<MFPacket>();
	checkLoss(insulated);
	distLimit = insulatedCable?(4*packetSize):packetSize;
}

private void checkLoss(boolean insulated) {
	if(!insulated)
	{
		percentageLoss=(packetSizeLimit/MFPacket.POWERLIMIT);
	}
}

@Override
public boolean takePacket(MFPacket packet)
{
	double excess=0;
	if(!insulatedCable)
	{

		excess+=(percentageLoss*packet.getBuffer());
		packet.setBuffer(packet.getBuffer()-excess);
	}
	if(packet.getBuffer()>packetSizeLimit)
	{
		excess += packet.getBuffer()-packetSizeLimit;
		packet.setBuffer(packetSizeLimit);
	}
	powerBleed(excess);

	boolean result=false;
	result=internalBuffer.add(packet);
	return result;
}

@Override
public void writeToNBT(NBTTagCompound nbtTag) {
	byte[] connectionsArr = new byte[connections.size()];
	int i =0;
	for (I_PipeDirection connection: connections) {
		connectionsArr[i] = connection.toByte();
		i++;
	}
	nbtTag.setByteArray("connections", connectionsArr);
	nbtTag.setBoolean("insulated", insulatedCable);
	nbtTag.setBoolean("bridged", bridgeConnections);

	nbtTag.setDouble("packetLimit", packetSizeLimit);

	super.writeToNBT(nbtTag);
};

@Override
public void readFromNBT(NBTTagCompound nbtTag) {
	byte[] connectionsArr = nbtTag.getByteArray("connections");
	for (byte b : connectionsArr) {
		I_PipeDirection temp = new PipeDirection(b);
		connections.add(temp);
	}

	insulatedCable=nbtTag.getBoolean("insulated");

	bridgeConnections=nbtTag.getBoolean("bridged");

	packetSizeLimit=nbtTag.getDouble("packetLimit");

	checkLoss(insulatedCable);

	super.readFromNBT(nbtTag);
}

//Fixed by Whov
@Override
public Packet getDescriptionPacket() {
	Packet packet = super.getDescriptionPacket();
    	NBTTagCompound nbtTag = packet != null ? ((S35PacketUpdateTileEntity)packet).func_148857_g() : new NBTTagCompound();
        writeToNBT(nbtTag);
	this.writeToNBT(nbtTag);
	//TODO: Get this damn working!
	return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, nbtTag);
}
//Fixed by Whov
@Override
public void onDataPacket(NetworkManager networkManager, S35PacketUpdateTileEntity packet) {
	super.onDataPacket(networkManager, packet);
	readFromNBT(packet.func_148857_g());
}

@Override
public void updateEntity() {
	if(!internalBuffer.isEmpty())
	{
		MFPacket packet = internalBuffer.remove();
		boolean result=false;
		byte  direction;
		for(int i=0; i<59;i++)
		{
			int posNeg = ((int)(Math.random()*%2==0)?1:-1;
			double randXvel=Math.random()*(2*posNeg);
			double randYvel=Math.random()*(2*posNeg);
			double randZvel=Math.random()*(2*posNeg);
			this.worldObj.spawnParticle("magicCrit", xCoord, yCoord, zCoord, randXvel, randYvel, randZvel);
		}

		switch(packet.getType())
		{
		case RESPOND:
			direction = packet.getOrigin().peek();
			result = (direction!=-1);
			result = pushPacket(packet);
			break;
		default:
			direction = packet.getOrigin().peek();
			packet.getOrigin().add(randDir(direction).toByte());
			result=pushPacket(packet);
			break;
		}
	}
	super.updateEntity();
}

private I_PipeDirection randDir(byte initDirection) {
	I_PipeDirection origin = new PipeDirection(initDirection);
	origin.invert();
	I_PipeDirection newDirection = origin;
	int attempt = 0;
	while (!connections.isEmpty()&&attempt<26&&newDirection.equals(origin))
	{
		attempt++;
		int randNum=(int)(Math.random()*connections.size());
		newDirection  = connections.get(randNum);
	}
	return newDirection;
}

@Override
public boolean checkConnections()
{
	boolean result=false;
	int x,y,z,i=0;
	for(y=-1;y<2;y++)
	{
		//System.out.println("Y Level: "+y);
		for(x=-1;x<2;x++)
		{
			//System.out.println("X Position: "+x);
			for(z=-1;z<2;z++)
			{
				//System.out.println("Z Position: "+z);
				i++;
				Block target = worldObj.getBlock(xCoord+x, yCoord+y, zCoord+z);
				//System.out.print("Test["+i+"] Checking block at ["+(xCoord+x)+","+(yCoord+y)+","+(zCoord+z)+"]");
				if(target.hasTileEntity(target.getDamageValue(worldObj, xCoord+x, yCoord+y, zCoord+z))&&MFHelper.checkConnectable(worldObj.getTileEntity(xCoord+x, yCoord+y, zCoord+z)))
				{
						//System.out.print(" - Valid!");
						boolean twoWay = (worldObj.getTileEntity(xCoord+x, yCoord+y, zCoord+z))instanceof I_MFCable;
						formConnection(twoWay, x,y,z);

				}
				//System.out.print('\n');
			}
		}
		//System.out.println("=================================================================");
	}


	return result;
}

@Override
public synchronized void formConnection(boolean twoWay, int x, int y, int z) {
	if(!(x==0&&y==0&&z==0))
	{
		connections.add(new PipeDirection(x, y, z));
		if (twoWay)
		{
			((I_MFCable)(worldObj.getTileEntity(xCoord+x, yCoord+y, zCoord+z))).formConnection(false, -x, -y, -z);

			worldObj.markBlockForUpdate(xCoord+x, yCoord+y, zCoord+z);
		}
		//System.out.println("connection formed");
		worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
	}
}

@Override
public synchronized void breakConnection(boolean twoWay, int x, int y, int z) {
	I_PipeDirection targetConnector = new PipeDirection(x,y,z);
	if(connections.contains(targetConnector))
	{
		System.out.println("Connector found...");
		System.out.println("Remove operation was "+(connections.remove(targetConnector)?"":"un")+"successful.");
	}
	if (twoWay&&(worldObj.getTileEntity(xCoord+x, yCoord+y, zCoord+z))instanceof I_MFCable)
	{
	I_MFCable targetTile = (I_MFCable)worldObj.getTileEntity(xCoord+x, yCoord+y, zCoord+z);
	targetTile.breakConnection(false,-x, -y, -z);
	worldObj.markBlockForUpdate(xCoord+x, yCoord+y, zCoord+z);
	}
	worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}

@Override
public boolean pushPacket(MFPacket packet)
{
	boolean result= false;
	if(packet.getType()==E_MFPacketType.RESPOND&&packet.getBuffer()<=0)
	{
		packet=null;
	}
	if(packet!=null&&packet.getOrigin().size()<=distLimit);
	{

	byte direction = packet.getOrigin().peek();
	if(packet.getType()==E_MFPacketType.RESPOND)
		packet.getOrigin().pop();


	int[]origin = {xCoord,yCoord,zCoord};
	int[] target = new PipeDirection(direction).getTarget();
	for(int i=0;i<3;i++)
	{
		target[i]+=origin[i];
	}
	result = this.worldObj.getBlock(target[0], target[1], target[2]).hasTileEntity(0);
	if(result)
		result=this.worldObj.getTileEntity(target[0], target[1], target[2])instanceof I_MFSink;
	if(result)
		result=((I_MFSink)this.worldObj.getTileEntity(target[0], target[1], target[2])).takePacket(packet);
	if(!result)
		powerBleed(packet.getBuffer());
	}
	return result;
}

@Override
public boolean canUpdate()
{
	return true;
}

@Override
public double flowLimit() {
	return packetSizeLimit;
}

@Override
public void powerBleed(double excess) {
	//add power bleed to chunk atmosphere -> own effects + taint if Thaumcraft installed
	if(excess>0)
		System.err.println(""+excess+" MF bled off into atmosphere!\n");

}

@Override
public double getPacketLimit() {
	return packetSizeLimit;
}

@Override
public boolean isInsulated() {
	return insulatedCable;
}

@Override
public boolean isBridged() {
	return bridgeConnections;
}

@Override
public boolean canDeBridge() {
	return insulatedCable;
}

@Override
public List<I_PipeDirection> getConnections() {
	System.out.println("Getting "+(worldObj.isRemote?"Client":"Server")+" connections");
	return connections;
}

public String toJSON() {
	String result = "\n{";
	result+=("\n\t\"tileX\":\""+xCoord+"\",");
	result+=("\n\t\"tileY\":\""+yCoord+"\",");
	result+=("\n\t\"tileZ\":\""+zCoord+"\",");
	result+=("\n\t\"connections\":[\n");
	for (I_PipeDirection pipe : connections) {
		result+=(pipe.toJSON()+",\n");
	}
	result+="]";
	result+="\n}\n";

	return result;
}

@Override
public void breakAllConnections() {
	int conNum=connections.size();
	for (int i= 0; i<conNum;i++) {
		int[] target = connections.get(0).getTarget();
		breakConnection(true, target[0], target[1], target[2]);
	}

}

}

Link to comment
Share on other sites

In your getDescriptionPacket method, your writing twice to NBT. I don't know if that causes the issue, but you might want to fix it.

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

Cheers for pointing that out Lars, I've cleaned that up and I'm wondering if I can force the client side to resync in any other way...

I'll do some more research over the weekend. Cheers again to everyone for all the help and suggestions so far though! (these forums actually help keep me motivated and ambitious)

Link to comment
Share on other sites

Actually, I got it wrong. The server overrides the client. Always. Unless, before that happens, you send that packet using those 2 methods to update the server before it can override the client. If the pipes are wrong in the client, they are either wrong in the server too or the custom renderer is doing something wrong (maybe using old data saved in a field instead of grabbing new one each tick? That would not be really good practice anyway, at least if it's just a intArray).

Check out my blog!

http://www.whov.altervista.org

Link to comment
Share on other sites

Currently the server is keeping the correct connections data and it's the client that's out of sync, I'm shunting all the connection making/breaking/checking code out of the tile entities now and into static methods in the MFHelper api class. Partly to centralize control so that one fix works for all, partly so that I'm not duplicating whole methods for each TE. I'll keep you guys posted if I manage to solve it or not. Cheers again to everyone for the suggestions, help and support!

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.

×
×
  • Create New...

Important Information

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