package com.captainbern.minecraft.net.handler;
import com.captainbern.minecraft.net.packet.Packet;
import com.captainbern.minecraft.net.protocol.MinecraftProtocol;
import com.captainbern.minecraft.net.protocol.Protocol;
import com.google.common.collect.Maps;
import com.google.common.reflect.ClassPath;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
public class HandlerLookup {
private final Map<Class<? extends Packet>, Handler> registry = Maps.newConcurrentMap();
private final Protocol protocol;
public HandlerLookup(Protocol protocol) {
this.protocol = protocol;
}
public <P extends Packet> Handler<?, P> getHandler(Class<P> packetType) {
if (this.registry.get(packetType) == null)
return null;
return this.registry.get(packetType);
}
public void registerHandlers(String packageName) {
try {
Set<ClassPath.ClassInfo> classes = ClassPath.from(MinecraftProtocol.class.getClassLoader()).getTopLevelClasses(packageName);
for (ClassPath.ClassInfo classInfo : classes) {
Class<?> clazz = classInfo.load();
if (!Handler.class.isAssignableFrom(clazz))
continue;
this.registerHandler(((Class<? extends Handler>) clazz));
}
} catch (IOException e) {
throw new RuntimeException("Failed to register the handlers for package: \'" + packageName + "\'");
}
}
public <P extends Packet, H extends Handler<?, P>> void registerHandler(Class<H> handlerClass) {
if (!handlerClass.isAnnotationPresent(PacketHandler.class))
throw new IllegalArgumentException("Handler: \'" + handlerClass.getName() + "\' does not have the required PacketHandler annotation!");
Handler handler;
try {
handler = handlerClass.newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create a new instance of handler class: \'" + handlerClass.getName() + "\'");
}
PacketHandler packetHandler = handlerClass.getAnnotation(PacketHandler.class);
if (packetHandler.protocol().getMinecraftProtocol().getClass() != this.protocol.getClass())
return;
Class<? extends Packet> annotationPacketType = packetHandler.packet();
Type[] types = handlerClass.getGenericInterfaces();
Class genericPacketType = (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[1];
// Check if the packet-types match
if (annotationPacketType != genericPacketType)
throw new IllegalArgumentException("PacketType defined in @PacketHandler does not match the generic defined PacketType for handler: \'" + handlerClass.getName() + "\'");
if (this.registry.get(annotationPacketType) != null)
MinecraftProtocol.getLogger().warn("Overriding a handler for: \'" + annotationPacketType.getName() + "\'");
this.registry.put(annotationPacketType, handler);
}
}