Jump to content

Recommended Posts

Posted

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

Posted

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.

Posted

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

Posted

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

}

}

Posted

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/

Posted

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)

Posted

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

Posted

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!

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • When I first heard about Bitcoin back in 2018, I was skeptical. The idea of a decentralized, digital currency seemed too good to be true. But I was intrigued as I learned more about the technology behind it and its potential. I started small, investing just a few hundred dollars, dipping my toes into the cryptocurrency waters. At first, it was exhilarating to watch the value of my investment grow exponentially. I felt like I was part of the future, an early adopter of this revolutionary new asset. But that euphoria was short-lived. One day, I logged into my digital wallet only to find it empty - my Bitcoin had vanished without a trace. It turned out that the online exchange I had trusted had been hacked, and my funds were stolen. I was devastated, both financially and emotionally. All the potential I had seen in Bitcoin was tainted by the harsh reality that with decentralization came a lack of regulation and oversight. My hard-earned money was gone, lost to the ether of the digital world. This experience taught me a painful lesson about the price of trust in the uncharted territory of cryptocurrency. While the technology holds incredible promise, the risks can be catastrophic if you don't approach it with extreme caution. My Bitcoin investment gamble had failed, and I was left to pick up the pieces, wiser but poorer for having placed my faith in the wrong hands. My sincere appreciation goes to MUYERN TRUST HACKER. You are my hero in recovering my lost funds. Send a direct m a i l ( muyerntrusted ( @ ) mail-me ( . )c o m ) or message on whats app : + 1 ( 4-4-0 ) ( 3 -3 -5 ) ( 0-2-0-5 )
    • You could try posting a log (if there is no log at all, it may be the launcher you are using, the FAQ may have info on how to enable the log) as described in the FAQ, however this will probably need to be reported to/remedied by the mod author.
    • So me and a couple of friends are playing with a shitpost mod pack and one of the mods in the pack is corail tombstone and for some reason there is a problem with it, where on death to fire the player will get kicked out of the server and the tombstone will not spawn basically deleting an entire inventory, it doesn't matter what type of fire it is, whether it's from vanilla fire/lava, or from modded fire like ice&fire/lycanites and it's common enough to where everyone on the server has experienced at least once or twice and it doesn't give any crash log. a solution to this would be much appreciated thank you!
    • It is 1.12.2 - I have no idea if there is a 1.12 pack
  • Topics

×
×
  • Create New...

Important Information

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