Further changes in data synchronization.
ClassMapping now supports more advanced behavior, in particlar cases where the destination object do not exist. It has now a much more comprehensive documentation. TileNetworkData has been renamed NetworkData, as it's used for more than just tile synchronization. Some additional markers have been placed on the blueprints to make progress and identify which areas still need support.
This commit is contained in:
parent
17ed47d2a2
commit
ce215587a8
15 changed files with 156 additions and 73 deletions
|
@ -15,7 +15,7 @@ import buildcraft.builders.blueprints.BlueprintDatabase;
|
|||
import buildcraft.core.Box;
|
||||
import buildcraft.core.TileBuildCraft;
|
||||
import buildcraft.core.network.PacketUpdate;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.core.utils.Utils;
|
||||
import java.io.IOException;
|
||||
|
@ -29,12 +29,12 @@ import net.minecraftforge.common.ForgeDirection;
|
|||
|
||||
public class TileArchitect extends TileBuildCraft implements IInventory {
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
Box box = new Box();
|
||||
private ItemStack items[] = new ItemStack[2];
|
||||
private boolean isComputing = false;
|
||||
public int computingTime = 0;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
String name = "";
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,7 +10,7 @@ import buildcraft.core.network.RPC;
|
|||
import buildcraft.core.network.RPCHandler;
|
||||
import buildcraft.core.network.RPCMessageInfo;
|
||||
import buildcraft.core.network.RPCSide;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.core.utils.Utils;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import buildcraft.core.inventory.InvUtils;
|
|||
import buildcraft.core.inventory.InventoryMapper;
|
||||
import buildcraft.core.inventory.SimpleInventory;
|
||||
import buildcraft.core.network.PacketUpdate;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import java.io.IOException;
|
||||
import java.util.ListIterator;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
@ -37,7 +37,7 @@ import static net.minecraftforge.common.ForgeDirection.*;
|
|||
public class TileBuilder extends TileBuildCraft implements IBuilderInventory, IPowerReceptor, IMachine {
|
||||
|
||||
private static final int SLOT_BLUEPRINT = 0;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
Box box = new Box();
|
||||
private PowerHandler powerHandler;
|
||||
private EntityRobot builderRobot;
|
||||
|
|
|
@ -16,7 +16,7 @@ import buildcraft.api.core.Position;
|
|||
import buildcraft.core.EntityBlock;
|
||||
import buildcraft.core.TileBuildCraft;
|
||||
import buildcraft.core.network.PacketUpdate;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.core.utils.Utils;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
@ -28,7 +28,7 @@ public class TileMarker extends TileBuildCraft implements IAreaProvider {
|
|||
|
||||
public static class TileWrapper {
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
int x, y, z;
|
||||
|
||||
public TileWrapper() {
|
||||
|
@ -73,20 +73,20 @@ public class TileMarker extends TileBuildCraft implements IAreaProvider {
|
|||
return vectO.isSet();
|
||||
}
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
TileWrapper vectO = new TileWrapper();
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
TileWrapper[] vect = { new TileWrapper(), new TileWrapper(), new TileWrapper() };
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
int xMin, yMin, zMin, xMax, yMax, zMax;
|
||||
}
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
Origin origin = new Origin();
|
||||
|
||||
private EntityBlock[] lasers;
|
||||
private EntityBlock[] signals;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean showSignals = false;
|
||||
|
||||
public void updateSignals() {
|
||||
|
|
|
@ -5,7 +5,7 @@ import buildcraft.core.BlockIndex;
|
|||
import buildcraft.core.EntityLaser;
|
||||
import buildcraft.core.EntityPowerLaser;
|
||||
import buildcraft.core.network.PacketUpdate;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
@ -20,7 +20,7 @@ public class TilePathMarker extends TileMarker {
|
|||
public EntityLaser lasers[] = new EntityLaser[2];
|
||||
public int x0, y0, z0, x1, y1, z1;
|
||||
public boolean loadLink0 = false, loadLink1 = false;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean tryingToConnect = false;
|
||||
public TilePathMarker links[] = new TilePathMarker[2];
|
||||
public static int searchSize = 64; // TODO: this should be moved to default props
|
||||
|
|
|
@ -10,6 +10,7 @@ package buildcraft.builders.blueprints;
|
|||
import buildcraft.BuildCraftBuilders;
|
||||
import buildcraft.api.builder.BlockHandler;
|
||||
import buildcraft.core.inventory.StackHelper;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.utils.BCLog;
|
||||
import buildcraft.core.utils.NBTUtils;
|
||||
import buildcraft.factory.TileQuarry;
|
||||
|
@ -24,7 +25,6 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
|
||||
/**
|
||||
|
@ -35,11 +35,23 @@ import net.minecraftforge.common.ForgeDirection;
|
|||
* @author Player
|
||||
*/
|
||||
public class Blueprint {
|
||||
private BlueprintMeta meta;
|
||||
|
||||
@NetworkData
|
||||
public BlueprintMeta meta;
|
||||
|
||||
// TODO: may need additional support from the serialization system
|
||||
private final Schematic[][][] schematics;
|
||||
public final int sizeX, sizeY, sizeZ;
|
||||
|
||||
@NetworkData
|
||||
public int sizeX, sizeY, sizeZ;
|
||||
|
||||
@NetworkData
|
||||
public int anchorX, anchorY, anchorZ;
|
||||
|
||||
// TODO: may need additional support from the serialization system
|
||||
public ForgeDirection anchorOrientation = ForgeDirection.NORTH;
|
||||
|
||||
// TODO: may need additional support from the serialization system
|
||||
private List<ItemStack> costs;
|
||||
|
||||
public static Blueprint create(int sizeX, int sizeY, int sizeZ) {
|
||||
|
|
|
@ -4,7 +4,12 @@ import java.security.MessageDigest;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import buildcraft.core.network.NetworkData;
|
||||
|
||||
public final class BlueprintId {
|
||||
@NetworkData
|
||||
public byte[] id;
|
||||
|
||||
public static BlueprintId generate(byte[] data) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
|
@ -22,6 +27,9 @@ public final class BlueprintId {
|
|||
return new BlueprintId(id);
|
||||
}
|
||||
|
||||
public BlueprintId() {
|
||||
}
|
||||
|
||||
private BlueprintId(byte[] id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
@ -59,6 +67,4 @@ public final class BlueprintId {
|
|||
private char toHex(int i) {
|
||||
return (char) (i < 10 ? '0' + i : 'a' - 10 + i);
|
||||
}
|
||||
|
||||
private final byte[] id;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
package buildcraft.builders.blueprints;
|
||||
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public class BlueprintMeta {
|
||||
|
||||
public final String version = "Blueprint-2.0";
|
||||
|
||||
/**
|
||||
* FIXME: The format of id is not completely supported by the serialiser
|
||||
* yet. To improve...
|
||||
*/
|
||||
private BlueprintId id;
|
||||
@NetworkData
|
||||
public BlueprintId id;
|
||||
|
||||
@TileNetworkData
|
||||
@NetworkData
|
||||
public String name;
|
||||
|
||||
@TileNetworkData
|
||||
@NetworkData
|
||||
public String creator;
|
||||
|
||||
public BlueprintMeta() {
|
||||
|
||||
}
|
||||
|
||||
protected BlueprintMeta(BlueprintId id, NBTTagCompound nbt) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import buildcraft.api.core.IAreaProvider;
|
|||
import buildcraft.api.core.IBox;
|
||||
import buildcraft.api.core.LaserKind;
|
||||
import buildcraft.api.core.Position;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.core.utils.Utils;
|
||||
import java.io.DataInputStream;
|
||||
|
@ -24,9 +24,9 @@ import net.minecraft.world.World;
|
|||
|
||||
public class Box implements IBox {
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
int xMin, yMin, zMin, xMax, yMax, zMax;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean initialized;
|
||||
private EntityBlock lasers[];
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ public class ClassMapping {
|
|||
}
|
||||
|
||||
private boolean isSynchronizedField(Field f) {
|
||||
TileNetworkData updateAnnotation = f.getAnnotation(TileNetworkData.class);
|
||||
NetworkData updateAnnotation = f.getAnnotation(NetworkData.class);
|
||||
|
||||
return updateAnnotation != null;
|
||||
}
|
||||
|
@ -291,30 +291,75 @@ public class ClassMapping {
|
|||
data.writeInt(val.length);
|
||||
|
||||
for (int i = 0; i < val.length; ++i) {
|
||||
data.writeUTF(val [i]);
|
||||
if (val [i] == null) {
|
||||
data.writeBoolean(false);
|
||||
} else {
|
||||
data.writeBoolean(true);
|
||||
data.writeUTF(val [i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassMapping c : objectArrayFields) {
|
||||
TileNetworkData updateAnnotation = c.field.getAnnotation(TileNetworkData.class);
|
||||
NetworkData updateAnnotation = c.field.getAnnotation(NetworkData.class);
|
||||
|
||||
Object[] cpts = (Object[]) c.field.get(obj);
|
||||
|
||||
for (int i = 0; i < cpts.length; ++i)
|
||||
if (cpts[i] == null) {
|
||||
data.writeBoolean(false);
|
||||
} else {
|
||||
data.writeBoolean(true);
|
||||
data.writeInt(cpts.length);
|
||||
c.setData(cpts[i], data);
|
||||
}
|
||||
if (cpts == null) {
|
||||
data.writeBoolean(false);
|
||||
} else {
|
||||
data.writeBoolean(true);
|
||||
data.writeInt(cpts.length);
|
||||
|
||||
for (int i = 0; i < cpts.length; ++i)
|
||||
if (cpts[i] == null) {
|
||||
data.writeBoolean(false);
|
||||
} else {
|
||||
data.writeBoolean(true);
|
||||
c.setData(cpts[i], data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class will update data in an object from a stream. Public data
|
||||
* market #NetworkData will get synchronized. The following rules will
|
||||
* apply:
|
||||
*
|
||||
* In the following description, we consider strings as primitive objects.
|
||||
*
|
||||
* Market primitives data will be directly updated on the destination
|
||||
* object after the value of the source object
|
||||
*
|
||||
* Market primitive arrays will be re-created in the destination object
|
||||
* after the primitive array of the source object. This means that array
|
||||
* references are not preserved by the proccess. TODO if an array is null
|
||||
* in the source array and not in the destination one, it will be turned to
|
||||
* null.
|
||||
*
|
||||
* Market object will be synchronized - that it we do not create new
|
||||
* instances in the destination object if they are already there but rather
|
||||
* recursively synchronize values. TODO if destination is null and not
|
||||
* source, the destination will get the instance created. If destination is
|
||||
* not null and source is, the destination will get truned to null.
|
||||
*
|
||||
* Market object arrays will be synchronized - not re-created. TODO if if
|
||||
* destination is null and not source, the destination will get the instance
|
||||
* created. If destination is not null and source is, the destination will
|
||||
* get turned to null. The same behavior applies to the contents of the
|
||||
* array. Trying to synchronize two arrays of different size is an error
|
||||
* and will lead to an exception - so if the array needs to change on the
|
||||
* destination it needs to be set to null first.
|
||||
*
|
||||
* WARNING - class instantiation will be done after the field type, not
|
||||
* the actual type used in serialization. Generally speaking, this system
|
||||
* is not robust to polymorphism
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void updateFromData(Object obj, DataInputStream data) throws IllegalArgumentException,
|
||||
IllegalAccessException, IOException {
|
||||
IllegalAccessException, IOException, InstantiationException {
|
||||
|
||||
for (Field f : shortFields) {
|
||||
f.setShort(obj, data.readShort());
|
||||
|
@ -343,16 +388,21 @@ public class ClassMapping {
|
|||
for (Field f : stringFields) {
|
||||
if (data.readBoolean()) {
|
||||
f.set(obj, data.readUTF());
|
||||
} else {
|
||||
f.set(obj, null);
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassMapping c : objectFields) {
|
||||
boolean isNull = data.readBoolean();
|
||||
if (data.readBoolean()) {
|
||||
if (c.field.get(obj) == null) {
|
||||
c.field.set
|
||||
(obj, c.field.getDeclaringClass().newInstance());
|
||||
}
|
||||
|
||||
if (!isNull) {
|
||||
// WARNING! Because we consider the object to exist already,
|
||||
// we perform the following. What if it's not the case?
|
||||
c.updateFromData(c.field.get(obj), data);
|
||||
} else {
|
||||
c.updateFromData(c.field.get(obj), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,7 +483,11 @@ public class ClassMapping {
|
|||
String [] tmp = new String [length];
|
||||
|
||||
for (int i = 0; i < tmp.length; ++i) {
|
||||
tmp [i] = data.readUTF();
|
||||
if (data.readBoolean()) {
|
||||
tmp [i] = data.readUTF();
|
||||
} else {
|
||||
tmp [i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
f.set(obj, tmp);
|
||||
|
@ -445,14 +499,29 @@ public class ClassMapping {
|
|||
for (ClassMapping c : objectArrayFields) {
|
||||
Object[] cpts = (Object[]) c.field.get(obj);
|
||||
|
||||
for (int i = 0; i < cpts.length; ++i) {
|
||||
boolean isNull = data.readBoolean();
|
||||
if (data.readBoolean()) {
|
||||
int serializedSize = data.readInt();
|
||||
|
||||
if (!isNull) {
|
||||
// WARNING! Because we consider the object to exist already,
|
||||
// we perform the following. What if it's not the case?
|
||||
c.updateFromData(cpts[i], data);
|
||||
if (serializedSize != cpts.length) {
|
||||
throw new IOException
|
||||
("Expected size doesn't match serialized size on object array");
|
||||
}
|
||||
|
||||
for (int i = 0; i < cpts.length; ++i) {
|
||||
boolean isNull = data.readBoolean();
|
||||
|
||||
if (!isNull) {
|
||||
if (cpts [i] == null) {
|
||||
cpts [i] = c.field.getDeclaringClass().getComponentType().newInstance();
|
||||
}
|
||||
|
||||
c.updateFromData(cpts[i], data);
|
||||
} else {
|
||||
cpts [i] = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c.field.set(obj, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@ import java.lang.annotation.RetentionPolicy;
|
|||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
//FIXME: Given the usage of this in RPCs, this should be renamed, e.g.
|
||||
//NetworkData
|
||||
public @interface TileNetworkData {
|
||||
public @interface NetworkData {
|
||||
|
||||
}
|
|
@ -29,7 +29,7 @@ import buildcraft.api.transport.IPipeTile.PipeType;
|
|||
import buildcraft.core.DefaultProps;
|
||||
import buildcraft.core.TileBuffer;
|
||||
import buildcraft.core.TileBuildCraft;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.energy.gui.ContainerEngine;
|
||||
|
||||
|
@ -58,11 +58,11 @@ public abstract class TileEngine extends TileBuildCraft implements IPowerRecepto
|
|||
public double energy;
|
||||
public float heat = MIN_HEAT;
|
||||
//
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
EnergyStage energyStage = EnergyStage.BLUE;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
ForgeDirection orientation = ForgeDirection.UP;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean isPumping = false; // Used for SMP synch
|
||||
|
||||
public TileEngine() {
|
||||
|
|
|
@ -27,7 +27,7 @@ import buildcraft.core.IBuilderInventory;
|
|||
import buildcraft.core.IMachine;
|
||||
import buildcraft.core.TileBuildCraft;
|
||||
import buildcraft.core.network.PacketUpdate;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.core.utils.BlockUtil;
|
||||
import buildcraft.core.utils.Utils;
|
||||
|
@ -54,17 +54,17 @@ import net.minecraftforge.common.ForgeDirection;
|
|||
|
||||
public class TileQuarry extends TileBuildCraft implements IMachine, IPowerReceptor, IBuilderInventory {
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
Box box = new Box();
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean inProcess = false;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
int targetX, targetY, targetZ;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
double headPosX, headPosY, headPosZ;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
double speed = 0.03;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean builderDone = false;
|
||||
public EntityRobot builder;
|
||||
private BlueprintBuilder blueprintBuilder;
|
||||
|
@ -122,7 +122,7 @@ public class TileQuarry extends TileBuildCraft implements IMachine, IPowerRecept
|
|||
private boolean movingVertically;
|
||||
private double headTrajectory;
|
||||
private Ticket chunkTicket;
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
boolean isAlive;
|
||||
public EntityPlayer placedBy;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import buildcraft.api.power.PowerHandler.PowerReceiver;
|
|||
import buildcraft.api.power.PowerHandler.Type;
|
||||
import buildcraft.api.transport.IPipeTile;
|
||||
import buildcraft.api.transport.PipeManager;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.transport.Pipe;
|
||||
import buildcraft.transport.PipeIconProvider;
|
||||
import buildcraft.transport.PipeTransportFluids;
|
||||
|
@ -31,7 +31,7 @@ import net.minecraftforge.fluids.IFluidHandler;
|
|||
|
||||
public class PipeFluidsWood extends Pipe<PipeTransportFluids> implements IPowerReceptor {
|
||||
|
||||
public @TileNetworkData
|
||||
public @NetworkData
|
||||
int liquidToExtract;
|
||||
private PowerHandler powerHandler;
|
||||
protected int standardIconIndex = PipeIconProvider.TYPE.PipeFluidsWood_Standard.ordinal();
|
||||
|
|
|
@ -11,7 +11,7 @@ import buildcraft.BuildCraftTransport;
|
|||
import buildcraft.api.core.IIconProvider;
|
||||
import buildcraft.api.gates.IAction;
|
||||
import buildcraft.api.tools.IToolWrench;
|
||||
import buildcraft.core.network.TileNetworkData;
|
||||
import buildcraft.core.network.NetworkData;
|
||||
import buildcraft.core.utils.EnumColor;
|
||||
import buildcraft.transport.Pipe;
|
||||
import buildcraft.transport.PipeIconProvider;
|
||||
|
@ -38,7 +38,7 @@ public class PipeItemsDaizuli extends Pipe<PipeTransportItems> {
|
|||
|
||||
private int standardIconIndex = PipeIconProvider.TYPE.PipeItemsDaizuli_Black.ordinal();
|
||||
private int solidIconIndex = PipeIconProvider.TYPE.PipeAllDaizuli_Solid.ordinal();
|
||||
@TileNetworkData
|
||||
@NetworkData
|
||||
private int color = EnumColor.BLACK.ordinal();
|
||||
private PipeLogicIron logic = new PipeLogicIron(this) {
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue