diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java index 868d0a795..c0b30efc5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java @@ -20,6 +20,9 @@ import de.bixilon.minosoft.data.locale.Strings; import de.bixilon.minosoft.data.mappings.versions.Version; import de.bixilon.minosoft.data.mappings.versions.Versions; import de.bixilon.minosoft.logging.Log; +import de.bixilon.minosoft.modding.event.EventInvokerCallback; +import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent; +import de.bixilon.minosoft.modding.event.events.ServerListPingArriveEvent; import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.protocol.ping.ForgeModInfo; import de.bixilon.minosoft.protocol.ping.ServerListPing; @@ -134,7 +137,8 @@ public class ServerListCell extends ListCell implements Initializable { if (server.getLastPing() == null) { server.ping(); } - server.getLastPing().addPingCallback(ping -> Platform.runLater(() -> { + server.getLastPing().registerEvent(new EventInvokerCallback(ServerListPingArriveEvent.class, event -> Platform.runLater(() -> { + ServerListPing ping = event.getServerListPing(); if (server != this.server) { // cell does not contains us anymore return; @@ -193,7 +197,7 @@ public class ServerListCell extends ListCell implements Initializable { canConnect = false; setErrorMotd(String.format("%s: %s", server.getLastPing().getLastConnectionException().getClass().getCanonicalName(), server.getLastPing().getLastConnectionException().getLocalizedMessage())); } - })); + }))); } private void resetCell() { @@ -265,7 +269,7 @@ public class ServerListCell extends ListCell implements Initializable { } optionsConnect.setDisable(true); connection.connect(server.getLastPing().getAddress(), version); - connection.addConnectionChangeCallback(this::handleConnectionCallback); + connection.registerEvent(new EventInvokerCallback<>(this::handleConnectionCallback)); server.addConnection(connection); } @@ -334,7 +338,8 @@ public class ServerListCell extends ListCell implements Initializable { dialog.showAndWait(); } - private void handleConnectionCallback(Connection connection) { + private void handleConnectionCallback(ConnectionStateChangeEvent event) { + Connection connection = event.getConnection(); if (!server.getConnections().contains(connection)) { // the card got recycled return; diff --git a/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java index 3ace14379..c9d997d3a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java @@ -15,6 +15,8 @@ package de.bixilon.minosoft.gui.main; import de.bixilon.minosoft.data.locale.LocaleManager; import de.bixilon.minosoft.data.locale.Strings; +import de.bixilon.minosoft.modding.event.EventInvokerCallback; +import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent; import de.bixilon.minosoft.protocol.network.Connection; import javafx.application.Platform; import javafx.fxml.FXMLLoader; @@ -81,12 +83,13 @@ public class SessionListCell extends ListCell implements Initializab } setStyle(null); this.connection = connection; - connection.addConnectionChangeCallback(this::handleConnectionCallback); + connection.registerEvent(new EventInvokerCallback<>(this::handleConnectionCallback)); connectionId.setText(String.format("#%d", connection.getConnectionId())); account.setText(connection.getPlayer().getAccount().getPlayerName()); } - private void handleConnectionCallback(Connection connection) { + private void handleConnectionCallback(ConnectionStateChangeEvent event) { + Connection connection = event.getConnection(); if (this.connection != connection) { // the card got recycled return; diff --git a/src/main/java/de/bixilon/minosoft/modding/event/EventInvoker.java b/src/main/java/de/bixilon/minosoft/modding/event/EventInvoker.java new file mode 100644 index 000000000..0c8de01c0 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/EventInvoker.java @@ -0,0 +1,41 @@ +/* + * Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program.If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event; + +import de.bixilon.minosoft.modding.event.events.ConnectionEvent; +import de.bixilon.minosoft.modding.loading.Priorities; + +public abstract class EventInvoker { + protected final EventListener listener; + protected final boolean ignoreCancelled; + protected final Priorities priority; + + public EventInvoker(boolean ignoreCancelled, Priorities priority, EventListener listener) { + this.ignoreCancelled = ignoreCancelled; + this.listener = listener; + this.priority = priority; + } + + public boolean isIgnoreCancelled() { + return ignoreCancelled; + } + + public Priorities getPriority() { + return priority; + } + + public abstract void invoke(ConnectionEvent event); + + public abstract Class getEventType(); +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/EventInvokerCallback.java b/src/main/java/de/bixilon/minosoft/modding/event/EventInvokerCallback.java new file mode 100644 index 000000000..7dd95d41a --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/EventInvokerCallback.java @@ -0,0 +1,54 @@ +/* + * Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program.If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event; + +import de.bixilon.minosoft.modding.event.events.ConnectionEvent; +import de.bixilon.minosoft.modding.loading.Priorities; + +public class EventInvokerCallback extends EventInvoker { + private final InvokerCallback callback; + + Class eventType = ConnectionEvent.class; + + public EventInvokerCallback(boolean ignoreCancelled, InvokerCallback callback) { + super(ignoreCancelled, Priorities.NORMAL, null); + this.callback = callback; + } + + + // if you need instant fireing support + public EventInvokerCallback(Class eventType, InvokerCallback callback) { + this(false, callback); + this.eventType = eventType; // ToDo: how to get the class of V? seems to be impossible + } + + public EventInvokerCallback(InvokerCallback callback) { + this(false, callback); + } + + public void invoke(ConnectionEvent event) { + if (eventType != event.getClass()) { + return; + } + callback.handle((V) event); + } + + public Class getEventType() { + return eventType; + } + + public interface InvokerCallback { + void handle(V event); + } +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/EventMethod.java b/src/main/java/de/bixilon/minosoft/modding/event/EventInvokerMethod.java similarity index 66% rename from src/main/java/de/bixilon/minosoft/modding/event/EventMethod.java rename to src/main/java/de/bixilon/minosoft/modding/event/EventInvokerMethod.java index 5d72c83d1..459e47431 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/EventMethod.java +++ b/src/main/java/de/bixilon/minosoft/modding/event/EventInvokerMethod.java @@ -16,23 +16,23 @@ package de.bixilon.minosoft.modding.event; import de.bixilon.minosoft.modding.event.events.CancelableEvent; import de.bixilon.minosoft.modding.event.events.ConnectionEvent; import de.bixilon.minosoft.modding.event.events.annotations.EventHandler; +import de.bixilon.minosoft.modding.loading.Priorities; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -public class EventMethod { - private final EventHandler annotation; - private final EventListener listener; +public class EventInvokerMethod extends EventInvoker { private final Method method; + private final Class eventType; - public EventMethod(EventHandler annotation, EventListener listener, Method method) { - this.annotation = annotation; - this.listener = listener; + public EventInvokerMethod(boolean ignoreCancelled, Priorities priority, EventListener listener, Method method) { + super(ignoreCancelled, priority, listener); this.method = method; + eventType = (Class) method.getParameters()[0].getType(); } - public EventHandler getAnnotation() { - return annotation; + public EventInvokerMethod(EventHandler annotation, EventListener listener, Method method) { + this(annotation.ignoreCancelled(), annotation.priority(), listener, method); } public Method getMethod() { @@ -43,7 +43,7 @@ public class EventMethod { if (!method.getParameters()[0].getType().isAssignableFrom(event.getClass())) { return; } - if (!annotation.ignoreCancelled() && event instanceof CancelableEvent cancelableEvent && cancelableEvent.isCancelled()) { + if (!ignoreCancelled && event instanceof CancelableEvent cancelableEvent && cancelableEvent.isCancelled()) { return; } try { @@ -52,4 +52,8 @@ public class EventMethod { e.printStackTrace(); } } + + public Class getEventType() { + return eventType; + } } diff --git a/src/main/java/de/bixilon/minosoft/modding/event/EventManager.java b/src/main/java/de/bixilon/minosoft/modding/event/EventManager.java index a2abeba77..9fbfebebf 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/EventManager.java +++ b/src/main/java/de/bixilon/minosoft/modding/event/EventManager.java @@ -23,16 +23,16 @@ import java.util.HashMap; import java.util.HashSet; public class EventManager { - private final HashSet globalEventListeners = new HashSet<>(); - private final HashMap, HashSet> specificEventListeners = new HashMap<>(); + private final HashSet globalEventListeners = new HashSet<>(); + private final HashMap, HashSet> specificEventListeners = new HashMap<>(); public void registerGlobalListener(EventListener listener) { globalEventListeners.addAll(getEventMethods(listener)); } - private HashSet getEventMethods(EventListener listener) { + private HashSet getEventMethods(EventListener listener) { Class clazz = listener.getClass(); - HashSet eventMethods = new HashSet<>(); + HashSet eventInvokers = new HashSet<>(); for (Method method : clazz.getMethods()) { EventHandler annotation = method.getAnnotation(EventHandler.class); if (annotation == null) { @@ -44,12 +44,12 @@ public class EventManager { if (!ConnectionEvent.class.isAssignableFrom(method.getParameters()[0].getType())) { continue; } - eventMethods.add(new EventMethod(annotation, listener, method)); + eventInvokers.add(new EventInvokerMethod(annotation, listener, method)); } - return eventMethods; + return eventInvokers; } - public HashSet getGlobalEventListeners() { + public HashSet getGlobalEventListeners() { return globalEventListeners; } @@ -61,7 +61,7 @@ public class EventManager { specificEventListeners.put(serverAddresses, getEventMethods(listener)); } - public HashMap, HashSet> getSpecificEventListeners() { + public HashMap, HashSet> getSpecificEventListeners() { return specificEventListeners; } } diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/ConnectionStateChangeEvent.java b/src/main/java/de/bixilon/minosoft/modding/event/events/ConnectionStateChangeEvent.java new file mode 100644 index 000000000..6bb8ef047 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/ConnectionStateChangeEvent.java @@ -0,0 +1,41 @@ +/* + * Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program.If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.modding.event.events; + +import de.bixilon.minosoft.modding.event.events.annotations.Unsafe; +import de.bixilon.minosoft.protocol.network.Connection; +import de.bixilon.minosoft.protocol.protocol.ConnectionStates; + +/** + * Fired when the connection state was just changed + */ +@Unsafe +public class ConnectionStateChangeEvent extends ConnectionEvent { + private final ConnectionStates previousState; + private final ConnectionStates currentState; + + public ConnectionStateChangeEvent(Connection connection, ConnectionStates previousState, ConnectionStates currentState) { + super(connection); + this.previousState = previousState; + this.currentState = currentState; + } + + public ConnectionStates getPreviousState() { + return previousState; + } + + public ConnectionStates getCurrentState() { + return currentState; + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ConnectionChangeCallback.java b/src/main/java/de/bixilon/minosoft/modding/event/events/ServerListPingArriveEvent.java similarity index 56% rename from src/main/java/de/bixilon/minosoft/gui/main/ConnectionChangeCallback.java rename to src/main/java/de/bixilon/minosoft/modding/event/events/ServerListPingArriveEvent.java index 2442a2483..be8095f6e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/ConnectionChangeCallback.java +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/ServerListPingArriveEvent.java @@ -11,10 +11,26 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.main; +package de.bixilon.minosoft.modding.event.events; import de.bixilon.minosoft.protocol.network.Connection; +import de.bixilon.minosoft.protocol.ping.ServerListPing; -public interface ConnectionChangeCallback { - void handle(Connection connection); +import javax.annotation.Nullable; + +/** + * Fired when a ping arrives from the server or the ping already arrived and the event got registered to late + */ +public class ServerListPingArriveEvent extends ConnectionEvent { + private final ServerListPing serverListPing; + + public ServerListPingArriveEvent(Connection connection, ServerListPing serverListPing) { + super(connection); + this.serverListPing = serverListPing; + } + + @Nullable + public ServerListPing getServerListPing() { + return serverListPing; + } } diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/annotations/Unsafe.java b/src/main/java/de/bixilon/minosoft/modding/event/events/annotations/Unsafe.java index bd3ce413a..7b38bf237 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/events/annotations/Unsafe.java +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/annotations/Unsafe.java @@ -13,5 +13,9 @@ package de.bixilon.minosoft.modding.event.events.annotations; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) public @interface Unsafe { } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java index 071edb608..07425f046 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java @@ -21,21 +21,16 @@ import de.bixilon.minosoft.data.mappings.recipes.Recipes; import de.bixilon.minosoft.data.mappings.versions.Version; import de.bixilon.minosoft.data.mappings.versions.VersionMapping; import de.bixilon.minosoft.data.mappings.versions.Versions; -import de.bixilon.minosoft.gui.main.ConnectionChangeCallback; import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.logging.LogLevels; -import de.bixilon.minosoft.modding.event.EventMethod; -import de.bixilon.minosoft.modding.event.events.CancelableEvent; -import de.bixilon.minosoft.modding.event.events.ConnectionEvent; -import de.bixilon.minosoft.modding.event.events.PacketReceiveEvent; -import de.bixilon.minosoft.modding.event.events.PacketSendEvent; +import de.bixilon.minosoft.modding.event.EventInvoker; +import de.bixilon.minosoft.modding.event.events.*; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.ServerboundPacket; import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketHandshake; import de.bixilon.minosoft.protocol.packets.serverbound.login.PacketLoginStart; import de.bixilon.minosoft.protocol.packets.serverbound.status.PacketStatusPing; import de.bixilon.minosoft.protocol.packets.serverbound.status.PacketStatusRequest; -import de.bixilon.minosoft.protocol.ping.PingCallback; import de.bixilon.minosoft.protocol.ping.ServerListPing; import de.bixilon.minosoft.protocol.protocol.*; import de.bixilon.minosoft.util.DNSUtil; @@ -43,7 +38,6 @@ import de.bixilon.minosoft.util.ServerAddress; import org.xbill.DNS.TextParseException; import javax.annotation.Nullable; -import java.util.HashSet; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; @@ -55,9 +49,7 @@ public class Connection { final PacketSender sender = new PacketSender(this); final LinkedBlockingQueue handlingQueue = new LinkedBlockingQueue<>(); final VelocityHandler velocityHandler = new VelocityHandler(this); - final HashSet pingCallbacks = new HashSet<>(); - final HashSet connectionChangeCallbacks = new HashSet<>(); - final LinkedList eventListeners = new LinkedList<>(); + final LinkedList eventListeners = new LinkedList<>(); final int connectionId; final Player player; final String hostname; @@ -282,15 +274,6 @@ public class Connection { return connectionId; } - public void addPingCallback(PingCallback callback) { - if (getConnectionState() == ConnectionStates.FAILED || getConnectionState() == ConnectionStates.FAILED_NO_RETRY || lastPing != null) { - // ping done - callback.handle(lastPing); - return; - } - pingCallbacks.add(callback); - } - public ConnectionStates getConnectionState() { return state; } @@ -320,7 +303,7 @@ public class Connection { if (a == null || b == null) { return 0; } - return -(b.getAnnotation().priority().ordinal() - a.getAnnotation().priority().ordinal()); + return -(b.getPriority().ordinal() - a.getPriority().ordinal()); }); // connection established, starting threads and logging in startHandlingThread(); @@ -370,11 +353,7 @@ public class Connection { case FAILED_NO_RETRY -> handlePingCallbacks(null); } // handle callbacks - connectionChangeCallbacks.forEach((callback -> callback.handle(this))); - } - - public HashSet getPingCallbacks() { - return pingCallbacks; + fireEvent(new ConnectionStateChangeEvent(this, previousState, state)); } public int getDesiredVersionNumber() { @@ -387,21 +366,23 @@ public class Connection { public void handlePingCallbacks(@Nullable ServerListPing ping) { this.lastPing = ping; - pingCallbacks.forEach((callback -> callback.handle(ping))); + fireEvent(new ServerListPingArriveEvent(this, ping)); + } + + public void registerEvent(EventInvoker method) { + eventListeners.add(method); + if (method.getEventType() == ServerListPingArriveEvent.class) { + if (getConnectionState() == ConnectionStates.FAILED || getConnectionState() == ConnectionStates.FAILED_NO_RETRY || lastPing != null) { + // ping done + method.invoke(new ServerListPingArriveEvent(this, lastPing)); + } + } } public Exception getLastConnectionException() { return (lastException != null) ? lastException : network.getLastException(); } - public void addConnectionChangeCallback(ConnectionChangeCallback callback) { - connectionChangeCallbacks.add(callback); - } - - public HashSet getConnectionChangeCallbacks() { - return connectionChangeCallbacks; - } - public ServerListPing getLastPing() { return lastPing; } diff --git a/src/main/java/de/bixilon/minosoft/protocol/ping/PingCallback.java b/src/main/java/de/bixilon/minosoft/protocol/ping/PingCallback.java deleted file mode 100644 index 4600e618a..000000000 --- a/src/main/java/de/bixilon/minosoft/protocol/ping/PingCallback.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2020 Moritz Zwerger - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program.If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.protocol.ping; - -public interface PingCallback { - void handle(ServerListPing ping); -}