package com.captainbern.minecraft.net.codec;
import com.captainbern.minecraft.net.exception.InvalidOpcodeException;
import com.captainbern.minecraft.net.packet.Packet;
import com.captainbern.reflection.Reflection;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class CodecLookup {
private final Map<Integer, Codec<?>> CODEC_LOOKUP = Maps.newConcurrentMap();
private final Map<Class<? extends Packet>, CodecRegistrationEntry> REGISTRATION = Maps.newConcurrentMap();
private final AtomicInteger NEXT_ID = new AtomicInteger(0);
public CodecLookup() {
}
public <P extends Packet, C extends Codec<? super P>> CodecRegistrationEntry register(int opcode, Class<P> packet, Class<C> codecClass) {
CodecRegistrationEntry codecRegistration = this.REGISTRATION.get(packet);
if (codecRegistration != null) {
return codecRegistration;
}
C codec;
try {
codec = new Reflection().reflect(codecClass).newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create a new instance of class: " + codecClass.getName());
}
if (opcode < 0) {
throw new IllegalArgumentException("Opcode must either be 0 or greater than 0");
} else {
int id;
try {
do {
id = this.NEXT_ID.getAndIncrement();
} while (get(id) != null);
} catch (IndexOutOfBoundsException e) {
throw new RuntimeException("Failed to assign a valid opcode to packet: " + packet.getCanonicalName());
}
opcode = id;
}
Codec<?> check = get(opcode);
if (check != null && check.getClass() != codecClass)
throw new IllegalStateException("Cannot assign opcode: " + opcode + " to: " + codecClass.getCanonicalName() + ", already assigned to: " + check.getClass().getCanonicalName());
codecRegistration = new CodecRegistrationEntry(opcode, codec);
this.register(opcode, codec);
this.REGISTRATION.put(packet, codecRegistration);
return codecRegistration;
}
private void register(int opcode, Codec<?> codec) {
this.CODEC_LOOKUP.put(opcode, codec);
}
private Codec<?> get(int opcode) {
return this.CODEC_LOOKUP.get(opcode);
}
public Codec<?> getCodecFor(int opcode) throws InvalidOpcodeException {
try {
Codec<?> codec = this.CODEC_LOOKUP.get(opcode);
if (codec == null)
throw new NullPointerException("Failed to find the codec for opcode: " + opcode);
return codec;
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
System.err.println("Failed to find a Codec for opcode: " + opcode);
return null;
}
}
public <P extends Packet> CodecRegistrationEntry getCodecFor(Class<P> packetClass) {
return this.REGISTRATION.get(packetClass);
}
@Override
public String toString() {
return "CodecLookup{packets=" + this.REGISTRATION + ", opcodes=" + this.CODEC_LOOKUP + "}";
}
}