package com.captainbern.minecraft.net.protocol; import com.captainbern.minecraft.net.codec.Codec; import com.captainbern.minecraft.net.codec.CodecLookup; import com.captainbern.minecraft.net.codec.CodecRegistrationEntry; import com.captainbern.minecraft.net.exception.InvalidOpcodeException; import com.captainbern.minecraft.net.handler.Handler; import com.captainbern.minecraft.net.handler.HandlerLookup; import com.captainbern.minecraft.net.packet.Packet; import com.captainbern.minecraft.net.util.ByteBufUtils; import com.google.common.collect.Maps; import io.netty.buffer.ByteBuf; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.List; import java.util.Map; public abstract class MinecraftProtocol implements Protocol { private static final Logger LOGGER = LogManager.getLogger(MinecraftProtocol.class); private Map<Side, CodecLookup> codecRegistry = Maps.newConcurrentMap(); private HandlerLookup handlerLookup; private final ProtocolState protocolState; public MinecraftProtocol(ProtocolState protocolState) { this.handlerLookup = new HandlerLookup(this); this.protocolState = protocolState; } public ProtocolState getProtocolState() { return this.protocolState; } @Override public String getId() { return this.getProtocolState().name().toLowerCase(); } @Override public <P extends Packet> Handler<?, P> getHandlerFor(Class<P> packetClass) { return this.handlerLookup.getHandler(packetClass); } @Override public void registerHandlers(String packageName) { this.handlerLookup.registerHandlers(packageName); } @Override public <P extends Packet, H extends Handler<?, P>> void registerHandler(Class<H> handlerClass) { this.handlerLookup.registerHandler(handlerClass); } protected <P extends Packet, C extends Codec<P>> void registerClient(int opcode, Class<P> packet, Class<C> codec) { this.register(Side.CLIENT, opcode, packet, codec); } protected <P extends Packet, C extends Codec<P>> void registerServer(int opcode, Class<P> packet, Class<C> codec) { this.register(Side.SERVER, opcode, packet, codec); } protected <P extends Packet, C extends Codec<P>> void register(Side side, int opcode, Class<P> packet, Class<C> codec) { this.getCodecLookupFor(side).register(opcode, packet, codec); } private CodecLookup getCodecLookupFor(Side side) { CodecLookup lookup = this.codecRegistry.get(side); if (lookup == null) { lookup = new CodecLookup(); this.codecRegistry.put(side, lookup); } return lookup; } @Override public <P extends Packet> CodecRegistrationEntry getCodecRegistration(Side side, Class<P> packetClass) { CodecRegistrationEntry registrationEntry = this.getCodecLookupFor(side).getCodecFor(packetClass); if (registrationEntry == null) { getLogger().warn("Failed to find a CodecRegistrationEntry for packet: \'" + packetClass.getName() + "\'"); } return registrationEntry; } @Override public Codec<?> readHeader(Side side, ByteBuf byteBuf) { int opcode = ByteBufUtils.readVarInt(byteBuf); Codec<?> codec = null; try { codec = this.getCodecLookupFor(side).getCodecFor(opcode); } catch (InvalidOpcodeException e) { getLogger().warn("Failed to find an inbound packet for opcode: " + opcode); } return codec; } public static Logger getLogger() { return LOGGER; } // TODO: This should be improved. // Perhaps provide a Protocol for multiple versions? public static int getProtocolVersion() { return 47; } }