diff --git a/build.gradle b/build.gradle index b32491b2a..0304bf8a6 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 group = 'tech.xigam' -version = '1.0.0-dev' +version = '1.0.2-dev' sourceCompatibility = 17 targetCompatibility = 17 diff --git a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java index 0dec6839e..633c2c8c1 100644 --- a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java @@ -8,13 +8,14 @@ import java.util.List; @Command(label = "coop", usage = "coop", description = "Forces someone to join the world of others", permission = "server.coop") -public class CoopCommand implements CommandHandler { +public final class CoopCommand implements CommandHandler { @Override public void execute(Player sender, List args) { if (args.size() < 2) { CommandHandler.sendMessage(sender, "Usage: coop "); return; } + try { int tid = Integer.parseInt(args.get(0)); int hostId = Integer.parseInt(args.get(1)); diff --git a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java index cb6d1e93e..e78b381e2 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java @@ -15,7 +15,7 @@ import java.util.*; @Command(label = "giveall", usage = "giveall [player] [amount]", description = "Gives all items", aliases = {"givea"}, permission = "player.giveall", threading = true) -public class GiveAllCommand implements CommandHandler { +public final class GiveAllCommand implements CommandHandler { @Override public void execute(Player sender, List args) { @@ -142,16 +142,11 @@ public class GiveAllCommand implements CommandHandler { } } - if (testItemsList.contains(itemId)) { - return true; - } - - return false; + return testItemsList.contains(itemId); } static class Range { - private int min; - private int max; + private final int min, max; public Range(int min, int max) { if(min > max){ @@ -159,6 +154,7 @@ public class GiveAllCommand implements CommandHandler { max ^= min; min ^= max; } + this.min = min; this.max = max; } diff --git a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java index 35cedab9a..031358d45 100644 --- a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java @@ -6,24 +6,20 @@ import emu.grasscutter.command.CommandHandler; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.packet.send.PacketMailChangeNotify; -import java.time.Instant; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Locale; @Command(label = "sendmail", usage = "sendmail [templateId]", description = "Sends mail to the specified user. The usage of this command changes based on it's composition state.", permission = "server.sendmail") -public class SendMailCommand implements CommandHandler { +public final class SendMailCommand implements CommandHandler { // TODO: You should be able to do /sendmail and then just send subsequent messages until you finish // However, due to the current nature of the command system, I don't think this is possible without rewriting // the command system (again). For now this will do // Key = User that is constructing the mail. - private static HashMap mailBeingConstructed = new HashMap(); + private static final HashMap mailBeingConstructed = new HashMap(); // Yes this is awful and I hate it. @Override @@ -48,7 +44,6 @@ public class SendMailCommand implements CommandHandler { default -> { if (DatabaseHelper.getPlayerById(Integer.parseInt(args.get(0))) != null) { mailBuilder = new MailBuilder(Integer.parseInt(args.get(0)), new Mail()); - break; } else { CommandHandler.sendMessage(sender, "The user with an id of '" + args.get(0) + "' does not exist"); return; @@ -73,7 +68,7 @@ public class SendMailCommand implements CommandHandler { } case "finish" -> { if (mailBuilder.constructionStage == 3) { - if (mailBuilder.sendToAll == false) { + if (!mailBuilder.sendToAll) { Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail); CommandHandler.sendMessage(sender, "Message sent to user " + mailBuilder.recipient + "!"); } else { diff --git a/src/main/java/emu/grasscutter/command/commands/TpallCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java similarity index 75% rename from src/main/java/emu/grasscutter/command/commands/TpallCommand.java rename to src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java index 20236c729..bd4a8a06e 100644 --- a/src/main/java/emu/grasscutter/command/commands/TpallCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java @@ -9,23 +9,25 @@ import java.util.List; @Command(label = "tpall", usage = "tpall", description = "Teleports all players in your world to your position", permission = "player.tpall") -public class TpallCommand implements CommandHandler { +public final class TeleportAllCommand implements CommandHandler { @Override public void execute(Player sender, List args) { if (sender == null) { CommandHandler.sendMessage(null, "Run this command in-game."); return; } + if (!sender.getWorld().isMultiplayer()) { CommandHandler.sendMessage(sender, "You only can use this command in MP mode."); return; } - for (Player gp : sender.getWorld().getPlayers()) { - if (gp.equals(sender)) + + for (Player player : sender.getWorld().getPlayers()) { + if (player.equals(sender)) continue; Position pos = sender.getPos(); - gp.getWorld().transferPlayerToScene(gp, sender.getSceneId(), pos); + player.getWorld().transferPlayerToScene(player, sender.getSceneId(), pos); } } } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 2d3442bbe..13f2674f2 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -37,6 +37,9 @@ import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass; import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass; +import emu.grasscutter.server.event.player.PlayerJoinEvent; +import emu.grasscutter.server.event.player.PlayerQuitEvent; +import emu.grasscutter.server.event.player.PlayerReceiveMailEvent; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.*; @@ -725,9 +728,13 @@ public class Player { public List getAllMail() { return this.mail; } public void sendMail(Mail message) { + // Call mail receive event. + PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this, message); event.call(); + if(event.isCanceled()) return; message = event.getMessage(); + this.mail.add(message); this.save(); - Grasscutter.getLogger().info("Mail sent to user [" + this.getUid() + ":" + this.getNickname() + "]!"); + Grasscutter.getLogger().debug("Mail sent to user [" + this.getUid() + ":" + this.getNickname() + "]!"); if(this.isOnline()) { this.sendPacket(new PacketMailChangeNotify(this, message)); } // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline @@ -1037,6 +1044,11 @@ public class Player { // First notify packets sent this.setHasSentAvatarDataNotify(true); + + // Call join event. + PlayerJoinEvent event = new PlayerJoinEvent(this); event.call(); + if(event.isCanceled()) // If event is not cancelled, continue. + session.close(); } public void onLogout() { @@ -1055,6 +1067,9 @@ public class Player { this.save(); this.getTeamManager().saveAvatars(); this.getFriendsList().save(); + + // Call quit event. + PlayerQuitEvent event = new PlayerQuitEvent(this); event.call(); } public enum SceneLoadState { diff --git a/src/main/java/emu/grasscutter/plugin/Plugin.java b/src/main/java/emu/grasscutter/plugin/Plugin.java index a3160d7c7..97fc5fd77 100644 --- a/src/main/java/emu/grasscutter/plugin/Plugin.java +++ b/src/main/java/emu/grasscutter/plugin/Plugin.java @@ -1,13 +1,22 @@ package emu.grasscutter.plugin; import emu.grasscutter.Grasscutter; +import emu.grasscutter.plugin.api.ServerHook; import emu.grasscutter.server.game.GameServer; +import java.io.File; +import java.io.InputStream; +import java.net.URLClassLoader; + /** * The base class for all plugins to extend. */ public abstract class Plugin { + private final ServerHook server = ServerHook.getInstance(); + private PluginIdentifier identifier; + private URLClassLoader classLoader; + private File dataFolder; /** * This method is reflected into. @@ -15,10 +24,20 @@ public abstract class Plugin { * Set plugin variables. * @param identifier The plugin's identifier. */ - private void initializePlugin(PluginIdentifier identifier) { - if(this.identifier == null) - this.identifier = identifier; - else Grasscutter.getLogger().warn(this.identifier.name + " had a reinitialization attempt."); + private void initializePlugin(PluginIdentifier identifier, URLClassLoader classLoader) { + if(this.identifier != null) { + Grasscutter.getLogger().warn(this.identifier.name + " had a reinitialization attempt."); + return; + } + + this.identifier = identifier; + this.classLoader = classLoader; + this.dataFolder = new File(Grasscutter.getConfig().PLUGINS_FOLDER, identifier.name); + + if(!this.dataFolder.exists() && !this.dataFolder.mkdirs()) { + Grasscutter.getLogger().warn("Failed to create plugin data folder for " + this.identifier.name); + return; + } } /** @@ -55,7 +74,32 @@ public abstract class Plugin { * @return A server instance. */ public final GameServer getServer() { - return Grasscutter.getGameServer(); + return this.server.getGameServer(); + } + + /** + * Returns an input stream for a resource in the JAR file. + * @param resourceName The name of the resource. + * @return An input stream. + */ + public final InputStream getResource(String resourceName) { + return this.classLoader.getResourceAsStream(resourceName); + } + + /** + * Returns a directory where plugins can store data files. + * @return A directory on the file system. + */ + public final File getDataFolder() { + return this.dataFolder; + } + + /** + * Returns the server hook. + * @return A server hook singleton. + */ + public final ServerHook getHandle() { + return this.server; } /* Called when the plugin is first loaded. */ diff --git a/src/main/java/emu/grasscutter/plugin/PluginManager.java b/src/main/java/emu/grasscutter/plugin/PluginManager.java index 9e0b869b9..7a5e0aa00 100644 --- a/src/main/java/emu/grasscutter/plugin/PluginManager.java +++ b/src/main/java/emu/grasscutter/plugin/PluginManager.java @@ -3,9 +3,9 @@ package emu.grasscutter.plugin; import emu.grasscutter.Grasscutter; import emu.grasscutter.server.event.Event; import emu.grasscutter.server.event.EventHandler; -import emu.grasscutter.server.event.Listener; +import emu.grasscutter.server.event.HandlerPriority; +import emu.grasscutter.utils.EventConsumer; import emu.grasscutter.utils.Utils; -import org.reflections.Reflections; import java.io.File; import java.io.InputStreamReader; @@ -21,7 +21,7 @@ import java.util.jar.JarFile; */ public final class PluginManager { private final Map plugins = new HashMap<>(); - private final Map> listeners = new HashMap<>(); + private final List> listeners = new LinkedList<>(); public PluginManager() { this.loadPlugins(); // Load all plugins from the plugins directory. @@ -68,12 +68,12 @@ public final class PluginManager { JarEntry entry = entries.nextElement(); if(entry.isDirectory() || !entry.getName().endsWith(".class") || entry.getName().contains("module-info")) continue; String className = entry.getName().replace(".class", "").replace("/", "."); - Class clazz = loader.loadClass(className); + loader.loadClass(className); } Class pluginClass = loader.loadClass(pluginConfig.mainClass); Plugin pluginInstance = (Plugin) pluginClass.getDeclaredConstructor().newInstance(); - this.loadPlugin(pluginInstance, PluginIdentifier.fromPluginConfig(pluginConfig)); + this.loadPlugin(pluginInstance, PluginIdentifier.fromPluginConfig(pluginConfig), loader); fileReader.close(); // Close the file reader. } catch (ClassNotFoundException ignored) { @@ -89,14 +89,14 @@ public final class PluginManager { * Load the specified plugin. * @param plugin The plugin instance. */ - private void loadPlugin(Plugin plugin, PluginIdentifier identifier) { + private void loadPlugin(Plugin plugin, PluginIdentifier identifier, URLClassLoader classLoader) { Grasscutter.getLogger().info("Loading plugin: " + identifier.name); // Add the plugin's identifier. try { Class pluginClass = Plugin.class; - Method method = pluginClass.getDeclaredMethod("initializePlugin", PluginIdentifier.class); - method.setAccessible(true); method.invoke(plugin, identifier); method.setAccessible(false); + Method method = pluginClass.getDeclaredMethod("initializePlugin", PluginIdentifier.class, URLClassLoader.class); + method.setAccessible(true); method.invoke(plugin, identifier, classLoader); method.setAccessible(false); } catch (Exception ignored) { Grasscutter.getLogger().warn("Failed to add plugin identifier: " + identifier.name); } @@ -129,11 +129,10 @@ public final class PluginManager { /** * Registers a plugin's event listener. - * @param plugin The plugin instance. * @param listener The event listener. */ - public void registerListener(Plugin plugin, Listener listener) { - this.listeners.computeIfAbsent(plugin, k -> new ArrayList<>()).add(listener); + public void registerListener(EventHandler listener) { + this.listeners.add(listener); } /** @@ -141,23 +140,31 @@ public final class PluginManager { * @param event The event to invoke. */ public void invokeEvent(Event event) { - this.listeners.values().stream() - .flatMap(Collection::stream) - .forEach(listener -> this.invokeOnListener(listener, event)); + EnumSet.allOf(HandlerPriority.class) + .forEach(priority -> this.checkAndFilter(event, priority)); } - + /** - * Attempts to invoke the event on the provided listener. + * Check an event to handlers for the priority. + * @param event The event being called. + * @param priority The priority to call for. */ - private void invokeOnListener(Listener listener, Event event) { - try { - Class listenerClass = listener.getClass(); - Method[] methods = listenerClass.getMethods(); - for (Method method : methods) { - if(!method.isAnnotationPresent(EventHandler.class)) return; - if(!method.getParameterTypes()[0].isAssignableFrom(event.getClass())) return; - method.invoke(listener, event); - } - } catch (Exception ignored) { } + private void checkAndFilter(Event event, HandlerPriority priority) { + this.listeners.stream() + .filter(handler -> handler.handles().isInstance(event)) + .filter(handler -> handler.getPriority() == priority) + .toList().forEach(handler -> this.invokeHandler(event, handler)); + } + + /** + * Performs logic checks then invokes the provided event handler. + * @param event The event passed through to the handler. + * @param handler The handler to invoke. + */ + @SuppressWarnings("unchecked") + private void invokeHandler(Event event, EventHandler handler) { + if(!event.isCanceled() || + (event.isCanceled() && handler.ignoresCanceled()) + ) handler.getCallback().consume((T) event); } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/plugin/api/ServerHook.java b/src/main/java/emu/grasscutter/plugin/api/ServerHook.java index cbca97b8f..a37abfb62 100644 --- a/src/main/java/emu/grasscutter/plugin/api/ServerHook.java +++ b/src/main/java/emu/grasscutter/plugin/api/ServerHook.java @@ -1,6 +1,9 @@ package emu.grasscutter.plugin.api; +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.dispatch.DispatchServer; import emu.grasscutter.server.game.GameServer; import java.util.LinkedList; @@ -11,7 +14,8 @@ import java.util.List; */ public final class ServerHook { private static ServerHook instance; - private final GameServer server; + private final GameServer gameServer; + private final DispatchServer dispatchServer; /** * Gets the server hook instance. @@ -23,19 +27,47 @@ public final class ServerHook { /** * Hooks into a server. - * @param server The server to hook into. + * @param gameServer The game server to hook into. + * @param dispatchServer The dispatch server to hook into. */ - public ServerHook(GameServer server) { - this.server = server; - + public ServerHook(GameServer gameServer, DispatchServer dispatchServer) { + this.gameServer = gameServer; + this.dispatchServer = dispatchServer; + instance = this; } + /** + * @return The game server. + */ + public GameServer getGameServer() { + return this.gameServer; + } + + /** + * @return The dispatch server. + */ + public DispatchServer getDispatchServer() { + return this.dispatchServer; + } + /** * Gets all online players. * @return Players connected to the server. */ public List getOnlinePlayers() { - return new LinkedList<>(this.server.getPlayers().values()); + return new LinkedList<>(this.gameServer.getPlayers().values()); + } + + /** + * Registers a command to the {@link emu.grasscutter.command.CommandMap}. + * @param handler The command handler. + */ + public void registerCommand(CommandHandler handler) { + Class clazz = handler.getClass(); + if(!clazz.isAnnotationPresent(Command.class)) + throw new IllegalArgumentException("Command handler must be annotated with @Command."); + Command commandData = clazz.getAnnotation(Command.class); + this.gameServer.getCommandMap().registerCommand(commandData.label(), handler); } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index 6997d0449..e77d9eb1c 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -30,6 +30,7 @@ import java.net.BindException; import java.net.InetSocketAddress; import java.net.URI; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.util.*; @@ -209,7 +210,7 @@ public final class DispatchServer { return null; } - private KeyManagerFactory createKeyManagerFactory(File keystore, String password) throws Exception { + private KeyManagerFactory createKeyManagerFactory(File keystore, String password) { char[] pass = password.toCharArray(); KeyManagerFactory kmf = null; @@ -220,8 +221,8 @@ public final class DispatchServer { kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, pass); - } catch (Exception e) { - throw e; + } catch (Exception exception) { + Grasscutter.getLogger().error("Unable to load keystore.", exception); } return kmf; @@ -243,10 +244,9 @@ public final class DispatchServer { try { kmf = createKeyManagerFactory(keystoreFile, "123456"); Grasscutter.getLogger().warn( - "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json."); + "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to '123456' in config.json."); } catch (Exception e2) { - Grasscutter.getLogger().warn("[Dispatch] Error while loading keystore!"); - e2.printStackTrace(); + Grasscutter.getLogger().warn("[Dispatch] Error while loading keystore!", e2); } } } @@ -257,7 +257,7 @@ public final class DispatchServer { server = this.safelyCreateServer(this.getAddress()); } - HttpsServer httpsServer = null; + HttpsServer httpsServer; try { httpsServer = HttpsServer.create(getAddress(), 0); @@ -339,10 +339,6 @@ public final class DispatchServer { // added. account = DatabaseHelper.createAccountWithId(requestData.account, 0); - for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { - account.addPermission(permission); - } - if (account != null) { responseData.message = "OK"; responseData.data.account.uid = account.getId(); @@ -352,6 +348,9 @@ public final class DispatchServer { Grasscutter.getLogger() .info(String.format("[Dispatch] Client %s failed to log in: Account %s created", t.getRemoteAddress(), responseData.data.account.uid)); + for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { + account.addPermission(permission); + } } else { responseData.retcode = -201; responseData.message = "Username not found, create failed."; @@ -575,15 +574,11 @@ public final class DispatchServer { if (next > last) { int eqPos = qs.indexOf('=', last); - try { - if (eqPos < 0 || eqPos > next) { - result.put(URLDecoder.decode(qs.substring(last, next), "utf-8"), ""); - } else { - result.put(URLDecoder.decode(qs.substring(last, eqPos), "utf-8"), - URLDecoder.decode(qs.substring(eqPos + 1, next), "utf-8")); - } - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); // will never happen, utf-8 support is mandatory for java + if (eqPos < 0 || eqPos > next) { + result.put(URLDecoder.decode(qs.substring(last, next), StandardCharsets.UTF_8), ""); + } else { + result.put(URLDecoder.decode(qs.substring(last, eqPos), StandardCharsets.UTF_8), + URLDecoder.decode(qs.substring(eqPos + 1, next), StandardCharsets.UTF_8)); } } last = next + 1; diff --git a/src/main/java/emu/grasscutter/server/event/EventHandler.java b/src/main/java/emu/grasscutter/server/event/EventHandler.java index d924933f2..6611b758c 100644 --- a/src/main/java/emu/grasscutter/server/event/EventHandler.java +++ b/src/main/java/emu/grasscutter/server/event/EventHandler.java @@ -1,11 +1,81 @@ package emu.grasscutter.server.event; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.utils.EventConsumer; -/** - * Declares a class as an event listener/handler. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface EventHandler { +public final class EventHandler { + private final Class eventClass; + private EventConsumer listener; + private HandlerPriority priority; + private boolean handleCanceled; + + public EventHandler(Class eventClass) { + this.eventClass = eventClass; + } + + /** + * Gets which event this handler is handling. + * @return An event class. + */ + public Class handles() { + return this.eventClass; + } + + /** + * Returns the callback for the handler. + * @return A consumer callback. + */ + public EventConsumer getCallback() { + return this.listener; + } + + /** + * Returns the handler's priority. + * @return The priority of the handler. + */ + public HandlerPriority getPriority() { + return this.priority; + } + + /** + * Returns if the handler will ignore cancelled events. + * @return The ignore cancelled state. + */ + public boolean ignoresCanceled() { + return this.handleCanceled; + } + + /** + * Sets the callback method for when the event is invoked. + * @param listener An event handler method. + * @return Method chaining. + */ + public EventHandler listener(EventConsumer listener) { + this.listener = listener; return this; + } + + /** + * Changes the handler's priority in handling events. + * @param priority The priority of the handler. + * @return Method chaining. + */ + public EventHandler priority(HandlerPriority priority) { + this.priority = priority; return this; + } + + /** + * Sets if the handler will ignore cancelled events. + * @param ignore If the handler should ignore cancelled events. + * @return Method chaining. + */ + public EventHandler ignore(boolean ignore) { + this.handleCanceled = ignore; return this; + } + + /** + * Registers the handler into the PluginManager. + */ + public void register() { + Grasscutter.getPluginManager().registerListener(this); + } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/event/HandlerPriority.java b/src/main/java/emu/grasscutter/server/event/HandlerPriority.java new file mode 100644 index 000000000..18891879f --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/HandlerPriority.java @@ -0,0 +1,18 @@ +package emu.grasscutter.server.event; + +public enum HandlerPriority { + /** + * The handler will be called before every other handler. + */ + HIGH, + + /** + * The handler will be called the same time as other handlers. + */ + NORMAL, + + /** + * The handler will be called after every other handler. + */ + LOW +} diff --git a/src/main/java/emu/grasscutter/server/event/Listener.java b/src/main/java/emu/grasscutter/server/event/Listener.java deleted file mode 100644 index 2949cfe4a..000000000 --- a/src/main/java/emu/grasscutter/server/event/Listener.java +++ /dev/null @@ -1,7 +0,0 @@ -package emu.grasscutter.server.event; - -/** - * Implementing this interface declares a class as an event listener. - */ -public interface Listener { -} diff --git a/src/main/java/emu/grasscutter/server/event/dispatch/QueryAllRegionsEvent.java b/src/main/java/emu/grasscutter/server/event/dispatch/QueryAllRegionsEvent.java index 8595f6221..bb4864692 100644 --- a/src/main/java/emu/grasscutter/server/event/dispatch/QueryAllRegionsEvent.java +++ b/src/main/java/emu/grasscutter/server/event/dispatch/QueryAllRegionsEvent.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.event.dispatch; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; public final class QueryAllRegionsEvent extends ServerEvent { private String regionList; diff --git a/src/main/java/emu/grasscutter/server/event/dispatch/QueryCurrentRegionEvent.java b/src/main/java/emu/grasscutter/server/event/dispatch/QueryCurrentRegionEvent.java index d6a20b2df..d963d74a7 100644 --- a/src/main/java/emu/grasscutter/server/event/dispatch/QueryCurrentRegionEvent.java +++ b/src/main/java/emu/grasscutter/server/event/dispatch/QueryCurrentRegionEvent.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.event.dispatch; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; public final class QueryCurrentRegionEvent extends ServerEvent { private String regionInfo; diff --git a/src/main/java/emu/grasscutter/server/event/game/PlayerCreationEvent.java b/src/main/java/emu/grasscutter/server/event/game/PlayerCreationEvent.java new file mode 100644 index 000000000..2049f4661 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/game/PlayerCreationEvent.java @@ -0,0 +1,27 @@ +package emu.grasscutter.server.event.game; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.types.GameEvent; +import emu.grasscutter.server.game.GameSession; + +public final class PlayerCreationEvent extends GameEvent { + private final GameSession session; + private Class playerClass; + + public PlayerCreationEvent(GameSession session, Class playerClass) { + this.session = session; + this.playerClass = playerClass; + } + + public GameSession getSession() { + return this.session; + } + + public void setPlayerClass(Class playerClass) { + this.playerClass = playerClass; + } + + public Class getPlayerClass() { + return this.playerClass; + } +} diff --git a/src/main/java/emu/grasscutter/server/event/game/ReceivePacketEvent.java b/src/main/java/emu/grasscutter/server/event/game/ReceivePacketEvent.java index 51109c720..e64a6305d 100644 --- a/src/main/java/emu/grasscutter/server/event/game/ReceivePacketEvent.java +++ b/src/main/java/emu/grasscutter/server/event/game/ReceivePacketEvent.java @@ -1,7 +1,7 @@ package emu.grasscutter.server.event.game; import emu.grasscutter.server.event.Cancellable; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; import emu.grasscutter.server.game.GameSession; public final class ReceivePacketEvent extends ServerEvent implements Cancellable { diff --git a/src/main/java/emu/grasscutter/server/event/game/SendPacketEvent.java b/src/main/java/emu/grasscutter/server/event/game/SendPacketEvent.java index b78e0d0c8..e5dd4982c 100644 --- a/src/main/java/emu/grasscutter/server/event/game/SendPacketEvent.java +++ b/src/main/java/emu/grasscutter/server/event/game/SendPacketEvent.java @@ -2,7 +2,7 @@ package emu.grasscutter.server.event.game; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.server.event.Cancellable; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; import emu.grasscutter.server.game.GameSession; public final class SendPacketEvent extends ServerEvent implements Cancellable { diff --git a/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java b/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java index 8ca7c8379..d1c12d02d 100644 --- a/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java +++ b/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.event.game; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; public final class ServerTickEvent extends ServerEvent { public ServerTickEvent() { diff --git a/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java b/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java index fd950a002..3a050d750 100644 --- a/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java +++ b/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.event.internal; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; import java.time.OffsetDateTime; diff --git a/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java b/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java index 5d105e3b3..c4e7ca8cf 100644 --- a/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java +++ b/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.event.internal; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; import java.time.OffsetDateTime; diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerJoinEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerJoinEvent.java new file mode 100644 index 000000000..59769c1c8 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerJoinEvent.java @@ -0,0 +1,11 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Cancellable; +import emu.grasscutter.server.event.types.PlayerEvent; + +public final class PlayerJoinEvent extends PlayerEvent implements Cancellable { + public PlayerJoinEvent(Player player) { + super(player); + } +} diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerQuitEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerQuitEvent.java new file mode 100644 index 000000000..4ac1b2f3b --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerQuitEvent.java @@ -0,0 +1,11 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.types.GameEvent; +import emu.grasscutter.server.event.types.PlayerEvent; + +public final class PlayerQuitEvent extends PlayerEvent { + public PlayerQuitEvent(Player player) { + super(player); + } +} diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerReceiveMailEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerReceiveMailEvent.java new file mode 100644 index 000000000..c38740ae4 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerReceiveMailEvent.java @@ -0,0 +1,24 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.mail.Mail; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Cancellable; +import emu.grasscutter.server.event.types.PlayerEvent; + +public final class PlayerReceiveMailEvent extends PlayerEvent implements Cancellable { + private Mail message; + + public PlayerReceiveMailEvent(Player player, Mail message) { + super(player); + + this.message = message; + } + + public void setMessage(Mail message) { + this.message = message; + } + + public Mail getMessage() { + return this.message; + } +} diff --git a/src/main/java/emu/grasscutter/server/event/types/GameEvent.java b/src/main/java/emu/grasscutter/server/event/types/GameEvent.java new file mode 100644 index 000000000..61c8daa73 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/types/GameEvent.java @@ -0,0 +1,10 @@ +package emu.grasscutter.server.event.types; + +import emu.grasscutter.server.event.Event; + +/** + * An event that is related to the game. + */ +public abstract class GameEvent extends Event { + +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/event/types/PlayerEvent.java b/src/main/java/emu/grasscutter/server/event/types/PlayerEvent.java new file mode 100644 index 000000000..eb55f2d58 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/types/PlayerEvent.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.event.types; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Event; + +/** + * An event that is related to player interactions. + */ +public abstract class PlayerEvent extends Event { + protected final Player player; + + public PlayerEvent(Player player) { + this.player = player; + } + + public Player getPlayer() { + return this.player; + } +} diff --git a/src/main/java/emu/grasscutter/server/event/ServerEvent.java b/src/main/java/emu/grasscutter/server/event/types/ServerEvent.java similarity index 80% rename from src/main/java/emu/grasscutter/server/event/ServerEvent.java rename to src/main/java/emu/grasscutter/server/event/types/ServerEvent.java index 5e73afdec..5191bbf22 100644 --- a/src/main/java/emu/grasscutter/server/event/ServerEvent.java +++ b/src/main/java/emu/grasscutter/server/event/types/ServerEvent.java @@ -1,4 +1,6 @@ -package emu.grasscutter.server.event; +package emu.grasscutter.server.event.types; + +import emu.grasscutter.server.event.Event; /** * An event that is related to the internals of the server. diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 9452b3993..c66a22e53 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -17,7 +17,7 @@ import emu.grasscutter.game.world.World; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.netty.KcpServer; -import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.types.ServerEvent; import emu.grasscutter.server.event.game.ServerTickEvent; import emu.grasscutter.server.event.internal.ServerStartEvent; import emu.grasscutter.server.event.internal.ServerStopEvent; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java index 9acd4f21b..cae0cce65 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -13,6 +13,7 @@ import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.SetPlayerBornDataReqOuterClass.SetPlayerBornDataReq; import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.server.event.game.PlayerCreationEvent; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession.SessionState; @@ -27,7 +28,7 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { // Sanity checks int avatarId = req.getAvatarId(); - int startingSkillDepot = 0; + int startingSkillDepot; if (avatarId == GameConstants.MAIN_CHARACTER_MALE) { startingSkillDepot = 504; } else if (avatarId == GameConstants.MAIN_CHARACTER_FEMALE) { @@ -41,8 +42,10 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { nickname = "Traveler"; } - // Create character - Player player = new Player(session); + // Call creation event. + PlayerCreationEvent event = new PlayerCreationEvent(session, Player.class); event.call(); + // Create player instance from event. + Player player = event.getPlayerClass().getDeclaredConstructor(GameSession.class).newInstance(session); player.setNickname(nickname); try { @@ -92,5 +95,4 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { session.close(); } } - } diff --git a/src/main/java/emu/grasscutter/task/TaskHandler.java b/src/main/java/emu/grasscutter/task/TaskHandler.java index ea6fe22cd..bf2b9850a 100644 --- a/src/main/java/emu/grasscutter/task/TaskHandler.java +++ b/src/main/java/emu/grasscutter/task/TaskHandler.java @@ -3,24 +3,12 @@ package emu.grasscutter.task; import org.quartz.*; @PersistJobDataAfterExecution -public class TaskHandler implements Job { - +public abstract class TaskHandler implements Job { public void restartExecute() throws JobExecutionException { execute(null); } - public void onEnable() { - - } - - public void onDisable() { - - } - - @Override - public void execute(JobExecutionContext context) throws JobExecutionException { - // TODO Auto-generated method stub - - } + public abstract void onEnable(); + public abstract void onDisable(); } diff --git a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java index 51088f46d..2d51151c1 100644 --- a/src/main/java/emu/grasscutter/task/tasks/MoonCard.java +++ b/src/main/java/emu/grasscutter/task/tasks/MoonCard.java @@ -4,22 +4,21 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.task.Task; import emu.grasscutter.task.TaskHandler; - import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @Task(taskName = "MoonCard", taskCronExpression = "0 0 0 * * ?", triggerName = "MoonCardTrigger") // taskCronExpression: Fixed time period: 0:0:0 every day (twenty-four hour system) -public class MoonCard extends TaskHandler { +public final class MoonCard extends TaskHandler { @Override public void onEnable() { - Grasscutter.getLogger().info("[Task] MoonCard task enabled."); + Grasscutter.getLogger().debug("[Task] MoonCard task enabled."); } @Override public void onDisable() { - Grasscutter.getLogger().info("[Task] MoonCard task disabled."); + Grasscutter.getLogger().debug("[Task] MoonCard task disabled."); } @Override diff --git a/src/main/java/emu/grasscutter/utils/EventConsumer.java b/src/main/java/emu/grasscutter/utils/EventConsumer.java new file mode 100644 index 000000000..baa531944 --- /dev/null +++ b/src/main/java/emu/grasscutter/utils/EventConsumer.java @@ -0,0 +1,7 @@ +package emu.grasscutter.utils; + +import emu.grasscutter.server.event.Event; + +public interface EventConsumer { + void consume(T event); +}