diff --git a/.gitignore b/.gitignore index 8422b6e18..ebb48dcaa 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,9 @@ hs_err_pid* build/ out/ +# Ignore Gradle properties +gradle.properties + # Eclipse .project .classpath diff --git a/build.gradle b/build.gradle index 9f5fe4775..1be86626c 100644 --- a/build.gradle +++ b/build.gradle @@ -12,11 +12,22 @@ plugins { // Apply the application plugin to add support for building a CLI application id 'application' + + id 'maven-publish' + id 'signing' } +group = 'tech.xigam' +version = '1.0.0-dev' + sourceCompatibility = 17 targetCompatibility = 17 +java { + withJavadocJar() + withSourcesJar() +} + repositories { mavenCentral() } @@ -65,3 +76,68 @@ jar { destinationDir = file(".") } +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'grasscutter' + from components.java + versionMapping { + usage('java-api') { + fromResolutionOf('runtimeClasspath') + } + usage('java-runtime') { + fromResolutionResult() + } + } + pom { + name = 'Grasscutter' + description = 'A server software reimplementation for an anime game.' + url = 'https://github.com/Grasscutters/Grasscutter' + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + developers { + developer { + id = 'melledy' + name = 'Melledy' + email = 'melledy@xigam.tech' // not a real email kek + } + developer { + id = 'magix' + name = 'Magix' + email = 'magix@xigam.tech' + } + } + scm { + connection = 'scm:git:git@github.com:Grasscutters/Grasscutter.git' + developerConnection = 'scm:git:ssh://github.com:Grasscutters/Grasscutter.git' + url = 'https://github.com/Grasscutters/Grasscutter' + } + } + } + } + repositories { + maven { + // change URLs to point to your repos, e.g. http://my.org/repo + def releasesRepoUrl = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/' + def snapshotsRepoUrl = 'https://s01.oss.sonatype.org/content/repositories/snapshots/' + url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + + name = 'sonatype' + credentials(PasswordCredentials) + } + } +} + +signing { + sign publishing.publications.mavenJava +} + +javadoc { + if(JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 8246588ae..dcd6a3b6f 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -36,7 +36,7 @@ public final class Grasscutter { private static GameServer gameServer; private static PluginManager pluginManager; - public static final Reflections reflector = new Reflections(); + public static final Reflections reflector = new Reflections("emu.grasscutter"); static { // Declare logback configuration. @@ -70,13 +70,13 @@ public final class Grasscutter { // Database DatabaseManager.initialize(); + // Create plugin manager instance. + pluginManager = new PluginManager(); + // Create server instances. dispatchServer = new DispatchServer(); gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port)); - // Create plugin manager instance. - pluginManager = new PluginManager(); - // Start servers. if(getConfig().RunMode.equalsIgnoreCase("HYBRID")) { dispatchServer.start(); diff --git a/src/main/java/emu/grasscutter/command/commands/ClearCommand.java b/src/main/java/emu/grasscutter/command/commands/ClearCommand.java index 8d16e58c1..fc6295253 100644 --- a/src/main/java/emu/grasscutter/command/commands/ClearCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/ClearCommand.java @@ -3,15 +3,10 @@ package emu.grasscutter.command.commands; import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; -import emu.grasscutter.data.GenshinData; -import emu.grasscutter.data.def.ItemData; import emu.grasscutter.game.GenshinPlayer; -import emu.grasscutter.game.inventory.GenshinItem; import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.inventory.ItemType; -import java.util.Collection; -import java.util.LinkedList; import java.util.List; @Command(label = "clear", usage = "clear ", //Merged /clearartifacts and /clearweapons to /clear [uid] @@ -33,62 +28,62 @@ public final class ClearCommand implements CommandHandler { try { target = Integer.parseInt(args.get(0)); GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target); - if (targetPlayer == null && sender != null) { + if (targetPlayer == null) { target = sender.getUid(); } else { - switch (cmdSwitch){ - case "wp": + switch (cmdSwitch) { + case "wp" -> { playerInventory.getItems().values().stream() - .filter(item -> item.getItemType() == ItemType.ITEM_WEAPON) - .filter(item -> !item.isLocked() && !item.isEquipped()) - .forEach(item -> playerInventory.removeItem(item, item.getCount())); + .filter(item -> item.getItemType() == ItemType.ITEM_WEAPON) + .filter(item -> !item.isLocked() && !item.isEquipped()) + .forEach(item -> playerInventory.removeItem(item, item.getCount())); sender.dropMessage("Cleared weapons for " + targetPlayer.getNickname() + " ."); - break; - case "art": + } + case "art" -> { playerInventory.getItems().values().stream() - .filter(item -> item.getItemType() == ItemType.ITEM_RELIQUARY) - .filter(item -> item.getLevel() == 1 && item.getExp() == 0) - .filter(item -> !item.isLocked() && !item.isEquipped()) - .forEach(item -> playerInventory.removeItem(item, item.getCount())); + .filter(item -> item.getItemType() == ItemType.ITEM_RELIQUARY) + .filter(item -> item.getLevel() == 1 && item.getExp() == 0) + .filter(item -> !item.isLocked() && !item.isEquipped()) + .forEach(item -> playerInventory.removeItem(item, item.getCount())); sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " ."); - break; - case "mat": + } + case "mat" -> { playerInventory.getItems().values().stream() - .filter(item -> item.getItemType() == ItemType.ITEM_MATERIAL) - .filter(item -> item.getLevel() == 1 && item.getExp() == 0) - .filter(item -> !item.isLocked() && !item.isEquipped()) - .forEach(item -> playerInventory.removeItem(item, item.getCount())); + .filter(item -> item.getItemType() == ItemType.ITEM_MATERIAL) + .filter(item -> item.getLevel() == 1 && item.getExp() == 0) + .filter(item -> !item.isLocked() && !item.isEquipped()) + .forEach(item -> playerInventory.removeItem(item, item.getCount())); sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " ."); - break; - case "all": + } + case "all" -> { playerInventory.getItems().values().stream() - .filter(item1 -> item1.getItemType() == ItemType.ITEM_RELIQUARY) - .filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0) - .filter(item1 -> !item1.isLocked() && !item1.isEquipped()) - .forEach(item1 -> playerInventory.removeItem(item1, item1.getCount())); + .filter(item1 -> item1.getItemType() == ItemType.ITEM_RELIQUARY) + .filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0) + .filter(item1 -> !item1.isLocked() && !item1.isEquipped()) + .forEach(item1 -> playerInventory.removeItem(item1, item1.getCount())); playerInventory.getItems().values().stream() - .filter(item2 -> item2.getItemType() == ItemType.ITEM_MATERIAL) - .filter(item2 -> !item2.isLocked() && !item2.isEquipped()) - .forEach(item2 -> playerInventory.removeItem(item2, item2.getCount())); + .filter(item2 -> item2.getItemType() == ItemType.ITEM_MATERIAL) + .filter(item2 -> !item2.isLocked() && !item2.isEquipped()) + .forEach(item2 -> playerInventory.removeItem(item2, item2.getCount())); playerInventory.getItems().values().stream() - .filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON) - .filter(item3 -> item3.getLevel() == 1 && item3.getExp() == 0) - .filter(item3 -> !item3.isLocked() && !item3.isEquipped()) - .forEach(item3 -> playerInventory.removeItem(item3, item3.getCount())); + .filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON) + .filter(item3 -> item3.getLevel() == 1 && item3.getExp() == 0) + .filter(item3 -> !item3.isLocked() && !item3.isEquipped()) + .forEach(item3 -> playerInventory.removeItem(item3, item3.getCount())); playerInventory.getItems().values().stream() - .filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE) - .filter(item4 -> !item4.isLocked() && !item4.isEquipped()) - .forEach(item4 -> playerInventory.removeItem(item4, item4.getCount())); + .filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE) + .filter(item4 -> !item4.isLocked() && !item4.isEquipped()) + .forEach(item4 -> playerInventory.removeItem(item4, item4.getCount())); playerInventory.getItems().values().stream() - .filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY) - .filter(item5 -> !item5.isLocked() && !item5.isEquipped()) - .forEach(item5 -> playerInventory.removeItem(item5, item5.getCount())); + .filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY) + .filter(item5 -> !item5.isLocked() && !item5.isEquipped()) + .forEach(item5 -> playerInventory.removeItem(item5, item5.getCount())); playerInventory.getItems().values().stream() - .filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL) - .filter(item6 -> !item6.isLocked() && !item6.isEquipped()) - .forEach(item6 -> playerInventory.removeItem(item6, item6.getCount())); + .filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL) + .filter(item6 -> !item6.isLocked() && !item6.isEquipped()) + .forEach(item6 -> playerInventory.removeItem(item6, item6.getCount())); sender.dropMessage("Cleared everything for " + targetPlayer.getNickname() + " ."); - break; + } } } } catch (NumberFormatException ignored) { diff --git a/src/main/java/emu/grasscutter/command/commands/HealCommand.java b/src/main/java/emu/grasscutter/command/commands/HealCommand.java index 511e52812..27511e527 100644 --- a/src/main/java/emu/grasscutter/command/commands/HealCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/HealCommand.java @@ -6,20 +6,19 @@ import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; -import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; -import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; import java.util.List; -@Command(label = "heal", usage = "heal|h", - description = "Heal all characters in your current team.", aliases = {"h"}, permission = "player.heal") -public class HealCommand implements CommandHandler { +@Command(label = "heal", usage = "heal|h", aliases = {"h"}, + description = "Heal all characters in your current team.", permission = "player.heal") +public final class HealCommand implements CommandHandler { @Override public void execute(GenshinPlayer sender, List args) { if (sender == null) { CommandHandler.sendMessage(null, "Run this command in-game."); return; } + sender.getTeamManager().getActiveTeam().forEach(entity -> { boolean isAlive = entity.isAlive(); entity.setFightProperty( @@ -31,6 +30,6 @@ public class HealCommand implements CommandHandler { entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); } }); - CommandHandler.sendMessage(sender, "All characters are healed."); + CommandHandler.sendMessage(sender, "All characters have been healed."); } } diff --git a/src/main/java/emu/grasscutter/command/commands/ListCommand.java b/src/main/java/emu/grasscutter/command/commands/ListCommand.java index 6afca4a6d..1fb7f0eed 100644 --- a/src/main/java/emu/grasscutter/command/commands/ListCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/ListCommand.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.Map; @Command(label = "list", description = "List online players") -public class ListCommand implements CommandHandler { +public final class ListCommand implements CommandHandler { @Override public void execute(GenshinPlayer sender, List args) { @@ -19,14 +19,10 @@ public class ListCommand implements CommandHandler { if (playersMap.size() != 0) { StringBuilder playerSet = new StringBuilder(); - - for (Map.Entry entry : playersMap.entrySet()) { - playerSet.append(entry.getValue().getNickname()); - playerSet.append(", "); - } - + playersMap.values().forEach(player -> + playerSet.append(player.getNickname()).append(", ")); + String players = playerSet.toString(); - CommandHandler.sendMessage(sender, players.substring(0, players.length() - 2)); } } diff --git a/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java b/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java index 676a2b279..565a480dc 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetFetterLevelCommand.java @@ -43,7 +43,7 @@ public final class SetFetterLevelCommand implements CommandHandler { sender.sendPacket(new PacketAvatarFetterDataNotify(avatar)); CommandHandler.sendMessage(sender, "Fetter level set to " + fetterLevel); } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(null, "Invalid fetter level."); + CommandHandler.sendMessage(sender, "Invalid fetter level."); } } diff --git a/src/main/java/emu/grasscutter/command/commands/TalentCommand.java b/src/main/java/emu/grasscutter/command/commands/TalentCommand.java index 21cf66249..59fc83226 100644 --- a/src/main/java/emu/grasscutter/command/commands/TalentCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TalentCommand.java @@ -13,7 +13,7 @@ import java.util.List; @Command(label = "talent", usage = "talent ", description = "Set talent level for your current active character", permission = "player.settalent") -public class TalentCommand implements CommandHandler { +public final class TalentCommand implements CommandHandler { @Override public void execute(GenshinPlayer sender, List args) { diff --git a/src/main/java/emu/grasscutter/command/commands/TelePortCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java similarity index 97% rename from src/main/java/emu/grasscutter/command/commands/TelePortCommand.java rename to src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index 84848afa5..6b08fb333 100644 --- a/src/main/java/emu/grasscutter/command/commands/TelePortCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -9,7 +9,7 @@ import java.util.List; @Command(label = "teleport", usage = "teleport ", aliases = {"tp"}, description = "Change the player's position.", permission = "player.teleport") -public class TelePortCommand implements CommandHandler { +public final class TeleportCommand implements CommandHandler { @Override public void execute(GenshinPlayer sender, List args) { diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java index 079f0dda3..ffb68a1d7 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaManager.java @@ -286,8 +286,6 @@ public class GachaManager { this.watchService = FileSystems.getDefault().newWatchService(); Path path = new File(Grasscutter.getConfig().DATA_FOLDER).toPath(); path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH); - - server.OnGameServerTick.register(this); } catch (Exception e) { Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload"); e.printStackTrace(); diff --git a/src/main/java/emu/grasscutter/plugin/api/Item.java b/src/main/java/emu/grasscutter/plugin/api/Item.java new file mode 100644 index 000000000..91b1a8a5c --- /dev/null +++ b/src/main/java/emu/grasscutter/plugin/api/Item.java @@ -0,0 +1,5 @@ +package emu.grasscutter.plugin.api; + +public enum Item { + /* TODO: Use handbook to generate an Item enum. */ +} diff --git a/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java b/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java new file mode 100644 index 000000000..f4a479acb --- /dev/null +++ b/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java @@ -0,0 +1,113 @@ +package emu.grasscutter.plugin.api; + +import emu.grasscutter.game.GenshinPlayer; +import emu.grasscutter.game.avatar.GenshinAvatar; +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.props.EnterReason; +import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.net.packet.GenshinPacket; +import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; +import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; +import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; +import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify; +import emu.grasscutter.utils.Position; + +/** + * Hooks into the {@link GenshinPlayer} class, adding convenient ways to do certain things. + */ +public final class PlayerHook { + private final GenshinPlayer player; + + /** + * Hooks into the player. + * @param player The player to hook into. + */ + public PlayerHook(GenshinPlayer player) { + this.player = player; + } + + /** + * Kicks a player from the server. + */ + public void kick() { + this.player.getSession().close(); + } + + /** + * Sends a player to another scene. + * @param sceneId The scene to send the player to. + */ + public void changeScenes(int sceneId) { + this.player.getWorld().transferPlayerToScene(this.player, sceneId, this.player.getPos()); + } + + /** + * Broadcasts an avatar property notify to all world players. + * @param property The property that was updated. + */ + public void updateFightProperty(FightProperty property) { + this.broadcastPacketToWorld(new PacketAvatarFightPropUpdateNotify(this.getCurrentAvatar(), property)); + } + + /** + * Broadcasts the packet sent to all world players. + * @param packet The packet to send. + */ + public void broadcastPacketToWorld(GenshinPacket packet) { + this.player.getWorld().broadcastPacket(packet); + } + + /** + * Set the currently equipped avatar's health. + * @param health The health to set the avatar to. + */ + public void setHealth(float health) { + this.getCurrentAvatarEntity().setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, health); + this.updateFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + } + + /** + * Revives the specified avatar. + * @param avatar The avatar to revive. + */ + public void reviveAvatar(GenshinAvatar avatar) { + this.broadcastPacketToWorld(new PacketAvatarLifeStateChangeNotify(avatar)); + } + + /** + * Teleports a player to a position. + * This will **not** transfer the player to another scene. + * @param position The position to teleport the player to. + */ + public void teleport(Position position) { + this.player.getPos().set(position); + this.player.sendPacket(new PacketPlayerEnterSceneNotify(this.player, + EnterType.EnterJump, EnterReason.TransPoint, + this.player.getSceneId(), position + )); + } + + /** + * Gets the currently selected avatar's max health. + * @return The max health as a float. + */ + public float getMaxHealth() { + return this.getCurrentAvatarEntity().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + } + + /** + * Gets the currently selected avatar in entity form. + * @return The avatar as an {@link EntityAvatar}. + */ + public EntityAvatar getCurrentAvatarEntity() { + return this.player.getTeamManager().getCurrentAvatarEntity(); + } + + /** + * Gets the currently selected avatar. + * @return The avatar as an {@link GenshinAvatar}. + */ + public GenshinAvatar getCurrentAvatar() { + return this.getCurrentAvatarEntity().getAvatar(); + } +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/plugin/api/README.md b/src/main/java/emu/grasscutter/plugin/api/README.md new file mode 100644 index 000000000..73a5a75ee --- /dev/null +++ b/src/main/java/emu/grasscutter/plugin/api/README.md @@ -0,0 +1,2 @@ +# Grasscutter Plugin API +**Warning!** As of now, this is a work in progress and isn't completely documented. \ 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 new file mode 100644 index 000000000..34ceb25f4 --- /dev/null +++ b/src/main/java/emu/grasscutter/plugin/api/ServerHook.java @@ -0,0 +1,41 @@ +package emu.grasscutter.plugin.api; + +import emu.grasscutter.game.GenshinPlayer; +import emu.grasscutter.server.game.GameServer; + +import java.util.LinkedList; +import java.util.List; + +/** + * Hooks into the {@link GameServer} class, adding convenient ways to do certain things. + */ +public final class ServerHook { + private static ServerHook instance; + private final GameServer server; + + /** + * Gets the server hook instance. + * @return A {@link ServerHook} singleton. + */ + public static ServerHook getInstance() { + return instance; + } + + /** + * Hooks into a server. + * @param server The server to hook into. + */ + public ServerHook(GameServer server) { + this.server = server; + + instance = this; + } + + /** + * Gets all online players. + * @return Players connected to the server. + */ + public List getOnlinePlayers() { + return new LinkedList<>(this.server.getPlayers().values()); + } +} \ 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 1daa1f6ef..e8caaaea8 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -103,8 +103,8 @@ public final class DispatchServer { byte[] decoded2 = Base64.getDecoder().decode(query_cur_region); QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRsp.parseFrom(decoded2); - List servers = new ArrayList(); - List usedNames = new ArrayList(); // List to check for potential naming conflicts + List servers = new ArrayList<>(); + List usedNames = new ArrayList<>(); // List to check for potential naming conflicts if (Grasscutter.getConfig().RunMode.equalsIgnoreCase("HYBRID")) { // Automatically add the game server if in // hybrid mode RegionSimpleInfo server = RegionSimpleInfo.newBuilder() @@ -268,7 +268,10 @@ public final class DispatchServer { Grasscutter.getLogger() .info(String.format("[Dispatch] Client %s request: query_region_list", t.getRemoteAddress())); - responseHTML(t, regionListBase64); + // Invoke event. + QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListBase64); event.call(); + // Respond with event result. + responseHTML(t, event.getRegionList()); }); for (String regionName : regions.keySet()) { diff --git a/src/main/java/emu/grasscutter/server/event/ServerEvent.java b/src/main/java/emu/grasscutter/server/event/ServerEvent.java index e87abae0d..5e73afdec 100644 --- a/src/main/java/emu/grasscutter/server/event/ServerEvent.java +++ b/src/main/java/emu/grasscutter/server/event/ServerEvent.java @@ -10,6 +10,10 @@ public abstract class ServerEvent extends Event { this.type = type; } + public Type getServerType() { + return this.type; + } + public enum Type { DISPATCH, GAME diff --git a/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java b/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java new file mode 100644 index 000000000..8ca7c8379 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java @@ -0,0 +1,9 @@ +package emu.grasscutter.server.event.game; + +import emu.grasscutter.server.event.ServerEvent; + +public final class ServerTickEvent extends ServerEvent { + public ServerTickEvent() { + super(Type.GAME); + } +} diff --git a/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java b/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java new file mode 100644 index 000000000..fd950a002 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.event.internal; + +import emu.grasscutter.server.event.ServerEvent; + +import java.time.OffsetDateTime; + +public final class ServerStartEvent extends ServerEvent { + private final OffsetDateTime startTime; + + public ServerStartEvent(Type type, OffsetDateTime startTime) { + super(type); + + this.startTime = startTime; + } + + public OffsetDateTime getStartTime() { + return this.startTime; + } +} diff --git a/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java b/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java new file mode 100644 index 000000000..5d105e3b3 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.event.internal; + +import emu.grasscutter.server.event.ServerEvent; + +import java.time.OffsetDateTime; + +public final class ServerStopEvent extends ServerEvent { + private final OffsetDateTime stopTime; + + public ServerStopEvent(Type type, OffsetDateTime stopTime) { + super(type); + + this.stopTime = stopTime; + } + + public OffsetDateTime getStopTime() { + return this.stopTime; + } +} diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 905317e9a..b37b24f33 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -1,6 +1,7 @@ package emu.grasscutter.server.game; import java.net.InetSocketAddress; +import java.time.OffsetDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -20,7 +21,10 @@ import emu.grasscutter.game.shop.ShopManager; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.netty.MihoyoKcpServer; -import org.greenrobot.eventbus.EventBus; +import emu.grasscutter.server.event.ServerEvent; +import emu.grasscutter.server.event.game.ServerTickEvent; +import emu.grasscutter.server.event.internal.ServerStartEvent; +import emu.grasscutter.server.event.internal.ServerStopEvent; public final class GameServer extends MihoyoKcpServer { private final InetSocketAddress address; @@ -36,18 +40,10 @@ public final class GameServer extends MihoyoKcpServer { private final MultiplayerManager multiplayerManager; private final DungeonManager dungeonManager; private final CommandMap commandMap; - - public EventBus OnGameServerStartFinish; - public EventBus OnGameServerTick; - public EventBus OnGameServerStop; public GameServer(InetSocketAddress address) { super(address); - OnGameServerStartFinish = EventBus.builder().throwSubscriberException(true).logNoSubscriberMessages(false).build(); - OnGameServerTick = EventBus.builder().throwSubscriberException(true).logNoSubscriberMessages(false).build(); - OnGameServerStop = EventBus.builder().throwSubscriberException(true).logNoSubscriberMessages(false).build(); - this.setServerInitializer(new GameServerInitializer(this)); this.address = address; this.packetHandler = new GameServerPacketHandler(PacketHandler.class); @@ -178,12 +174,8 @@ public final class GameServer extends MihoyoKcpServer { world.onTick(); } - - for (GenshinPlayer player : this.getPlayers().values()) { - player.onTick(); - } - - OnGameServerTick.post(new GameServerTickEvent()); + + ServerTickEvent event = new ServerTickEvent(); event.call(); } public void registerWorld(World world) { @@ -198,12 +190,11 @@ public final class GameServer extends MihoyoKcpServer { @Override public void onStartFinish() { Grasscutter.getLogger().info("Game Server started on port " + address.getPort()); - - OnGameServerStartFinish.post(new GameServerStartFinishEvent()); + ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call(); } public void onServerShutdown() { - OnGameServerStop.post(new GameServerStopEvent()); + ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call(); // Kick and save all players List list = new ArrayList<>(this.getPlayers().size());