From 9af4cc244667fdbfbdc5056082dd0783bae4acdb Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 00:04:03 -0400 Subject: [PATCH 1/8] Refactor classes --- .../grasscutter/command/commands/HealCommand.java | 11 +++++------ .../grasscutter/command/commands/ListCommand.java | 12 ++++-------- .../grasscutter/command/commands/TalentCommand.java | 2 +- .../{TelePortCommand.java => TeleportCommand.java} | 2 +- .../grasscutter/server/dispatch/DispatchServer.java | 4 ++-- 5 files changed, 13 insertions(+), 18 deletions(-) rename src/main/java/emu/grasscutter/command/commands/{TelePortCommand.java => TeleportCommand.java} (97%) 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/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/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index 5cb06d5e1..fe8e79abc 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -98,8 +98,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() From 779ea8cdb166065ee1ad7396dd86168531e6bda3 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 00:39:05 -0400 Subject: [PATCH 2/8] Fix command issue --- src/main/java/emu/grasscutter/Grasscutter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 8246588ae..3db73eb1b 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. From f176408d417dd93bcce266a9ee9c57198a166996 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 00:39:30 -0400 Subject: [PATCH 3/8] Bug fix & Cleanup --- .../command/commands/ClearCommand.java | 87 +++++++++---------- .../commands/SetFetterLevelCommand.java | 2 +- 2 files changed, 42 insertions(+), 47 deletions(-) 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/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."); } } From 9ee8974feaca45381b47700c624eeb274a222300 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 00:39:43 -0400 Subject: [PATCH 4/8] Begin on plugin API --- .../java/emu/grasscutter/plugin/api/Item.java | 5 + .../grasscutter/plugin/api/PlayerHook.java | 113 ++++++++++++++++++ .../java/emu/grasscutter/plugin/api/README.md | 2 + 3 files changed, 120 insertions(+) create mode 100644 src/main/java/emu/grasscutter/plugin/api/Item.java create mode 100644 src/main/java/emu/grasscutter/plugin/api/PlayerHook.java create mode 100644 src/main/java/emu/grasscutter/plugin/api/README.md 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 From 3f8e1ea9d2709820f652d448af22ab270ddf441b Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 00:45:42 -0400 Subject: [PATCH 5/8] Reimplement the region list event --- .../java/emu/grasscutter/server/dispatch/DispatchServer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index fe8e79abc..2cb3808fb 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -264,7 +264,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()) { From 9fd5aef687c22100a70b6c01d5291c1338f3decc Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 02:07:00 -0400 Subject: [PATCH 6/8] Add more events --- .../java/emu/grasscutter/Grasscutter.java | 6 +-- .../grasscutter/game/gacha/GachaManager.java | 2 - .../grasscutter/plugin/api/ServerHook.java | 41 +++++++++++++++++++ .../grasscutter/server/event/ServerEvent.java | 4 ++ .../server/event/game/ServerTickEvent.java | 9 ++++ .../event/internal/ServerStartEvent.java | 19 +++++++++ .../event/internal/ServerStopEvent.java | 19 +++++++++ .../grasscutter/server/game/GameServer.java | 23 ++++------- 8 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 src/main/java/emu/grasscutter/plugin/api/ServerHook.java create mode 100644 src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java create mode 100644 src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java create mode 100644 src/main/java/emu/grasscutter/server/event/internal/ServerStopEvent.java diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 3db73eb1b..dcd6a3b6f 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -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/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/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/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 065344ee2..a1986d1a2 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; @@ -19,7 +20,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; @@ -34,18 +38,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); @@ -160,23 +156,22 @@ public final class GameServer extends MihoyoKcpServer { return DatabaseHelper.getAccountByName(username); } - public void onTick() throws Exception { + public void onTick() { for (GenshinPlayer player : this.getPlayers().values()) { player.onTick(); } - OnGameServerTick.post(new GameServerTickEvent()); + ServerTickEvent event = new ServerTickEvent(); event.call(); } @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()); From 27378f0788ba1a7f789daa4275320ffe215873a7 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 11:13:25 -0400 Subject: [PATCH 7/8] Publish to Maven central --- build.gradle | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/build.gradle b/build.gradle index bf839316a..fccaa9b68 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() } @@ -64,3 +75,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 From 9809b6b31d7ba9674f7623a8c3316c4f8cfd562e Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Tue, 26 Apr 2022 11:14:39 -0400 Subject: [PATCH 8/8] Ignore `gradle.properties` --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) 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