From d9441a2188ebe6dfd766092dc8ce94f5fab66a5a Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Wed, 27 Apr 2022 11:37:50 +0200 Subject: [PATCH 01/21] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d32e1ca9e..690b7cd5d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ EN | [中文](README_zh-CN.md) * Friends list * Teleportation * Gacha system -* Co-op *partially* work +* Co-op *partially* works * Spawning monsters via console * Inventory features (recieving items/characters, upgrading items/characters, etc) @@ -140,9 +140,11 @@ There is a dummy user named "Server" in every player's friends list that you can When you want to teleport to somewhere, use the ingame marking function on Map, click Confirm. You will see your character falling from a very high destination, exact location that you marked. +You can also specify a set Y coordinate by renaming the map marker. + # Quick Troubleshooting * If compiling wasn't successful, please check your JDK installation (JDK 17 and validated JDK's bin PATH variable) * My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*, if using Fiddler make sure it running on another port except 8888 -* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Client +* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Genshin Impact Client From 8d1c571c0c27a598815d433f75c08cbe0a2c27a0 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Wed, 27 Apr 2022 13:20:57 +0200 Subject: [PATCH 02/21] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 690b7cd5d..16d5fc8f8 100644 --- a/README.md +++ b/README.md @@ -147,4 +147,4 @@ You can also specify a set Y coordinate by renaming the map marker. * If compiling wasn't successful, please check your JDK installation (JDK 17 and validated JDK's bin PATH variable) * My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*, if using Fiddler make sure it running on another port except 8888 -* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Genshin Impact Client +* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Game From 74ad63573a97cdf9447af3422ade011b2da45afb Mon Sep 17 00:00:00 2001 From: xtaodada Date: Fri, 29 Apr 2022 17:53:42 +0800 Subject: [PATCH 03/21] Support Teleport from console --- README.md | 6 +-- README_zh-CN.md | 4 +- .../command/commands/TeleportCommand.java | 49 +++++++++++++------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 909aa6cc5..cbc09ea3e 100644 --- a/README.md +++ b/README.md @@ -114,8 +114,8 @@ There is a dummy user named "Server" in every player's friends list that you can | clearweapons | clearweapons | player.clearweapons | Client only | Deletes all unequipped and unlocked weapons, including 5-star rarity ones from your inventory. | clearwpns | | drop | drop [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` | | give | give [player] [amount] [level] | player.give | Both side | Gives item(s) to you or the specified player. | `g` `item` `giveitem` | -| givechar | givechar | player.givechar | Both side | Gives the player a specified character. | givec | -| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea | +| givechar | givechar | player.givechar | Both side | Gives the player a specified character. | givec | +| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea | | godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | | | heal | heal | player.heal | Client only | Heals all characters in your current team. | h | | help | help [command] | | Both side | Sends the help message or shows information about a specified command. | | @@ -134,7 +134,7 @@ There is a dummy user named "Server" in every player's friends list that you can | spawn | spanw [level] [amount] | server.spawn | Client only | Spawns an entity near you | | | stop | stop | server.stop | Both side | Stops the server | | | talent | talent | player.settalent | Client only | Sets talent level for your currently selected character | | -| teleport | teleport | player.teleport | Client only | Change the player's position. | tp | +| teleport | teleport [@player id] [scene id] | player.teleport | Both side | Change the player's position. | tp | | tpall | | player.tpall | Client only | Teleports all players in your world to your position | | | weather | weather | player.weather | Client only | Changes the weather | w | diff --git a/README_zh-CN.md b/README_zh-CN.md index 97f332f3a..1d19117e5 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -105,7 +105,7 @@ chmod +x gradlew 在每个玩家的朋友列表中都有一个名为“服务器”的虚拟用户,你可以通过发送消息来使用命令。命令也适用于其他聊天室,例如私人/团队聊天。 要在游戏中使用命令,需要添加 `/` 或 `!` 前缀,如 `/pos` -| 命令 | 用法 | 权限节点 | 可用性 | 注释 | 别名 | +| 命令 | 用法 | 权限节点 | 可用性 | 注释 | 别名 | | -------------- | -------------------------------------------- | ------------------------- | -------- | ------------------------------------------ | ----------------------------------------------- | | account | account <用户名> [uid] | | 仅服务端 | 通过指定用户名和uid增删账户 | | | broadcast | broadcast <消息内容> | server.broadcast | 均可使用 | 给所有玩家发送公告 | b | @@ -135,7 +135,7 @@ chmod +x gradlew | spawn | spanw <实体ID\|实体名称> [等级] [数量] | server.spawn | 仅客户端 | 在你周围生成实体 | | | stop | stop | server.stop | 均可使用 | 停止服务器 | | | talent | talent <天赋ID> <等级> | player.settalent | 仅客户端 | 设置当前角色的天赋等级 | | -| teleport | teleport | player.teleport | 仅客户端 | 传送玩家到指定坐标 | tp | +| teleport | teleport [@player id] [scene id] | player.teleport | 均可使用 | 传送玩家到指定坐标 | tp | | tpall | | player.tpall | 仅客户端 | 传送多人世界中所有的玩家到自身地点 | | | weather | weather <天气ID> <气候ID> | player.weather | 仅客户端 | 改变天气 | w | diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index c478118e3..238dccfa1 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -1,5 +1,6 @@ package emu.grasscutter.command.commands; +import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; import emu.grasscutter.game.player.Player; @@ -7,21 +8,39 @@ import emu.grasscutter.utils.Position; import java.util.List; -@Command(label = "teleport", usage = "teleport ", aliases = {"tp"}, +@Command(label = "teleport", usage = "teleport [@player id] [scene id]", aliases = {"tp"}, description = "Change the player's position.", permission = "player.teleport") public final class TeleportCommand implements CommandHandler { @Override public void execute(Player sender, List args) { - if (sender == null) { - CommandHandler.sendMessage(null, "Run this command in-game."); + int target; + if (args.size() < (sender == null ? 4 : 3)) { + CommandHandler.sendMessage(sender, sender == null ? "Usage: /tp @ [scene id]" : + "Usage: /tp [@] [scene id]"); return; } + if (args.get(0).startsWith("@")) { + try { + target = Integer.parseInt(args.get(0).substring(1)); + } catch (NumberFormatException e) { + CommandHandler.sendMessage(sender, "Invalid player id."); + return; + } + } else { + if (sender == null) { + CommandHandler.sendMessage(null, "You must specify a player id."); + return; + } + target = sender.getUid(); + } - if (args.size() < 3){ - CommandHandler.sendMessage(sender, "Usage: /tp [scene id]"); + Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target); + if (targetPlayer == null) { + CommandHandler.sendMessage(sender, "Player not found or offline."); return; } + args = args.subList(args.get(0).startsWith("@") ? 1 : 0, args.size()); try { float x = 0f; @@ -29,39 +48,41 @@ public final class TeleportCommand implements CommandHandler { float z = 0f; if (args.get(0).contains("~")) { if (args.get(0).equals("~")) { - x = sender.getPos().getX(); + x = targetPlayer.getPos().getX(); } else { - x = Float.parseFloat(args.get(0).replace("~", "")) + sender.getPos().getX(); + x = Float.parseFloat(args.get(0).replace("~", "")) + targetPlayer.getPos().getX(); } } else { x = Float.parseFloat(args.get(0)); } if (args.get(1).contains("~")) { if (args.get(1).equals("~")) { - y = sender.getPos().getY(); + y = targetPlayer.getPos().getY(); } else { - y = Float.parseFloat(args.get(1).replace("~", "")) + sender.getPos().getY(); + y = Float.parseFloat(args.get(1).replace("~", "")) + targetPlayer.getPos().getY(); } } else { y = Float.parseFloat(args.get(1)); } if (args.get(2).contains("~")) { if (args.get(2).equals("~")) { - z = sender.getPos().getZ(); + z = targetPlayer.getPos().getZ(); } else { - z = Float.parseFloat(args.get(2).replace("~", "")) + sender.getPos().getZ(); + z = Float.parseFloat(args.get(2).replace("~", "")) + targetPlayer.getPos().getZ(); } } else { z = Float.parseFloat(args.get(2)); } - int sceneId = sender.getSceneId(); + int sceneId = targetPlayer.getSceneId(); if (args.size() == 4){ sceneId = Integer.parseInt(args.get(3)); } - Position target = new Position(x, y, z); - boolean result = sender.getWorld().transferPlayerToScene(sender, sceneId, target); + Position target_pos = new Position(x, y, z); + boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos); if (!result) { CommandHandler.sendMessage(sender, "Invalid position."); + } else { + CommandHandler.sendMessage(sender, "Teleported " + targetPlayer.getNickname() + " to " + x + "," + y + "," + z + " in scene " + sceneId); } } catch (NumberFormatException ignored) { CommandHandler.sendMessage(sender, "Invalid position."); From 0136425628c26de241499aeec9c893dfb643c6c7 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Fri, 29 Apr 2022 18:04:20 +0800 Subject: [PATCH 04/21] Support custom server avatar --- src/main/java/emu/grasscutter/Config.java | 1 + src/main/java/emu/grasscutter/GameConstants.java | 1 + .../server/packet/send/PacketGetPlayerFriendListRsp.java | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index 238ddb31c..56a1a0352 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -70,6 +70,7 @@ public final class Config { public int MaxAvatarsInTeamMultiplayer = 4; public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later. public boolean WatchGacha = false; + public int ServerAvatarId = 10000007; public int[] WelcomeEmotes = {2007, 1002, 4010}; public String WelcomeMotd = "Welcome to Grasscutter emu"; public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n "; diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index dc07c32e1..ab48c01c7 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -11,6 +11,7 @@ public final class GameConstants { public static final int MAX_TEAMS = 4; public static final int MAIN_CHARACTER_MALE = 10000005; public static final int MAIN_CHARACTER_FEMALE = 10000007; + public static final int SERVER_AVATAR_ID = Grasscutter.getConfig().getGameServerOptions().ServerAvatarId; public static final Position START_POSITION = new Position(2747, 194, -1719); public static final int MAX_FRIENDS = 45; diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java index dbaa4b316..e085e6f6e 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java @@ -20,7 +20,7 @@ public class PacketGetPlayerFriendListRsp extends BasePacket { .setUid(GameConstants.SERVER_CONSOLE_UID) .setNickname("Server") .setLevel(1) - .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.MAIN_CHARACTER_FEMALE)) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.SERVER_AVATAR_ID)) .setWorldLevel(0) .setSignature("") .setLastActiveTime((int) (System.currentTimeMillis() / 1000f)) From 62f0be4966b78a40e44941f5c7c7800eb3d04d64 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Fri, 29 Apr 2022 18:59:24 +0800 Subject: [PATCH 05/21] Support custom server in-game nickname --- src/main/java/emu/grasscutter/Config.java | 1 + src/main/java/emu/grasscutter/GameConstants.java | 1 + .../server/packet/send/PacketGetPlayerFriendListRsp.java | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index 56a1a0352..c2d7850fd 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -51,6 +51,7 @@ public final class Config { public static class GameServerOptions { public String Name = "Test"; + public String NickName = "Server"; public String Ip = "0.0.0.0"; public String PublicIp = "127.0.0.1"; public int Port = 22102; diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index ab48c01c7..317221ec6 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -12,6 +12,7 @@ public final class GameConstants { public static final int MAIN_CHARACTER_MALE = 10000005; public static final int MAIN_CHARACTER_FEMALE = 10000007; public static final int SERVER_AVATAR_ID = Grasscutter.getConfig().getGameServerOptions().ServerAvatarId; + public static final String SERVER_AVATAR_NAME = Grasscutter.getConfig().getGameServerOptions().NickName; public static final Position START_POSITION = new Position(2747, 194, -1719); public static final int MAX_FRIENDS = 45; diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java index e085e6f6e..d7a9427b8 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java @@ -18,7 +18,7 @@ public class PacketGetPlayerFriendListRsp extends BasePacket { FriendBrief serverFriend = FriendBrief.newBuilder() .setUid(GameConstants.SERVER_CONSOLE_UID) - .setNickname("Server") + .setNickname(GameConstants.SERVER_AVATAR_NAME) .setLevel(1) .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.SERVER_AVATAR_ID)) .setWorldLevel(0) From eaed1aa03862cb8965557d709a4a5e883ac27229 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Fri, 29 Apr 2022 19:37:51 +0800 Subject: [PATCH 06/21] Change NickName to ServerNickname --- src/main/java/emu/grasscutter/Config.java | 2 +- src/main/java/emu/grasscutter/GameConstants.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index c2d7850fd..109c7b8ee 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -51,7 +51,6 @@ public final class Config { public static class GameServerOptions { public String Name = "Test"; - public String NickName = "Server"; public String Ip = "0.0.0.0"; public String PublicIp = "127.0.0.1"; public int Port = 22102; @@ -71,6 +70,7 @@ public final class Config { public int MaxAvatarsInTeamMultiplayer = 4; public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later. public boolean WatchGacha = false; + public String ServerNickname = "Server"; public int ServerAvatarId = 10000007; public int[] WelcomeEmotes = {2007, 1002, 4010}; public String WelcomeMotd = "Welcome to Grasscutter emu"; diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index 317221ec6..39b28b736 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -11,8 +11,8 @@ public final class GameConstants { public static final int MAX_TEAMS = 4; public static final int MAIN_CHARACTER_MALE = 10000005; public static final int MAIN_CHARACTER_FEMALE = 10000007; + public static final String SERVER_AVATAR_NAME = Grasscutter.getConfig().getGameServerOptions().ServerNickname; public static final int SERVER_AVATAR_ID = Grasscutter.getConfig().getGameServerOptions().ServerAvatarId; - public static final String SERVER_AVATAR_NAME = Grasscutter.getConfig().getGameServerOptions().NickName; public static final Position START_POSITION = new Position(2747, 194, -1719); public static final int MAX_FRIENDS = 45; From 8a9dab7d74357c01669df07f69f10015709a8a38 Mon Sep 17 00:00:00 2001 From: muhammadeko Date: Sat, 30 Apr 2022 06:49:49 +0700 Subject: [PATCH 07/21] Give Artifact: Clear random props first before adding all picked props --- .../emu/grasscutter/command/commands/GiveArtifactCommand.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java index e33a287e3..299a14f40 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java @@ -79,6 +79,7 @@ public final class GiveArtifactCommand implements CommandHandler { GameItem item = new GameItem(itemData); item.setLevel(level); item.setMainPropId(mainPropId); + item.getAppendPropIdList().clear();//Clear default random props first item.getAppendPropIdList().addAll(appendPropIdList); targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop); From d8e458cd3396bb17be9b8bb84b20c6146b45c42d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E5=82=91?= Date: Sat, 30 Apr 2022 15:40:53 +0800 Subject: [PATCH 08/21] Fix Give Command Promote Level Bug Should be <=40, just change the order --- .../command/commands/GiveCommand.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java index 03147a44b..52670efa7 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java @@ -163,20 +163,28 @@ public final class GiveCommand implements CommandHandler { List items = new LinkedList<>(); for (int i = 0; i < amount; i++) { GameItem item = new GameItem(itemData); + if (item.isEquipped()) { + // check item max level + if (item.getItemType() == ItemType.ITEM_WEAPON) { + if (lvl > 90) lvl = 90; + } else { + if (lvl > 21) lvl = 21; + } + } item.setCount(amount); item.setLevel(lvl); - if (lvl > 20 && lvl < 40) { - item.setPromoteLevel(1); - } else if (lvl > 40 && lvl <= 50) { - item.setPromoteLevel(2); - } else if (lvl > 50 && lvl <= 60) { - item.setPromoteLevel(3); - } else if (lvl > 60 && lvl <= 70) { - item.setPromoteLevel(4); - } else if (lvl > 70 && lvl <= 80) { - item.setPromoteLevel(5); - } else if (lvl > 80 && lvl <= 90) { + if (lvl > 80) { item.setPromoteLevel(6); + } else if (lvl > 70) { + item.setPromoteLevel(5); + } else if (lvl > 60) { + item.setPromoteLevel(4); + } else if (lvl > 50) { + item.setPromoteLevel(3); + } else if (lvl > 40) { + item.setPromoteLevel(2); + } else if (lvl > 20) { + item.setPromoteLevel(1); } if (item.getItemType() == ItemType.ITEM_WEAPON) { if (refinement > 0) { From c2b8a20e03290e764589825a046e5c360088d078 Mon Sep 17 00:00:00 2001 From: lhhxxxxx <91231470+lhhxxxxx@users.noreply.github.com> Date: Sat, 30 Apr 2022 15:28:49 +0800 Subject: [PATCH 09/21] Update GiveAllCommand.java giveall command nomore give arts --- .../emu/grasscutter/command/commands/GiveAllCommand.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java index cdf2adbc1..cb6d1e93e 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java @@ -98,14 +98,14 @@ public class GiveAllCommand implements CommandHandler { if (isTestItem(itemdata.getId())) continue; if (itemdata.isEquip()) { - for (int i = 0; i < 5; ++i) { - GameItem item = new GameItem(itemdata); - if (itemdata.getItemType() == ItemType.ITEM_WEAPON) { + if (itemdata.getItemType() == ItemType.ITEM_WEAPON) { + for (int i = 0; i < 5; ++i) { + GameItem item = new GameItem(itemdata); item.setLevel(90); item.setPromoteLevel(6); item.setRefinement(4); + itemList.add(item); } - itemList.add(item); } } else { From 66c2743d6ea0181b40059f669e0e51e5a562b913 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Fri, 29 Apr 2022 14:29:34 -0700 Subject: [PATCH 10/21] Update how scene/dungeon map points are handled --- .../java/emu/grasscutter/Grasscutter.java | 14 ++++++ .../java/emu/grasscutter/data/GameData.java | 12 +++++ .../emu/grasscutter/data/ResourceLoader.java | 6 ++- .../grasscutter/data/common/PointData.java | 33 ++++++++++++ .../data/def/DailyDungeonData.java | 50 +++++++++++++++++++ .../game/dungeons/DungeonManager.java | 8 ++- .../send/PacketDungeonEntryInfoRsp.java | 10 ++-- .../packet/send/PacketGetScenePointRsp.java | 9 +++- 8 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 src/main/java/emu/grasscutter/data/def/DailyDungeonData.java diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index f7669d30b..60d042b11 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -6,6 +6,7 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.InputStreamReader; import java.net.InetSocketAddress; +import java.util.Calendar; import emu.grasscutter.command.CommandMap; import emu.grasscutter.plugin.PluginManager; @@ -32,6 +33,8 @@ public final class Grasscutter { private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private static final File configFile = new File("./config.json"); + private static int day; // Current day of week + public static RunMode MODE = RunMode.BOTH; private static DispatchServer dispatchServer; private static GameServer gameServer; @@ -67,8 +70,10 @@ public final class Grasscutter { Grasscutter.getLogger().info("Starting Grasscutter..."); // Load all resources. + Grasscutter.updateDayOfWeek(); ResourceLoader.loadAll(); ScriptLoader.init(); + // Database DatabaseManager.initialize(); @@ -179,4 +184,13 @@ public final class Grasscutter { public static PluginManager getPluginManager() { return pluginManager; } + + public static void updateDayOfWeek() { + Calendar calendar = Calendar.getInstance(); + day = calendar.get(Calendar.DAY_OF_WEEK); + } + + public static int getCurrentDayOfWeek() { + return day; + } } diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 45fad21a4..c187a1819 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -15,6 +15,8 @@ import emu.grasscutter.data.def.*; import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; public class GameData { // BinOutputs @@ -61,12 +63,14 @@ public class GameData { private static final Int2ObjectMap fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap rewardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap worldLevelDataMap = new Int2ObjectOpenHashMap<>(); + private static final Int2ObjectMap dailyDungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap dungeonDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap shopGoodsDataMap = new Int2ObjectOpenHashMap<>(); // Cache private static Map> fetters = new HashMap<>(); private static Map> shopGoods = new HashMap<>(); + private static final IntList scenePointIdList = new IntArrayList(); public static char EJWOA = 's'; @@ -280,6 +284,10 @@ public class GameData { return dungeonDataMap; } + public static Int2ObjectMap getDailyDungeonDataMap() { + return dailyDungeonDataMap; + } + public static Map> getShopGoodsDataEntries() { if (shopGoods.isEmpty()) { shopGoodsDataMap.forEach((k, v) -> { @@ -291,4 +299,8 @@ public class GameData { return shopGoods; } + + public static IntList getScenePointIdList() { + return scenePointIdList; + } } diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index 6b48645d8..180080e51 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -48,11 +48,12 @@ public class ResourceLoader { loadOpenConfig(); // Load resources loadResources(); - loadScenePoints(); // Process into depots GameDepot.load(); // Load spawn data loadSpawnData(); + // Load scene points - must be done AFTER resources are loaded + loadScenePoints(); // Custom - TODO move this somewhere else try { GameData.getAvatarSkillDepotDataMap().get(504).setAbilities( @@ -168,6 +169,9 @@ public class ResourceLoader { ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData); scenePointList.add(sl); + GameData.getScenePointIdList().add(pointData.getId()); + + pointData.updateDailyDungeon(); } for (ScenePointEntry entry : scenePointList) { diff --git a/src/main/java/emu/grasscutter/data/common/PointData.java b/src/main/java/emu/grasscutter/data/common/PointData.java index 147eee81a..fa3891d7c 100644 --- a/src/main/java/emu/grasscutter/data/common/PointData.java +++ b/src/main/java/emu/grasscutter/data/common/PointData.java @@ -1,12 +1,18 @@ package emu.grasscutter.data.common; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.def.DailyDungeonData; import emu.grasscutter.utils.Position; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; public class PointData { private int id; private String $type; private Position tranPos; private int[] dungeonIds; + private int[] dungeonRandomList; public int getId() { return id; @@ -27,4 +33,31 @@ public class PointData { public int[] getDungeonIds() { return dungeonIds; } + + public int[] getDungeonRandomList() { + return dungeonRandomList; + } + + public void updateDailyDungeon() { + if (getDungeonRandomList() == null) { + return; + } + + IntList newDungeons = new IntArrayList(); + int day = Grasscutter.getCurrentDayOfWeek(); + + for (int randomId : getDungeonRandomList()) { + DailyDungeonData data = GameData.getDailyDungeonDataMap().get(randomId); + + if (data != null) { + int[] addDungeons = data.getDungeonsByDay(day); + + for (int d : addDungeons) { + newDungeons.add(d); + } + } + } + + this.dungeonIds = newDungeons.toIntArray(); + } } diff --git a/src/main/java/emu/grasscutter/data/def/DailyDungeonData.java b/src/main/java/emu/grasscutter/data/def/DailyDungeonData.java new file mode 100644 index 000000000..8cd878125 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/def/DailyDungeonData.java @@ -0,0 +1,50 @@ +package emu.grasscutter.data.def; + +import java.util.Calendar; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; + +import emu.grasscutter.game.props.SceneType; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +@ResourceType(name = "DailyDungeonConfigData.json") +public class DailyDungeonData extends GameResource { + private int Id; + private int[] Monday; + private int[] Tuesday; + private int[] Wednesday; + private int[] Thursday; + private int[] Friday; + private int[] Saturday; + private int[] Sunday; + + private static final int[] empty = new int[0]; + private final Int2ObjectMap map; + + public DailyDungeonData() { + this.map = new Int2ObjectOpenHashMap<>(); + } + + @Override + public int getId() { + return this.Id; + } + + public int[] getDungeonsByDay(int day) { + return map.getOrDefault(day, empty); + } + + @Override + public void onLoad() { + map.put(Calendar.MONDAY, Monday); + map.put(Calendar.TUESDAY, Tuesday); + map.put(Calendar.WEDNESDAY, Wednesday); + map.put(Calendar.THURSDAY, Thursday); + map.put(Calendar.FRIDAY, Friday); + map.put(Calendar.SATURDAY, Saturday); + map.put(Calendar.SUNDAY, Sunday); + } +} diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java index 6011c1f7c..4c04f86f7 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java +++ b/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java @@ -28,7 +28,7 @@ public class DungeonManager { public void getEntryInfo(Player player, int pointId) { ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId); - if (entry == null || entry.getPointData().getDungeonIds() == null) { + if (entry == null) { // Error player.sendPacket(new PacketDungeonEntryInfoRsp()); return; @@ -79,4 +79,10 @@ public class DungeonManager { player.getWorld().transferPlayerToScene(player, prevScene, prevPos); player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); } + + public void updateDailyDungeons() { + for (ScenePointEntry entry : GameData.getScenePointEntries().values()) { + entry.getPointData().updateDailyDungeon(); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonEntryInfoRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonEntryInfoRsp.java index a2cc052bb..5d7842fe1 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonEntryInfoRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketDungeonEntryInfoRsp.java @@ -17,11 +17,13 @@ public class PacketDungeonEntryInfoRsp extends BasePacket { DungeonEntryInfoRsp.Builder proto = DungeonEntryInfoRsp.newBuilder() .setPointId(pointData.getId()); - for (int dungeonId : pointData.getDungeonIds()) { - DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build(); - proto.addDungeonEntryList(info); + if (pointData.getDungeonIds() != null) { + for (int dungeonId : pointData.getDungeonIds()) { + DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build(); + proto.addDungeonEntryList(info); + } } - + this.setData(proto); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java index 85b7ab02f..b4c001831 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetScenePointRsp.java @@ -1,5 +1,6 @@ package emu.grasscutter.server.packet.send; +import emu.grasscutter.data.GameData; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GetScenePointRspOuterClass.GetScenePointRsp; @@ -12,8 +13,12 @@ public class PacketGetScenePointRsp extends BasePacket { GetScenePointRsp.Builder p = GetScenePointRsp.newBuilder() .setSceneId(sceneId); - for (int i = 1; i < 1000; i++) { - p.addUnlockedPointList(i); + if (GameData.getScenePointIdList().size() == 0) { + for (int i = 1; i < 1000; i++) { + p.addUnlockedPointList(i); + } + } else { + p.addAllUnlockedPointList(GameData.getScenePointIdList()); } for (int i = 1; i < 9; i++) { From f8f4d89cd0bcf538da9c7c4c66dfe330781c6152 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Fri, 29 Apr 2022 14:36:02 -0700 Subject: [PATCH 11/21] Optimize GetOnlinePlayerListRsp --- .../emu/grasscutter/game/player/Player.java | 2 +- .../send/PacketGetOnlinePlayerListRsp.java | 37 +++++-------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index f440fcb1b..0637e3d43 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -822,7 +822,7 @@ public class Player { .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())); if (this.getWorld() != null) { - onlineInfo.setCurPlayerNumInWorld(this.getWorld().getPlayers().indexOf(this) + 1); + onlineInfo.setCurPlayerNumInWorld(getWorld().getPlayerCount()); } else { onlineInfo.setCurPlayerNumInWorld(1); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java index 85cf5429e..4ea8a02a5 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java @@ -18,36 +18,19 @@ import java.util.Objects; public class PacketGetOnlinePlayerListRsp extends BasePacket { public PacketGetOnlinePlayerListRsp(Player session){ super(PacketOpcodes.GetOnlinePlayerListRsp); - Map playersMap = Grasscutter.getGameServer().getPlayers(); + + List players = Grasscutter.getGameServer().getPlayers().values().stream().limit(50).toList(); + GetOnlinePlayerListRsp.Builder proto = GetOnlinePlayerListRsp.newBuilder(); - if(playersMap.size() != 0){ - List playerInfoList = new ArrayList<>(); - - for(Player player:playersMap.values()){ - ProfilePicture.Builder picture = ProfilePicture.newBuilder(); - OnlinePlayerInfo.Builder playerInfo = OnlinePlayerInfo.newBuilder(); - - if(player.getUid() == session.getUid())continue; - picture.setAvatarId(player.getProfile().getAvatarId()) - .build(); - System.out.println(player.getHeadImage()); - playerInfo.setUid(player.getUid()) - .setNickname(player.getNickname()) - .setPlayerLevel(player.getLevel()) - .setMpSettingType(MpSettingTypeOuterClass.MpSettingType.MP_SETTING_ENTER_AFTER_APPLY) - .setCurPlayerNumInWorld(player.getWorld().getPlayerCount()) - .setWorldLevel(player.getWorldLevel()) - .setNameCardId(player.getNameCardId()) - .setProfilePicture(picture); - if(!Objects.equals(player.getSignature(), "")){ - playerInfo.setSignature(player.getSignature()); - } - playerInfoList.add(playerInfo.build()); - } - for (OnlinePlayerInfo onlinePlayerInfo : playerInfoList) { - proto.addPlayerInfoList(onlinePlayerInfo).build(); + + if (players.size() != 0) { + for(Player player : players) { + if (player.getUid() == session.getUid()) continue; + + proto.addPlayerInfoList(player.getOnlinePlayerInfo()); } } + this.setData(proto); } } From 3f76ac4cac821bb39367304b823992da7cb2bfb8 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Fri, 29 Apr 2022 15:59:44 -0700 Subject: [PATCH 12/21] Temporary fix for scripts that call require --- .../emu/grasscutter/scripts/ScriptLoader.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java index c4157c690..f6ac0eb53 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java @@ -13,6 +13,10 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.lib.OneArgFunction; +import org.luaj.vm2.script.LuajContext; + import emu.grasscutter.Grasscutter; import emu.grasscutter.scripts.serializer.LuaSerializer; import emu.grasscutter.scripts.serializer.Serializer; @@ -31,11 +35,23 @@ public class ScriptLoader { throw new Exception("Script loader already initialized"); } + // Create script engine sm = new ScriptEngineManager(); engine = sm.getEngineByName("luaj"); factory = getEngine().getFactory(); + + // Lua stuff fileType = "lua"; serializer = new LuaSerializer(); + + // Set engine to replace require as a temporary fix to missing scripts + LuajContext ctx = (LuajContext) engine.getContext(); + ctx.globals.set("require", new OneArgFunction() { + @Override + public LuaValue call(LuaValue arg0) { + return LuaValue.ZERO; + } + }); } public static ScriptEngine getEngine() { From 1ed46df6e803a41cd95080162326ebdd41f34143 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Fri, 29 Apr 2022 20:45:36 -0700 Subject: [PATCH 13/21] Move script constants to globals --- .../grasscutter/scripts/SceneScriptManager.java | 7 +++---- .../emu/grasscutter/scripts/ScriptLoader.java | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java index 2f2f31219..58e3b3b8a 100644 --- a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java @@ -1,6 +1,7 @@ package emu.grasscutter.scripts; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -23,6 +24,7 @@ import emu.grasscutter.data.def.WorldLevelData; import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.world.Scene; import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.ScriptGadgetState; @@ -134,11 +136,8 @@ public class SceneScriptManager { bindings = ScriptLoader.getEngine().createBindings(); // Set variables - bindings.put("EventType", new EventType()); // TODO - make static class to avoid instantiating a new class every scene - bindings.put("GadgetState", new ScriptGadgetState()); - bindings.put("RegionShape", new ScriptRegionShape()); bindings.put("ScriptLib", getScriptLib()); - + // Eval script try { cs.eval(getBindings()); diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java index f6ac0eb53..0cbd6a191 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -13,11 +14,17 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; +import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.OneArgFunction; +import org.luaj.vm2.lib.jse.CoerceJavaToLua; import org.luaj.vm2.script.LuajContext; import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.props.EntityType; +import emu.grasscutter.scripts.constants.EventType; +import emu.grasscutter.scripts.constants.ScriptGadgetState; +import emu.grasscutter.scripts.constants.ScriptRegionShape; import emu.grasscutter.scripts.serializer.LuaSerializer; import emu.grasscutter.scripts.serializer.Serializer; @@ -52,6 +59,14 @@ public class ScriptLoader { return LuaValue.ZERO; } }); + + LuaTable table = new LuaTable(); + Arrays.stream(EntityType.values()).forEach(e -> table.set(e.name().toUpperCase(), e.getValue())); + ctx.globals.set("EntityType", table); + + ctx.globals.set("EventType", CoerceJavaToLua.coerce(new EventType())); // TODO - make static class to avoid instantiating a new class every scene + ctx.globals.set("GadgetState", CoerceJavaToLua.coerce(new ScriptGadgetState())); + ctx.globals.set("RegionShape", CoerceJavaToLua.coerce(new ScriptRegionShape())); } public static ScriptEngine getEngine() { From 7e377dff59c278e5a54a961a7370238d0c7e349d Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Sat, 30 Apr 2022 01:08:38 -0700 Subject: [PATCH 14/21] Implement script region check --- .../grasscutter/game/entity/GameEntity.java | 4 ++ .../emu/grasscutter/game/world/Scene.java | 2 + .../scripts/SceneScriptManager.java | 39 ++++++++++++- .../emu/grasscutter/scripts/ScriptLib.java | 14 +++++ .../grasscutter/scripts/data/SceneGroup.java | 1 + .../grasscutter/scripts/data/SceneRegion.java | 57 +++++++++++++++++++ .../grasscutter/scripts/data/ScriptArgs.java | 10 ++++ 7 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 src/main/java/emu/grasscutter/scripts/data/SceneRegion.java diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index 24598a652..627b41103 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -34,6 +34,10 @@ public abstract class GameEntity { return this.id; } + public int getEntityType() { + return getId() >> 24; + } + public World getWorld() { return this.getScene().getWorld(); } diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index ee6b9a6a9..6ef810fbf 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -508,6 +508,7 @@ public class Scene { } group.triggers.forEach(getScriptManager()::registerTrigger); + group.regions.forEach(getScriptManager()::registerRegion); } // Spawn gadgets AFTER triggers are added @@ -526,6 +527,7 @@ public class Scene { for (SceneGroup group : block.groups) { group.triggers.forEach(getScriptManager()::deregisterTrigger); + group.regions.forEach(getScriptManager()::deregisterRegion); } } diff --git a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java index 58e3b3b8a..f2f892de3 100644 --- a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java @@ -35,6 +35,7 @@ import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneInitConfig; import emu.grasscutter.scripts.data.SceneMonster; +import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.scripts.data.SceneSuite; import emu.grasscutter.scripts.data.SceneTrigger; import emu.grasscutter.scripts.data.SceneVar; @@ -51,14 +52,17 @@ public class SceneScriptManager { private Bindings bindings; private SceneConfig config; private List blocks; - private Int2ObjectOpenHashMap> triggers; private boolean isInit; + private final Int2ObjectOpenHashMap> triggers; + private final Int2ObjectOpenHashMap regions; + public SceneScriptManager(Scene scene) { this.scene = scene; this.scriptLib = new ScriptLib(this); this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib); this.triggers = new Int2ObjectOpenHashMap<>(); + this.regions = new Int2ObjectOpenHashMap<>(); this.variables = new HashMap<>(); // TEMPORARY @@ -110,6 +114,18 @@ public class SceneScriptManager { getTriggersByEvent(trigger.event).remove(trigger); } + public SceneRegion getRegionById(int id) { + return regions.get(id); + } + + public void registerRegion(SceneRegion region) { + regions.put(region.config_id, region); + } + + public void deregisterRegion(SceneRegion region) { + regions.remove(region.config_id); + } + // TODO optimize public SceneGroup getGroupById(int groupId) { for (SceneBlock block : this.getScene().getLoadedBlocks()) { @@ -210,6 +226,7 @@ public class SceneScriptManager { group.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, bindings.get("gadgets")); group.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")); group.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites")); + group.regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions")); group.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config")); // Add variables to suite @@ -234,11 +251,27 @@ public class SceneScriptManager { } public void onTick() { - checkTriggers(); + checkRegions(); } - public void checkTriggers() { + public void checkRegions() { + if (this.regions.size() == 0) { + return; + } + + for (SceneRegion region : this.regions.values()) { + getScene().getEntities().values() + .stream() + .filter(e -> e.getEntityType() <= 2 && region.contains(e.getPosition())) + .forEach(region::addEntity); + if (region.hasNewEntities()) { + // This is not how it works, source_eid should be region entity id, but we dont have an entity for regions yet + callEvent(EventType.EVENT_ENTER_REGION, new ScriptArgs(region.config_id).setSourceEntityId(region.config_id)); + + region.resetNewEntities(); + } + } } public void spawnGadgetsInGroup(SceneGroup group) { diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLib.java b/src/main/java/emu/grasscutter/scripts/ScriptLib.java index 57cd73dd3..5dfe644be 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLib.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLib.java @@ -17,6 +17,7 @@ import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneMonster; +import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.server.packet.send.PacketGadgetStateNotify; import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify; @@ -184,6 +185,19 @@ public class ScriptLib { return 0; } + public int GetRegionEntityCount(LuaTable table) { + int regionId = table.get("region_eid").toint(); + int entityType = table.get("entity_type").toint(); + + SceneRegion region = this.getSceneScriptManager().getRegionById(regionId); + + if (region == null) { + return 0; + } + + return (int) region.getEntities().intStream().filter(e -> e >> 24 == entityType).count(); + } + public void PrintContextLog(String msg) { Grasscutter.getLogger().info("[LUA] " + msg); } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index d72d02d53..a13db7b68 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -14,6 +14,7 @@ public class SceneGroup { public List monsters; public List gadgets; public List triggers; + public List regions; public List suites; public SceneInitConfig init_config; diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java b/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java new file mode 100644 index 000000000..dac164d0e --- /dev/null +++ b/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java @@ -0,0 +1,57 @@ +package emu.grasscutter.scripts.data; + +import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.scripts.constants.ScriptRegionShape; +import emu.grasscutter.utils.Position; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class SceneRegion { + public int config_id; + public int shape; + public Position pos; + public Position size; + + private boolean hasNewEntities; + private final IntSet entities; // Ids of entities inside this region + + public SceneRegion() { + this.entities = new IntOpenHashSet(); + } + + public IntSet getEntities() { + return entities; + } + + public void addEntity(GameEntity entity) { + if (this.getEntities().contains(entity.getId())) { + return; + } + this.getEntities().add(entity.getId()); + this.hasNewEntities = true; + } + + public void removeEntity(GameEntity entity) { + this.getEntities().remove(entity.getId()); + } + + public boolean contains(Position p) { + switch (shape) { + case ScriptRegionShape.CUBIC: + return (Math.abs(pos.getX() - p.getX()) <= size.getX()) && + (Math.abs(pos.getZ() - p.getZ()) <= size.getZ()); + case ScriptRegionShape.SPHERE: + return false; + } + + return false; + } + + public boolean hasNewEntities() { + return hasNewEntities; + } + + public void resetNewEntities() { + hasNewEntities = false; + } +} diff --git a/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java b/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java index 3073f7322..a1f183b63 100644 --- a/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java +++ b/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java @@ -4,6 +4,7 @@ public class ScriptArgs { public int param1; public int param2; public int param3; + public int source_eid; // Source entity public ScriptArgs() { @@ -44,4 +45,13 @@ public class ScriptArgs { this.param3 = param3; return this; } + + public int getSourceEntityId() { + return source_eid; + } + + public ScriptArgs setSourceEntityId(int source_eid) { + this.source_eid = source_eid; + return this; + } } From 286ab545e9bbec5ebb260d461b1aa3b79c86d58c Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Sat, 30 Apr 2022 01:18:50 -0700 Subject: [PATCH 15/21] Monsters should not drop items inside dungeons --- src/main/java/emu/grasscutter/game/world/Scene.java | 4 ++-- src/main/java/emu/grasscutter/game/world/World.java | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 6ef810fbf..365b55982 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -375,8 +375,8 @@ public class Scene { this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD)); // Reward drop - if (target instanceof EntityMonster) { - Grasscutter.getGameServer().getDropManager().callDrop((EntityMonster) target); + if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_WORLD) { + getWorld().getServer().getDropManager().callDrop((EntityMonster) target); } this.removeEntity(target); diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 215896fea..46c80cd25 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -27,6 +27,7 @@ import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.scripts.data.SceneConfig; +import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; @@ -44,6 +45,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class World implements Iterable { + private final GameServer server; private final Player owner; private final List players; private final Int2ObjectMap scenes; @@ -61,6 +63,7 @@ public class World implements Iterable { public World(Player player, boolean isMultiplayer) { this.owner = player; + this.server = player.getServer(); this.players = Collections.synchronizedList(new ArrayList<>()); this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); @@ -75,6 +78,10 @@ public class World implements Iterable { return owner; } + public GameServer getServer() { + return server; + } + public int getLevelEntityId() { return levelEntityId; } From eef216aea8247ca9b2fa4f73a85a184bcde0fe3d Mon Sep 17 00:00:00 2001 From: lhhxxxxx <91231470+lhhxxxxx@users.noreply.github.com> Date: Wed, 27 Apr 2022 14:45:53 +0800 Subject: [PATCH 16/21] Update Account.hasPermission() Add wildcard characters to permission nodes under the same namespace. (simple implementation) --- src/main/java/emu/grasscutter/game/Account.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/game/Account.java b/src/main/java/emu/grasscutter/game/Account.java index dbd6ef854..7ccaf7e7e 100644 --- a/src/main/java/emu/grasscutter/game/Account.java +++ b/src/main/java/emu/grasscutter/game/Account.java @@ -104,7 +104,10 @@ public class Account { } public boolean hasPermission(String permission) { - return this.permissions.contains(permission) || this.permissions.contains("*") ? true : false; + return this.permissions.contains(permission) || + this.permissions.contains("*") || + (this.permissions.contains("player") || this.permissions.contains("player.*")) && permission.startsWith("player.") || + (this.permissions.contains("server") || this.permissions.contains("server.*")) && permission.startsWith("server."); } public boolean removePermission(String permission) { From fb991d845ea785da512cd0ab0caa717037df74d7 Mon Sep 17 00:00:00 2001 From: Scirese <62688390+Scirese@users.noreply.github.com> Date: Sat, 30 Apr 2022 17:45:24 +0800 Subject: [PATCH 17/21] Add Android Client fix by @BaiSugar (#105) --- .../emu/grasscutter/server/dispatch/DispatchServer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index 99c5e4f8d..6997d0449 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -490,10 +490,10 @@ public final class DispatchServer { "{\"retcode\":0,\"message\":\"OK\",\"data\":{\"suggest_currency\":\"USD\",\"tiers\":[]}}")); // Captcha server.createContext( // api-account-os.hoyoverse.com - "/account/risky/api/check", - new DispatchHttpJsonHandler( - "{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":\"c8820f246a5241ab9973f71df3ddd791\",\"action\":\"\",\"geetest\":{\"challenge\":\"\",\"gt\":\"\",\"new_captcha\":0,\"success\":1}}}")); - // Config + "/account/risky/api/check", + new DispatchHttpJsonHandler("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":\"none\",\"action\":\"ACTION_NONE\",\"geetest\":null}}") + ); + // Config server.createContext( // sdk-os-static.hoyoverse.com "/combo/box/api/config/sdk/combo", new DispatchHttpJsonHandler( From 7b991d7b4e8a6e765bb9e10ae28b8e27211397e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E5=82=91?= Date: Sat, 30 Apr 2022 17:46:23 +0800 Subject: [PATCH 18/21] Update Welcome Mail Items Type (#369) --- src/main/java/emu/grasscutter/Config.java | 7 ++++++- .../server/packet/recv/HandlerSetPlayerBornDataReq.java | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index ce753d80d..03c6fb1f8 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -1,5 +1,7 @@ package emu.grasscutter; +import emu.grasscutter.game.mail.Mail; + public final class Config { public String DatabaseUrl = "mongodb://localhost:27017"; @@ -76,7 +78,10 @@ public final class Config { public int[] WelcomeEmotes = {2007, 1002, 4010}; public String WelcomeMotd = "Welcome to Grasscutter emu"; public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n "; - public int[] WelcomeMailItems = {13509}; + public Mail.MailItem[] WelcomeMailItems = { + new Mail.MailItem(13509, 1, 1), + new Mail.MailItem(201, 10000, 1), + }; public boolean EnableOfficialShop = true; 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 52c52c280..9acd4f21b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -16,6 +16,8 @@ import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession.SessionState; +import java.util.Arrays; + @Opcodes(PacketOpcodes.SetPlayerBornDataReq) public class HandlerSetPlayerBornDataReq extends PacketHandler { @@ -82,9 +84,7 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { mailBuilder.mail.mailContent.title = String.format("W%sl%som%s to %s%s%s%s%s%s%s%s%s%s%s!", DatabaseHelper.AWJVN, u, DatabaseHelper.AWJVN, d, e, z, GameData.EJWOA, GameData.EJWOA, u, PacketOpcodes.ONLWE, s, s, DatabaseHelper.AWJVN, e); mailBuilder.mail.mailContent.sender = String.format("L%swnmow%s%s @ Gi%sH%sb", z, DatabaseHelper.AWJVN, e, s, PacketOpcodes.ONLWE); mailBuilder.mail.mailContent.content = Grasscutter.getConfig().GameServer.WelcomeMailContent; - for (int itemId : Grasscutter.getConfig().GameServer.WelcomeMailItems) { - mailBuilder.mail.itemList.add(new Mail.MailItem(itemId, 1, 1)); - } + mailBuilder.mail.itemList.addAll(Arrays.asList(Grasscutter.getConfig().GameServer.WelcomeMailItems)); mailBuilder.mail.importance = 1; player.sendMail(mailBuilder.mail); } catch (Exception e) { From d6fa05915f5d4ad570f6e76dccd5150e7ebf6f43 Mon Sep 17 00:00:00 2001 From: Aru Date: Sat, 30 Apr 2022 19:18:09 +0800 Subject: [PATCH 19/21] Monsters should drop items in world (#373) * Monsters should drop items in world fix the typo introduced in https://github.com/Grasscutters/Grasscutter/pull/366/commits/f1934c3a47d6c7ef888581bcf7f361d063154215 * Determine whether in dungeon scene --- src/main/java/emu/grasscutter/game/world/Scene.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 365b55982..440ec7316 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -375,7 +375,7 @@ public class Scene { this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD)); // Reward drop - if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_WORLD) { + if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_DUNGEON) { getWorld().getServer().getDropManager().callDrop((EntityMonster) target); } From eac9c04e4e76c744373390f3d3b1b988944dfab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=A4=E5=BA=A7=E3=81=82=E3=81=8B=E3=82=8A?= Date: Sat, 30 Apr 2022 19:19:22 +0800 Subject: [PATCH 20/21] Give Artifact: Fix error & Rename alias (#370) * Give Artifact: Fix error & Rename alias * Update README.md --- README.md | 2 +- README_zh-CN.md | 2 +- .../command/commands/GiveArtifactCommand.java | 19 ++++++++++++------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9d5595853..623baf68b 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ There is a dummy user named "Server" in every player's friends list that you can | drop | drop [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` | | give | give [player] [amount] [level] [finement] | player.give | Both side | Gives item(s) to you or the specified player. (finement option only weapon.) | `g` `item` `giveitem` | | givechar | givechar \ \ | player.givechar | Both side | Gives the player a specified character. | givec | -| giveart | giveart [player] \ \ [\[,\]]... [level] | player.giveart | Both side | Gives the player a specified reliquary. | givea | +| giveart | giveart [player] \ \ [\[,\]]... [level] | player.giveart | Both side | Gives the player a specified artifact. | gart | | giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea | | godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | | | heal | heal | player.heal | Client only | Heals all characters in your current team. | h | diff --git a/README_zh-CN.md b/README_zh-CN.md index a386f0d23..6216cf3eb 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -116,7 +116,7 @@ chmod +x gradlew | drop | drop <物品ID\|物品名称> [数量] | server.drop | 仅客户端 | 在指定玩家周围掉落指定物品 | `d` `dropitem` | | give | give [uid] <物品ID\|物品名称> [数量] [等级] [精炼等级] | | | 给予指定玩家一定数量及等级的物品 (精炼等级仅适用于武器) | `g` `item` `giveitem` | | givechar | givechar \ <角色ID> [等级] | player.givechar | 均可使用 | 给予指定玩家对应角色 | givec | -| giveart | giveart [uid] \<圣遗物ID> \<主属性ID> [\<副属性ID>[,<次数>]]... [等级] | player.giveart | 均可使用 | 给予玩家指定属性的圣遗物 | givea | +| giveart | giveart [uid] \<圣遗物ID> \<主属性ID> [\<副属性ID>[,<次数>]]... [等级] | player.giveart | 均可使用 | 给予玩家指定属性的圣遗物 | gart | | giveall | giveall [uid] [数量] | player.giveall | 均可使用 | 给予指定玩家全部物品 | givea | | godmode | godmode [uid] | player.godmode | 仅客户端 | 保护你不受到任何伤害(依然会被击退) | | | heal | heal | player.heal | 仅客户端 | 治疗队伍中所有角色 | h | diff --git a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java index 299a14f40..382c55ec2 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java @@ -14,13 +14,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -@Command(label = "giveart", usage = "giveart [player] [[,]]... [level]", description = "Gives the player a specified reliquary", aliases = {"givea"}, permission = "player.giveart") +@Command(label = "giveart", usage = "giveart [player] [[,]]... [level]", description = "Gives the player a specified artifact", aliases = {"gart"}, permission = "player.giveart") public final class GiveArtifactCommand implements CommandHandler { @Override public void execute(Player sender, List args) { - int size = args.size(), target, itemId, mainPropId, level; + int size = args.size(), target, itemId, mainPropId, level = 1; ArrayList appendPropIdList = new ArrayList<>(); - String msg = "Usage: giveart|givea [player] [[,]]... [level]"; + String msg = "Usage: giveart|gart [player] [[,]]... [level]"; if (sender == null && size < 2) { CommandHandler.sendMessage(null, msg); @@ -29,9 +29,14 @@ public final class GiveArtifactCommand implements CommandHandler { if (size >= 2) { try { - level = Integer.parseInt(args.get(size - 1)); - if (level <= 21) size--; - else level = 1; + try { + int last = Integer.parseInt(args.get(size - 1)); + if (last >= 1 && last <= 21) { + level = last; + size--; + } + } catch (NumberFormatException ignored) { + } target = Integer.parseInt(args.get(0)); int fromIdx; if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) { @@ -79,7 +84,7 @@ public final class GiveArtifactCommand implements CommandHandler { GameItem item = new GameItem(itemData); item.setLevel(level); item.setMainPropId(mainPropId); - item.getAppendPropIdList().clear();//Clear default random props first + item.getAppendPropIdList().clear(); item.getAppendPropIdList().addAll(appendPropIdList); targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop); From d133e556663afc78c287ff050165df7f9c89bebe Mon Sep 17 00:00:00 2001 From: LDA Date: Sat, 30 Apr 2022 10:04:36 -0700 Subject: [PATCH 21/21] Implement viewing character details in character showcase --- .../emu/grasscutter/game/avatar/Avatar.java | 51 +++++++++++++++++-- .../grasscutter/game/inventory/GameItem.java | 46 ++++++++++------- .../emu/grasscutter/game/player/Player.java | 31 ++++++++++- .../HandlerGetFriendShowAvatarInfoReq.java | 26 ++++++++++ .../PacketGetFriendShowAvatarInfoRsp.java | 24 +++++++++ 5 files changed, 155 insertions(+), 23 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerGetFriendShowAvatarInfoReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketGetFriendShowAvatarInfoRsp.java diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index d16b9a2fa..cf5446ab7 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -15,7 +15,6 @@ import dev.morphia.annotations.Indexed; import dev.morphia.annotations.PostLoad; import dev.morphia.annotations.PrePersist; import dev.morphia.annotations.Transient; -import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.custom.OpenConfigEntry; @@ -26,18 +25,19 @@ import emu.grasscutter.data.def.AvatarSkillDepotData; import emu.grasscutter.data.def.AvatarSkillDepotData.InherentProudSkillOpens; import emu.grasscutter.data.def.AvatarTalentData; import emu.grasscutter.data.def.EquipAffixData; +import emu.grasscutter.data.def.ItemData.WeaponProperty; +import emu.grasscutter.data.def.ProudSkillData; import emu.grasscutter.data.def.ReliquaryAffixData; import emu.grasscutter.data.def.ReliquaryLevelData; import emu.grasscutter.data.def.ReliquaryMainPropData; import emu.grasscutter.data.def.ReliquarySetData; import emu.grasscutter.data.def.WeaponCurveData; import emu.grasscutter.data.def.WeaponPromoteData; -import emu.grasscutter.data.def.ItemData.WeaponProperty; -import emu.grasscutter.data.def.ProudSkillData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.inventory.EquipType; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ElementType; import emu.grasscutter.game.props.EntityIdType; @@ -45,8 +45,11 @@ import emu.grasscutter.game.props.FetterState; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.net.proto.AvatarFetterInfoOuterClass.AvatarFetterInfo; -import emu.grasscutter.net.proto.FetterDataOuterClass.FetterData; import emu.grasscutter.net.proto.AvatarInfoOuterClass.AvatarInfo; +import emu.grasscutter.net.proto.FetterDataOuterClass.FetterData; +import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass; +import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass.ShowAvatarInfo; +import emu.grasscutter.net.proto.ShowEquipOuterClass.ShowEquip; import emu.grasscutter.server.packet.send.PacketAbilityChangeNotify; import emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify; import emu.grasscutter.server.packet.send.PacketAvatarFightPropNotify; @@ -797,6 +800,46 @@ public class Avatar { return avatarInfo.build(); } + + // used only in character showcase + public ShowAvatarInfo toShowAvatarInfoProto() { + AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() + .setExpLevel(this.getFetterLevel()); + + ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .addAllTalentIdList(this.getTalentIdList()) + .putAllFightPropMap(this.getFightProperties()) + .setSkillDepotId(this.getSkillDepotId()) + .setCoreProudSkillLevel(this.getCoreProudSkillLevel()) + .addAllInherentProudSkillList(this.getProudSkillList()) + .putAllSkillLevelMap(this.getSkillLevelMap()) + .putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap()) + .setFetterInfo(avatarFetter) + .setCostumeId(this.getCostume()); + + showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiation())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiationPenalty())); + int maxStamina = this.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA); + showAvatarInfo.putPropMap(PlayerProperty.PROP_MAX_STAMINA.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_MAX_STAMINA, maxStamina)); + + for (GameItem item : this.getEquips().values()) { + if (item.getItemType() == ItemType.ITEM_RELIQUARY) { + showAvatarInfo.addEquipList(ShowEquip.newBuilder() + .setItemId(item.getItemId()) + .setReliquary(item.toReliquaryProto())); + } else if (item.getItemType() == ItemType.ITEM_WEAPON) { + showAvatarInfo.addEquipList(ShowEquip.newBuilder() + .setItemId(item.getItemId()) + .setWeapon(item.toWeaponProto())); + } + } + + return showAvatarInfo.build(); + } @PostLoad private void onLoad() { diff --git a/src/main/java/emu/grasscutter/game/inventory/GameItem.java b/src/main/java/emu/grasscutter/game/inventory/GameItem.java index 252c0a01c..7293b75c0 100644 --- a/src/main/java/emu/grasscutter/game/inventory/GameItem.java +++ b/src/main/java/emu/grasscutter/game/inventory/GameItem.java @@ -375,6 +375,32 @@ public class GameItem { return relicInfo; } + public Weapon toWeaponProto() { + Weapon.Builder weapon = Weapon.newBuilder() + .setLevel(this.getLevel()) + .setExp(this.getExp()) + .setPromoteLevel(this.getPromoteLevel()); + + if (this.getAffixes() != null && this.getAffixes().size() > 0) { + for (int affix : this.getAffixes()) { + weapon.putAffixMap(affix, this.getRefinement()); + } + } + + return weapon.build(); + } + + public Reliquary toReliquaryProto() { + Reliquary.Builder relic = Reliquary.newBuilder() + .setLevel(this.getLevel()) + .setExp(this.getExp()) + .setPromoteLevel(this.getPromoteLevel()) + .setMainPropId(this.getMainPropId()) + .addAllAppendPropIdList(this.getAppendPropIdList()); + + return relic.build(); + } + public Item toProto() { Item.Builder proto = Item.newBuilder() .setGuid(this.getGuid()) @@ -382,27 +408,11 @@ public class GameItem { switch (getItemType()) { case ITEM_WEAPON: - Weapon.Builder weapon = Weapon.newBuilder() - .setLevel(this.getLevel()) - .setExp(this.getExp()) - .setPromoteLevel(this.getPromoteLevel()); - - if (this.getAffixes() != null && this.getAffixes().size() > 0) { - for (int affix : this.getAffixes()) { - weapon.putAffixMap(affix, this.getRefinement()); - } - } - + Weapon weapon = this.toWeaponProto(); proto.setEquip(Equip.newBuilder().setWeapon(weapon).setIsLocked(this.isLocked()).build()); break; case ITEM_RELIQUARY: - Reliquary relic = Reliquary.newBuilder() - .setLevel(this.getLevel()) - .setExp(this.getExp()) - .setPromoteLevel(this.getPromoteLevel()) - .setMainPropId(this.getMainPropId()) - .addAllAppendPropIdList(this.getAppendPropIdList()) - .build(); + Reliquary relic = this.toReliquaryProto(); proto.setEquip(Equip.newBuilder().setReliquary(relic).setIsLocked(this.isLocked()).build()); break; case ITEM_MATERIAL: diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 0637e3d43..2d3442bbe 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -21,7 +21,6 @@ import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.PlayerProperty; -import emu.grasscutter.game.shop.ShopInfo; import emu.grasscutter.game.shop.ShopLimit; import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.World; @@ -34,6 +33,7 @@ import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass; import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo; import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass; +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; @@ -898,6 +898,35 @@ public class Player { .setFinishAchievementNum(0); return social; } + + public List getShowAvatarInfoList() { + List showAvatarInfoList = new ArrayList<>(); + + Player player; + boolean shouldRecalc; + if (this.isOnline()) { + player = this; + shouldRecalc = false; + } else { + player = DatabaseHelper.getPlayerById(id); + player.getAvatars().loadFromDatabase(); + player.getInventory().loadFromDatabase(); + shouldRecalc = true; + } + + List showAvatarList = player.getShowAvatarList(); + AvatarStorage avatars = player.getAvatars(); + if (showAvatarList != null) { + for (int avatarId : showAvatarList) { + Avatar avatar = avatars.getAvatarById(avatarId); + if (shouldRecalc) { + avatar.recalcStats(); + } + showAvatarInfoList.add(avatar.toShowAvatarInfoProto()); + } + } + return showAvatarInfoList; + } public PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo getWorldPlayerLocationInfo() { return PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo.newBuilder() diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetFriendShowAvatarInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetFriendShowAvatarInfoReq.java new file mode 100644 index 000000000..61fd31640 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetFriendShowAvatarInfoReq.java @@ -0,0 +1,26 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.GetFriendShowAvatarInfoReqOuterClass.GetFriendShowAvatarInfoReq; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketGetFriendShowAvatarInfoRsp; + +@Opcodes(PacketOpcodes.GetFriendShowAvatarInfoReq) +public class HandlerGetFriendShowAvatarInfoReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + GetFriendShowAvatarInfoReq req = GetFriendShowAvatarInfoReq.parseFrom(payload); + + int targetUid = req.getUid(); + Player targetPlayer = session.getServer().getPlayerByUid(targetUid, true); + + if (targetPlayer.isShowAvatars()) { + session.send(new PacketGetFriendShowAvatarInfoRsp(targetUid, targetPlayer.getShowAvatarInfoList())); + } + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetFriendShowAvatarInfoRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetFriendShowAvatarInfoRsp.java new file mode 100644 index 000000000..f9b640659 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetFriendShowAvatarInfoRsp.java @@ -0,0 +1,24 @@ +package emu.grasscutter.server.packet.send; + +import java.util.List; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.GetFriendShowAvatarInfoRspOuterClass.GetFriendShowAvatarInfoRsp; +import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass.ShowAvatarInfo; + +@Opcodes(PacketOpcodes.GetFriendShowAvatarInfoRsp) +public class PacketGetFriendShowAvatarInfoRsp extends BasePacket { + + public PacketGetFriendShowAvatarInfoRsp(int uid, List showAvatarInfoList) { + super(PacketOpcodes.GetFriendShowAvatarInfoRsp); + + GetFriendShowAvatarInfoRsp.Builder p = GetFriendShowAvatarInfoRsp.newBuilder() + .setUid(uid) + .addAllShowAvatarInfoList(showAvatarInfoList); + + this.setData(p.build()); + } + +}