diff --git a/src/main/java/net/hypixel/modapi/HypixelModAPI.java b/src/main/java/net/hypixel/modapi/HypixelModAPI.java index eecc7d7..7169809 100644 --- a/src/main/java/net/hypixel/modapi/HypixelModAPI.java +++ b/src/main/java/net/hypixel/modapi/HypixelModAPI.java @@ -1,8 +1,9 @@ package net.hypixel.modapi; import net.hypixel.modapi.error.ErrorReason; -import net.hypixel.modapi.error.ModAPIException; import net.hypixel.modapi.handler.ClientboundPacketHandler; +import net.hypixel.modapi.handler.ErrorHandler; +import net.hypixel.modapi.handler.RegisteredHandler; import net.hypixel.modapi.packet.ClientboundHypixelPacket; import net.hypixel.modapi.packet.EventPacket; import net.hypixel.modapi.packet.HypixelPacket; @@ -29,7 +30,7 @@ public static HypixelModAPI getInstance() { } private final PacketRegistry registry = new PacketRegistry(); - private final Map, Collection>> handlers = new ConcurrentHashMap<>(); + private final Map>> handlers = new ConcurrentHashMap<>(); private final Set subscribedEvents = ConcurrentHashMap.newKeySet(); private Set lastSubscribedEvents = Collections.emptySet(); private Predicate packetSender = null; @@ -109,7 +110,8 @@ public void handle(String identifier, PacketSerializer serializer) { // All responses contain a boolean of if the response is a success, if not then a further var int is included to identify the error if (!serializer.readBoolean()) { ErrorReason reason = ErrorReason.getById(serializer.readVarInt()); - throw new ModAPIException(identifier, reason); + handleError(identifier, reason); + return; } ClientboundHypixelPacket packet = registry.createClientboundPacket(identifier, serializer); @@ -124,12 +126,20 @@ public void handle(String identifier, PacketSerializer serializer) { @ApiStatus.Internal @SuppressWarnings("unchecked") public void handle(ClientboundHypixelPacket packet) { - Collection> typedHandlers = handlers.get(packet.getClass()); + Collection> typedHandlers = handlers.get(packet.getIdentifier()); // nothing registered for this packet. if (typedHandlers == null) return; - for (ClientboundPacketHandler handler : typedHandlers) { - // this cast is safe as we ensure its type when it is added to the handlers list in the first place. - ((ClientboundPacketHandler) handler).handle(packet); + for (RegisteredHandlerImpl handler : typedHandlers) { + handler.handle(packet); + } + } + + @ApiStatus.Internal + public void handleError(String identifier, ErrorReason reason) { + Collection> handlers = this.handlers.get(identifier); + if (handlers == null) return; + for (RegisteredHandlerImpl handler : handlers) { + handler.handleError(reason); } } @@ -141,9 +151,19 @@ public void setPacketSender(Predicate packetSender) { this.packetSender = packetSender; } - public void registerHandler(Class packetClass, ClientboundPacketHandler handler) { - if (packetClass == null || handler == null) return; - handlers.computeIfAbsent(packetClass, cls -> new CopyOnWriteArrayList<>()).add(handler); + public RegisteredHandler registerHandler(Class packetClass, ClientboundPacketHandler handler) { + if (packetClass == null) { + throw new NullPointerException("packetClass cannot be null"); + } + + if (handler == null) { + throw new NullPointerException("handler cannot be null"); + } + + RegisteredHandlerImpl registeredHandler = new RegisteredHandlerImpl<>(handler); + handlers.computeIfAbsent(getRegistry().getIdentifier(packetClass), cls -> new CopyOnWriteArrayList<>()) + .add(registeredHandler); + return registeredHandler; } public void subscribeToEventPacket(Class packet) { @@ -162,4 +182,32 @@ public boolean sendPacket(HypixelPacket packet) { return packetSender.test(packet); } + + private static class RegisteredHandlerImpl implements RegisteredHandler { + private final ClientboundPacketHandler handler; + private ErrorHandler errorHandler; + + RegisteredHandlerImpl(ClientboundPacketHandler handler) { + this.handler = handler; + } + + @Override + public void onError(ErrorHandler errorHandler) { + if (this.errorHandler != null) { + throw new IllegalStateException("Error handler already set"); + } + this.errorHandler = errorHandler; + } + + void handle(ClientboundHypixelPacket packet) { + // this cast is safe as we ensure its type when it is added to the handlers list in the first place. + handler.handle((T) packet); + } + + void handleError(ErrorReason reason) { + if (errorHandler != null) { + errorHandler.onError(reason); + } + } + } } diff --git a/src/main/java/net/hypixel/modapi/handler/ErrorHandler.java b/src/main/java/net/hypixel/modapi/handler/ErrorHandler.java new file mode 100644 index 0000000..b2d49f9 --- /dev/null +++ b/src/main/java/net/hypixel/modapi/handler/ErrorHandler.java @@ -0,0 +1,9 @@ +package net.hypixel.modapi.handler; + +import net.hypixel.modapi.error.ErrorReason; +import net.hypixel.modapi.packet.ClientboundHypixelPacket; + +@FunctionalInterface +public interface ErrorHandler { + void onError(ErrorReason reason); +} diff --git a/src/main/java/net/hypixel/modapi/handler/RegisteredHandler.java b/src/main/java/net/hypixel/modapi/handler/RegisteredHandler.java new file mode 100644 index 0000000..79fab78 --- /dev/null +++ b/src/main/java/net/hypixel/modapi/handler/RegisteredHandler.java @@ -0,0 +1,12 @@ +package net.hypixel.modapi.handler; + +import net.hypixel.modapi.packet.ClientboundHypixelPacket; + +public interface RegisteredHandler { + /** + * Handling for when an error is received for this registered handler. + *
+ * Note: This error may be received due to any modification requesting the same packet type. + */ + void onError(ErrorHandler errorHandler); +}