package openmods.network.rpc;
import com.google.common.base.Preconditions;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import java.io.DataOutput;
import java.lang.reflect.Method;
import java.util.List;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.INetHandler;
import openmods.OpenMods;
import openmods.utils.ByteUtils;
@Sharable
public class RpcCallCodec extends MessageToMessageCodec<FMLProxyPacket, RpcCall> {
private final TargetWrapperRegistry targetRegistry;
private final MethodIdRegistry methodRegistry;
public RpcCallCodec(TargetWrapperRegistry targetRegistry, MethodIdRegistry methodRegistry) {
this.targetRegistry = targetRegistry;
this.methodRegistry = methodRegistry;
}
@Override
protected void encode(ChannelHandlerContext ctx, RpcCall call, List<Object> out) throws Exception {
ByteBuf buf = Unpooled.buffer();
DataOutput output = new ByteBufOutputStream(buf);
{
final IRpcTarget targetWrapper = call.target;
int targetId = targetRegistry.getWrapperId(targetWrapper.getClass());
ByteUtils.writeVLI(output, targetId);
targetWrapper.writeToStream(output);
}
{
final Method method = call.method;
int methodId = methodRegistry.methodToId(method);
ByteUtils.writeVLI(output, methodId);
MethodParamsCodec paramsCodec = MethodParamsCodec.create(method);
paramsCodec.writeArgs(output, call.args);
}
FMLProxyPacket packet = new FMLProxyPacket(buf.copy(), RpcCallDispatcher.CHANNEL_NAME);
out.add(packet);
}
@Override
protected void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List<Object> out) throws Exception {
ByteBufInputStream input = new ByteBufInputStream(msg.payload());
final IRpcTarget target;
final Method method;
final Object[] args;
{
int targetId = ByteUtils.readVLI(input);
target = targetRegistry.createWrapperFromId(targetId);
EntityPlayer player = getPlayer(msg);
target.readFromStreamStream(player, input);
}
{
int methodId = ByteUtils.readVLI(input);
method = methodRegistry.idToMethod(methodId);
MethodParamsCodec paramsCodec = MethodParamsCodec.create(method);
args = paramsCodec.readArgs(input);
}
int bufferJunkSize = input.available();
Preconditions.checkState(bufferJunkSize == 0, "%s junk bytes left in buffer, method = %s", bufferJunkSize, method);
out.add(new RpcCall(target, method, args));
}
protected EntityPlayer getPlayer(FMLProxyPacket msg) {
INetHandler handler = msg.handler();
EntityPlayer player = OpenMods.proxy.getPlayerFromHandler(handler);
Preconditions.checkNotNull(player, "Can't get player from handler %s", handler);
return player;
}
}