initial set of experiments with RPC implementation
This commit is contained in:
parent
8ee5270145
commit
b1f5a4b96a
6 changed files with 348 additions and 0 deletions
36
common/buildcraft/core/BlockPingPong.java
Executable file
36
common/buildcraft/core/BlockPingPong.java
Executable file
|
@ -0,0 +1,36 @@
|
|||
package buildcraft.core;
|
||||
|
||||
import buildcraft.factory.TileRefinery;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.renderer.texture.IconRegister;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BlockPingPong extends BlockBuildCraft {
|
||||
|
||||
public static final Random rand = new Random();
|
||||
|
||||
public BlockPingPong(int id) {
|
||||
super(id, Material.rock);
|
||||
setBlockUnbreakable();
|
||||
setResistance(6000000.0F);
|
||||
setStepSound(soundStoneFootstep);
|
||||
disableStats();
|
||||
setTickRandomly(true);
|
||||
setCreativeTab(CreativeTabBuildCraft.MACHINES.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World var1) {
|
||||
return new TilePingPong();
|
||||
}
|
||||
}
|
42
common/buildcraft/core/TilePingPong.java
Executable file
42
common/buildcraft/core/TilePingPong.java
Executable file
|
@ -0,0 +1,42 @@
|
|||
package buildcraft.core;
|
||||
|
||||
import buildcraft.api.core.SafeTimeTracker;
|
||||
import buildcraft.core.network.RPC;
|
||||
import buildcraft.core.network.RPCHandler;
|
||||
import buildcraft.core.network.RPCMessageInfo;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public class TilePingPong extends TileBuildCraft {
|
||||
|
||||
@RPC
|
||||
public void ping (int time, RPCMessageInfo info) {
|
||||
System.out.println ("ping " + time);
|
||||
|
||||
RPCHandler.rpcPlayer(this, "pong", info.sender, time);
|
||||
}
|
||||
|
||||
@RPC
|
||||
public void pong (int time) {
|
||||
System.out.println ("pong " + time);
|
||||
}
|
||||
|
||||
SafeTimeTracker tracker;
|
||||
|
||||
@Override
|
||||
public void updateEntity() {
|
||||
super.updateEntity();
|
||||
|
||||
if (worldObj.isRemote) {
|
||||
if (tracker == null) {
|
||||
tracker = new SafeTimeTracker();
|
||||
tracker.markTimeIfDelay(worldObj, 50);
|
||||
}
|
||||
|
||||
if (tracker.markTimeIfDelay(worldObj, 50)) {
|
||||
RPCHandler.rpcServer(this, "ping", (int) worldObj.getWorldTime());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
52
common/buildcraft/core/network/PacketRPC.java
Executable file
52
common/buildcraft/core/network/PacketRPC.java
Executable file
|
@ -0,0 +1,52 @@
|
|||
package buildcraft.core.network;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
import org.bouncycastle.crypto.util.Pack;
|
||||
|
||||
import cpw.mods.fml.common.network.Player;
|
||||
|
||||
public class PacketRPC extends BuildCraftPacket {
|
||||
|
||||
public TileEntity tile;
|
||||
|
||||
byte [] contents;
|
||||
|
||||
public EntityPlayer sender;
|
||||
|
||||
public PacketRPC () {
|
||||
|
||||
}
|
||||
|
||||
public PacketRPC (byte [] bytes) {
|
||||
contents = bytes;
|
||||
}
|
||||
|
||||
public void setTile (TileEntity aTile) {
|
||||
tile = aTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getID() {
|
||||
return PacketIds.RPC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readData(DataInputStream data) throws IOException {
|
||||
RPCMessageInfo info = new RPCMessageInfo();
|
||||
info.sender = sender;
|
||||
|
||||
RPCHandler.receiveRPC(tile, info, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(DataOutputStream data) throws IOException {
|
||||
data.write(contents);
|
||||
}
|
||||
|
||||
}
|
11
common/buildcraft/core/network/RPC.java
Executable file
11
common/buildcraft/core/network/RPC.java
Executable file
|
@ -0,0 +1,11 @@
|
|||
package buildcraft.core.network;
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface RPC {
|
||||
|
||||
}
|
200
common/buildcraft/core/network/RPCHandler.java
Executable file
200
common/buildcraft/core/network/RPCHandler.java
Executable file
|
@ -0,0 +1,200 @@
|
|||
package buildcraft.core.network;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
import cpw.mods.fml.common.network.Player;
|
||||
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.MinecraftForge;
|
||||
|
||||
/**
|
||||
* This is a first implementation of a RPC connector, using the regular tile
|
||||
* synchronization layers as a communication protocol. As a result, these
|
||||
* RPCs must be sent and received by a tile entity.
|
||||
*/
|
||||
public class RPCHandler {
|
||||
|
||||
private static Map <String, RPCHandler> handlers =
|
||||
new TreeMap <String, RPCHandler> ();
|
||||
|
||||
private Map<String, Integer> methodsMap = new TreeMap<String, Integer>();
|
||||
private Method [] methods;
|
||||
|
||||
public RPCHandler (Class c) {
|
||||
methods = c.getMethods();
|
||||
|
||||
Arrays.sort(methods, new Comparator <Method> () {
|
||||
@Override
|
||||
public int compare(Method o1, Method o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
|
||||
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]);
|
||||
|
||||
Class formals [] = methods [i].getParameterTypes();
|
||||
|
||||
for (int j = 0; i < formals.length; ++i) {
|
||||
if (formals [j].equals(int.class)) {
|
||||
// accepted
|
||||
} else if (formals [j].equals(String.class)) {
|
||||
// accepted
|
||||
} else if (formals [j].equals(RPCMessageInfo.class)) {
|
||||
// accepted
|
||||
// FIXME: only if last one
|
||||
} else {
|
||||
throw new RuntimeException
|
||||
("parameter type " + formals [j].getName() + " not supported in RPC.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
methods = rpcMethods.toArray(new Method [rpcMethods.size()]);
|
||||
}
|
||||
|
||||
public static void rpcServer (TileEntity tile, String method, Object ... actuals) {
|
||||
if (!handlers.containsKey(tile.getClass().getName())) {
|
||||
handlers.put (tile.getClass().getName(), new RPCHandler (tile.getClass()));
|
||||
}
|
||||
|
||||
PacketRPC packet = handlers.get (tile.getClass().getName()).createRCPPacket(tile, method, actuals);
|
||||
|
||||
if (packet != null) {
|
||||
CoreProxy.proxy.sendToServer(packet.getPacket());
|
||||
}
|
||||
}
|
||||
|
||||
public static void rpcPlayer (TileEntity tile, String method, EntityPlayer player, Object ... actuals) {
|
||||
if (!handlers.containsKey(tile.getClass().getName())) {
|
||||
handlers.put (tile.getClass().getName(), new RPCHandler (tile.getClass()));
|
||||
}
|
||||
|
||||
PacketRPC packet = handlers.get (tile.getClass().getName()).createRCPPacket(tile, method, actuals);
|
||||
|
||||
if (packet != null) {
|
||||
CoreProxy.proxy.sendToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
public static void receiveRPC (TileEntity tile, RPCMessageInfo info, DataInputStream data) {
|
||||
if (!handlers.containsKey(tile.getClass().getName())) {
|
||||
handlers.put (tile.getClass().getName(), new RPCHandler (tile.getClass()));
|
||||
}
|
||||
|
||||
handlers.get (tile.getClass().getName()).internalRpcReceive(tile, info, data);
|
||||
}
|
||||
|
||||
private PacketRPC createRCPPacket (TileEntity tile, String method, Object ... actuals) {
|
||||
if (!methodsMap.containsKey(method)) {
|
||||
throw new RuntimeException(method + " is not a callable method of " + getClass().getName());
|
||||
}
|
||||
|
||||
int methodIndex = methodsMap.get(method);
|
||||
Method m = methods [methodIndex];
|
||||
Class formals [] = m.getParameterTypes();
|
||||
|
||||
boolean hasSpecialMessageInfo = formals.length > 0 && formals [formals.length - 1].equals(RPCMessageInfo.class);
|
||||
|
||||
int expectedParameters = hasSpecialMessageInfo ? 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);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
DataOutputStream data = new DataOutputStream(bytes);
|
||||
|
||||
try {
|
||||
data.writeInt(tile.xCoord);
|
||||
data.writeInt(tile.yCoord);
|
||||
data.writeInt(tile.zCoord);
|
||||
|
||||
data.writeShort(methodIndex);
|
||||
|
||||
for (int i = 0; i < actuals.length; ++i) {
|
||||
if (formals [i].equals(int.class)) {
|
||||
data.writeInt((Integer) actuals [i]);
|
||||
} else if (formals [i].equals(String.class)) {
|
||||
data.writeUTF((String) actuals [i]);
|
||||
}
|
||||
}
|
||||
|
||||
data.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new PacketRPC(bytes.toByteArray());
|
||||
}
|
||||
|
||||
private void internalRpcReceive (TileEntity tile, RPCMessageInfo info, DataInputStream data) {
|
||||
try {
|
||||
short methodIndex = data.readShort();
|
||||
|
||||
Method m = methods [methodIndex];
|
||||
Class formals [] = m.getParameterTypes();
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSpecialMessageInfo) {
|
||||
actuals [actuals.length - 1] = info;
|
||||
}
|
||||
|
||||
m.invoke(tile, actuals);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
7
common/buildcraft/core/network/RPCMessageInfo.java
Executable file
7
common/buildcraft/core/network/RPCMessageInfo.java
Executable file
|
@ -0,0 +1,7 @@
|
|||
package buildcraft.core.network;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
public class RPCMessageInfo {
|
||||
public EntityPlayer sender;
|
||||
}
|
Loading…
Reference in a new issue