package net.glowstone.net.protocol;
import com.flowpowered.networking.Codec;
import com.flowpowered.networking.Message;
import com.flowpowered.networking.MessageHandler;
import com.flowpowered.networking.exception.IllegalOpcodeException;
import com.flowpowered.networking.exception.UnknownPacketException;
import com.flowpowered.networking.protocol.AbstractProtocol;
import com.flowpowered.networking.service.CodecLookupService;
import com.flowpowered.networking.service.HandlerLookupService;
import com.flowpowered.networking.util.ByteBufUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.glowstone.GlowServer;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public abstract class GlowProtocol extends AbstractProtocol {
private final CodecLookupService inboundCodecs;
private final CodecLookupService outboundCodecs;
private final HandlerLookupService handlers;
public GlowProtocol(String name, int highestOpcode) {
super(name);
inboundCodecs = new CodecLookupService(highestOpcode + 1);
outboundCodecs = new CodecLookupService(highestOpcode + 1);
handlers = new HandlerLookupService();
}
protected <M extends Message, C extends Codec<? super M>, H extends MessageHandler<?, ? super M>> void inbound(int opcode, Class<M> message, Class<C> codec, Class<H> handler) {
try {
inboundCodecs.bind(message, codec, opcode);
handlers.bind(message, handler);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
getLogger().error("Error registering inbound " + opcode + " in " + getName(), e);
}
}
protected <M extends Message, C extends Codec<? super M>> void outbound(int opcode, Class<M> message, Class<C> codec) {
try {
outboundCodecs.bind(message, codec, opcode);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
getLogger().error("Error registering outbound " + opcode + " in " + getName(), e);
}
}
@Override
public <M extends Message> MessageHandler<?, M> getMessageHandle(Class<M> clazz) {
MessageHandler<?, M> handler = handlers.find(clazz);
if (handler == null) {
GlowServer.logger.warning("No message handler for: " + clazz.getSimpleName() + " in " + getName());
}
return handler;
}
@Override
@Deprecated
public Codec<?> readHeader(ByteBuf buf) throws UnknownPacketException {
int length = -1;
int opcode = -1;
try {
length = ByteBufUtils.readVarInt(buf);
// mark point before opcode
buf.markReaderIndex();
opcode = ByteBufUtils.readVarInt(buf);
return inboundCodecs.find(opcode);
} catch (IOException e) {
throw new UnknownPacketException("Failed to read packet data (corrupt?)", opcode, length);
} catch (IllegalOpcodeException e) {
// go back to before opcode, so that skipping length doesn't skip too much
buf.resetReaderIndex();
throw new UnknownPacketException("Opcode received is not a registered codec on the server!", opcode, length);
}
}
@Override
public <M extends Message> Codec.CodecRegistration getCodecRegistration(Class<M> clazz) {
Codec.CodecRegistration reg = outboundCodecs.find(clazz);
if (reg == null) {
GlowServer.logger.warning("No codec to write: " + clazz.getSimpleName() + " in " + getName());
}
return reg;
}
@Override
@Deprecated
public ByteBuf writeHeader(ByteBuf out, Codec.CodecRegistration codec, ByteBuf data) {
final ByteBuf opcodeBuffer = Unpooled.buffer(5);
ByteBufUtils.writeVarInt(opcodeBuffer, codec.getOpcode());
ByteBufUtils.writeVarInt(out, opcodeBuffer.readableBytes() + data.readableBytes());
ByteBufUtils.writeVarInt(out, codec.getOpcode());
if (opcodeBuffer.refCnt() > 0) {
opcodeBuffer.release(opcodeBuffer.refCnt());
}
return out;
}
public Codec<?> newReadHeader(ByteBuf in) throws IOException, IllegalOpcodeException {
int opcode = ByteBufUtils.readVarInt(in);
return inboundCodecs.find(opcode);
}
}