Improved RPC parameter support - now classes can be serialized through the
same system as tiles, and fields selected through @TileEntityNetwork. Improved the TileLibrary rpc calls to take advantage of this new capability. The RPC world identification has been fixed as well.
This commit is contained in:
parent
1596c5ffc5
commit
17ed47d2a2
5 changed files with 133 additions and 50 deletions
|
@ -114,13 +114,13 @@ public class TileBlueprintLibrary extends TileBuildCraft implements IInventory {
|
|||
BlueprintMeta dummyMeta = new BlueprintMeta ();
|
||||
dummyMeta.name = "Blueprint #" + i;
|
||||
|
||||
RPCHandler.rpcPlayer(this, "receiveBlueprintMeta", info.sender, dummyMeta.name);
|
||||
RPCHandler.rpcPlayer(this, "receiveBlueprintMeta", info.sender, dummyMeta);
|
||||
}
|
||||
}
|
||||
|
||||
@RPC (RPCSide.CLIENT)
|
||||
public void receiveBlueprintMeta (String meta) {
|
||||
currentBlueprint.add(meta);
|
||||
public void receiveBlueprintMeta (BlueprintMeta meta) {
|
||||
currentBlueprint.add(meta.name);
|
||||
}
|
||||
|
||||
public ArrayList<BptBase> getCurrentPage() {
|
||||
|
|
|
@ -5,11 +5,11 @@ import net.minecraft.nbt.NBTTagCompound;
|
|||
|
||||
public class BlueprintMeta {
|
||||
|
||||
@TileNetworkData
|
||||
public final String version = "Blueprint-2.0";
|
||||
|
||||
/**
|
||||
* FIXME: The format of id is not completely supported yet. To improve...
|
||||
* FIXME: The format of id is not completely supported by the serialiser
|
||||
* yet. To improve...
|
||||
*/
|
||||
private BlueprintId id;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
|
@ -65,6 +66,7 @@ public class ClassMapping {
|
|||
private LinkedList<Field> enumFields = new LinkedList<Field>();
|
||||
private LinkedList<ClassMapping> objectFields = new LinkedList<ClassMapping>();
|
||||
|
||||
private LinkedList<Field> byteArrayFields = new LinkedList<Field>();
|
||||
private LinkedList<Field> doubleArrayFields = new LinkedList<Field>();
|
||||
private LinkedList<Field> shortArrayFields = new LinkedList<Field>();
|
||||
private LinkedList<Field> intArrayFields = new LinkedList<Field>();
|
||||
|
@ -76,6 +78,8 @@ public class ClassMapping {
|
|||
|
||||
private Class<? extends Object> clas;
|
||||
|
||||
private static Map <String, ClassMapping> classes = new TreeMap <String, ClassMapping> ();
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public ClassMapping(final Class<? extends Object> c) {
|
||||
clas = c;
|
||||
|
@ -122,7 +126,9 @@ public class ClassMapping {
|
|||
Class fieldClass = (Class) t;
|
||||
Class cptClass = fieldClass.getComponentType();
|
||||
|
||||
if (cptClass.equals(double.class)) {
|
||||
if (cptClass.equals(byte.class)) {
|
||||
byteArrayFields.add(f);
|
||||
} else if (cptClass.equals(double.class)) {
|
||||
doubleArrayFields.add(f);
|
||||
} else if (cptClass.equals(short.class)) {
|
||||
shortArrayFields.add(f);
|
||||
|
@ -182,7 +188,14 @@ public class ClassMapping {
|
|||
}
|
||||
|
||||
for (Field f : stringFields) {
|
||||
data.writeUTF((String) f.get(obj));
|
||||
String s = (String) f.get(obj);
|
||||
|
||||
if (s == null) {
|
||||
data.writeBoolean(false);
|
||||
} else {
|
||||
data.writeBoolean(true);
|
||||
data.writeUTF(s);
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassMapping c : objectFields) {
|
||||
|
@ -196,6 +209,18 @@ public class ClassMapping {
|
|||
}
|
||||
}
|
||||
|
||||
for (Field f : byteArrayFields) {
|
||||
byte [] val = (byte[]) f.get(obj);
|
||||
|
||||
if (val == null) {
|
||||
data.writeBoolean(false);
|
||||
} else {
|
||||
data.writeBoolean(true);
|
||||
data.writeInt(val.length);
|
||||
data.write(val);
|
||||
}
|
||||
}
|
||||
|
||||
for (Field f : doubleArrayFields) {
|
||||
double [] val = (double[]) f.get(obj);
|
||||
|
||||
|
@ -316,7 +341,9 @@ public class ClassMapping {
|
|||
}
|
||||
|
||||
for (Field f : stringFields) {
|
||||
f.set(obj, data.readUTF());
|
||||
if (data.readBoolean()) {
|
||||
f.set(obj, data.readUTF());
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassMapping c : objectFields) {
|
||||
|
@ -329,6 +356,17 @@ public class ClassMapping {
|
|||
}
|
||||
}
|
||||
|
||||
for (Field f : byteArrayFields) {
|
||||
if (data.readBoolean()) {
|
||||
int length = data.readInt();
|
||||
byte[] tmp = new byte [length];
|
||||
data.read(tmp);
|
||||
f.set(obj, tmp);
|
||||
} else {
|
||||
f.set(obj, null);
|
||||
}
|
||||
}
|
||||
|
||||
for (Field f : doubleArrayFields) {
|
||||
if (data.readBoolean()) {
|
||||
int length = data.readInt();
|
||||
|
@ -418,4 +456,12 @@ public class ClassMapping {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassMapping get (Class clas) {
|
||||
if (!classes.containsKey(clas.getCanonicalName())) {
|
||||
classes.put(clas.getCanonicalName(), new ClassMapping(clas));
|
||||
}
|
||||
|
||||
return classes.get(clas.getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import net.minecraft.network.INetworkManager;
|
|||
import net.minecraft.network.packet.Packet250CustomPayload;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import cpw.mods.fml.common.network.IPacketHandler;
|
||||
import cpw.mods.fml.common.network.Player;
|
||||
import cpw.mods.fml.repackage.com.nothome.delta.DebugDiffWriter;
|
||||
|
@ -72,15 +73,30 @@ public class PacketHandler implements IPacketHandler {
|
|||
PacketRPC rpc = new PacketRPC();
|
||||
rpc.sender = (EntityPlayer) player;
|
||||
|
||||
int x = data.readInt();
|
||||
int y = data.readInt();
|
||||
int z = data.readInt();
|
||||
int dimId = data.readShort();
|
||||
World world = null;
|
||||
|
||||
World world = ((EntityPlayer) player).worldObj;
|
||||
TileEntity tile = world.getBlockTileEntity(x, y, z);
|
||||
if (!rpc.sender.worldObj.isRemote) {
|
||||
// if this is a server, then get the world
|
||||
|
||||
world = DimensionManager.getProvider(dimId).worldObj;
|
||||
} else if (rpc.sender.worldObj.provider.dimensionId == dimId) {
|
||||
// if the player is on this world, then synchronize things
|
||||
|
||||
world = rpc.sender.worldObj;
|
||||
}
|
||||
|
||||
if (world != null) {
|
||||
int x = data.readInt();
|
||||
int y = data.readInt();
|
||||
int z = data.readInt();
|
||||
|
||||
TileEntity tile = world.getBlockTileEntity(x, y, z);
|
||||
|
||||
rpc.setTile (tile);
|
||||
rpc.readData(data);
|
||||
}
|
||||
|
||||
rpc.setTile (tile);
|
||||
rpc.readData(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@ import java.util.LinkedList;
|
|||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import buildcraft.core.proxy.CoreProxy;
|
||||
import buildcraft.core.proxy.CoreProxyClient;
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
|
@ -24,6 +22,7 @@ import net.minecraft.entity.player.EntityPlayer;
|
|||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
/**
|
||||
|
@ -37,12 +36,22 @@ public class RPCHandler {
|
|||
new TreeMap <String, RPCHandler> ();
|
||||
|
||||
private Map<String, Integer> methodsMap = new TreeMap<String, Integer>();
|
||||
private Method [] methods;
|
||||
|
||||
class MethodMapping {
|
||||
Method method;
|
||||
Class [] parameters;
|
||||
ClassMapping [] mappings;
|
||||
boolean hasInfo = false;
|
||||
}
|
||||
|
||||
private MethodMapping [] methods;
|
||||
|
||||
public RPCHandler (Class c) {
|
||||
methods = c.getMethods();
|
||||
Method [] sortedMethods = c.getMethods();
|
||||
|
||||
Arrays.sort(methods, new Comparator <Method> () {
|
||||
LinkedList <MethodMapping> mappings = new LinkedList<MethodMapping>();
|
||||
|
||||
Arrays.sort(sortedMethods, new Comparator <Method> () {
|
||||
@Override
|
||||
public int compare(Method o1, Method o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
|
@ -51,32 +60,33 @@ public class RPCHandler {
|
|||
|
||||
LinkedList <Method> rpcMethods = new LinkedList<Method>();
|
||||
|
||||
for (int i = 0; i < methods.length; ++i) {
|
||||
if (methods [i].getAnnotation (RPC.class) != null) {
|
||||
methodsMap.put(methods [i].getName(), rpcMethods.size());
|
||||
rpcMethods.add(methods [i]);
|
||||
for (int i = 0; i < sortedMethods.length; ++i) {
|
||||
if (sortedMethods [i].getAnnotation (RPC.class) != null) {
|
||||
methodsMap.put(sortedMethods [i].getName(), rpcMethods.size());
|
||||
rpcMethods.add(sortedMethods [i]);
|
||||
|
||||
Class formals [] = methods [i].getParameterTypes();
|
||||
MethodMapping mapping = new MethodMapping();
|
||||
mapping.method = sortedMethods [i];
|
||||
mapping.parameters = sortedMethods [i].getParameterTypes();
|
||||
mapping.mappings = new ClassMapping [mapping.parameters.length];
|
||||
|
||||
for (int j = 0; i < formals.length; ++i) {
|
||||
if (formals [j].equals(int.class)) {
|
||||
for (int j = 0; j < mapping.parameters.length; ++j) {
|
||||
if (mapping.parameters [j].equals(int.class)) {
|
||||
// accepted
|
||||
} else if (formals [j].equals(String.class)) {
|
||||
} else if (mapping.parameters [j].equals(String.class)) {
|
||||
// accepted
|
||||
} else if (formals [j].equals(RPCMessageInfo.class)) {
|
||||
|
||||
// accepted
|
||||
// FIXME: only if last one
|
||||
} else if (mapping.parameters [j].equals(RPCMessageInfo.class)) {
|
||||
mapping.hasInfo = true;
|
||||
} else {
|
||||
// all other will be serialized
|
||||
//throw new RuntimeException
|
||||
//("parameter type " + formals [j].getName() + " not supported in RPC.");
|
||||
mapping.mappings [j] = ClassMapping.get(mapping.parameters [j]);
|
||||
}
|
||||
}
|
||||
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
methods = rpcMethods.toArray(new Method [rpcMethods.size()]);
|
||||
methods = mappings.toArray(new MethodMapping [mappings.size()]);
|
||||
}
|
||||
|
||||
public static void rpcServer (TileEntity tile, String method, Object ... actuals) {
|
||||
|
@ -117,25 +127,26 @@ public class RPCHandler {
|
|||
}
|
||||
|
||||
int methodIndex = methodsMap.get(method);
|
||||
Method m = methods [methodIndex];
|
||||
Class formals [] = m.getParameterTypes();
|
||||
MethodMapping m = methods [methodIndex];
|
||||
Class formals [] = m.parameters;
|
||||
|
||||
boolean hasSpecialMessageInfo = formals.length > 0 && formals [formals.length - 1].equals(RPCMessageInfo.class);
|
||||
|
||||
int expectedParameters = hasSpecialMessageInfo ? formals.length - 1 : formals.length;
|
||||
int expectedParameters = m.hasInfo ? formals.length - 1 : formals.length;
|
||||
|
||||
if (expectedParameters != actuals.length) {
|
||||
// We accept formals + 1 as an argument, in order to support the
|
||||
// special last argument RPCMessageInfo
|
||||
|
||||
throw new RuntimeException(getClass().getName() + "." + method
|
||||
+ " expects " + m.getParameterTypes().length + "parameters, not " + actuals.length);
|
||||
+ " expects " + m.parameters.length + "parameters, not " + actuals.length);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
DataOutputStream data = new DataOutputStream(bytes);
|
||||
|
||||
try {
|
||||
// In order to save space on message, we assuming dimensions ids
|
||||
// small. Maybe worth using a varint instead
|
||||
data.writeShort(tile.worldObj.provider.dimensionId);
|
||||
data.writeInt(tile.xCoord);
|
||||
data.writeInt(tile.yCoord);
|
||||
data.writeInt(tile.zCoord);
|
||||
|
@ -148,13 +159,19 @@ public class RPCHandler {
|
|||
} else if (formals [i].equals(String.class)) {
|
||||
data.writeUTF((String) actuals [i]);
|
||||
} else {
|
||||
//data.write
|
||||
m.mappings [i].setData(actuals [i], data);
|
||||
}
|
||||
}
|
||||
|
||||
data.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new PacketRPC(bytes.toByteArray());
|
||||
|
@ -164,28 +181,29 @@ public class RPCHandler {
|
|||
try {
|
||||
short methodIndex = data.readShort();
|
||||
|
||||
Method m = methods [methodIndex];
|
||||
Class formals [] = m.getParameterTypes();
|
||||
MethodMapping m = methods [methodIndex];
|
||||
Class formals [] = m.parameters;
|
||||
|
||||
Object [] actuals = new Object [formals.length];
|
||||
|
||||
boolean hasSpecialMessageInfo = formals.length > 0 && formals [formals.length - 1].equals(RPCMessageInfo.class);
|
||||
|
||||
int expectedParameters = hasSpecialMessageInfo ? formals.length - 1 : formals.length;
|
||||
int expectedParameters = m.hasInfo ? formals.length - 1 : formals.length;
|
||||
|
||||
for (int i = 0; i < expectedParameters; ++i) {
|
||||
if (formals [i].equals(int.class)) {
|
||||
actuals [i] = data.readInt();
|
||||
} else if (formals [i].equals(String.class)) {
|
||||
actuals [i] = data.readUTF();
|
||||
} else {
|
||||
actuals [i] = formals [i].newInstance();
|
||||
m.mappings [i].updateFromData(actuals [i], data);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSpecialMessageInfo) {
|
||||
if (m.hasInfo) {
|
||||
actuals [actuals.length - 1] = info;
|
||||
}
|
||||
|
||||
m.invoke(tile, actuals);
|
||||
m.method.invoke(tile, actuals);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
|
@ -198,6 +216,9 @@ public class RPCHandler {
|
|||
} catch (InvocationTargetException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InstantiationException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue