From d9441a2188ebe6dfd766092dc8ce94f5fab66a5a Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Wed, 27 Apr 2022 11:37:50 +0200 Subject: [PATCH 01/16] 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/16] 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 79165aa4029973df989a40ca6a52f66a07ad0c02 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: Fri, 29 Apr 2022 22:31:22 +0800 Subject: [PATCH 03/16] Add command to get reliquary with specific props (#300) --- README.md | 29 +++--- README_zh-CN.md | 11 +-- .../command/commands/GiveArtifactCommand.java | 88 +++++++++++++++++++ .../grasscutter/game/inventory/GameItem.java | 4 + 4 files changed, 113 insertions(+), 19 deletions(-) create mode 100644 src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java diff --git a/README.md b/README.md index 927fc7a8c..e40ffe12a 100644 --- a/README.md +++ b/README.md @@ -106,37 +106,38 @@ There is a dummy user named "Server" in every player's friends list that you can | Commands | Usage | Permission node | Availability | description | Alias | | -------------- | ------------------------------------------------- | ------------------------- | ------------ | ------------------------------------------------------------ | ----------------------------------------------- | -| account | account [UID] | | Server only | Creates an account with the specified username and the in-game UID for that account. The UID will be auto generated if not set. | | -| broadcast | broadcast | server.broadcast | Both side | Sends a message to all the players. | b | -| coop | coop | server.coop | Both side | Forces someone to join the world of others. | | -| changescene | changescene | player.changescene | Client only | Switch scenes by scene ID. | scene | +| account | account \ [UID] | | Server only | Creates an account with the specified username and the in-game UID for that account. The UID will be auto generated if not set. | | +| broadcast | broadcast \ | server.broadcast | Both side | Sends a message to all the players. | b | +| coop | coop \ \ | server.coop | Both side | Forces someone to join the world of others. | | +| changescene | changescene \ | player.changescene | Client only | Switch scenes by scene ID. | scene | | clearartifacts | clearartifacts | player.clearartifacts | Client only | Deletes all unequipped and unlocked level 0 artifacts, including 5-star rarity ones from your inventory. | clearart | | 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] [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 | +| 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 | | 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. | | -| kick | kick | server.kick | Both side | Kicks the specified player from the server. (WIP) | k | +| kick | kick \ | server.kick | Both side | Kicks the specified player from the server. (WIP) | k | | killall | killall [playerUid] [sceneId] | server.killall | Both side | Kills all entities in the current scene or specified scene of the corresponding player. | | | list | list | | Both side | Lists online players. | | -| permission | permission | * | Both side | Grants or removes a permission for a user. | | +| permission | permission \ \ | * | Both side | Grants or removes a permission for a user. | | | position | position | | Client only | Sends your current coordinates. | pos | | reload | reload | server.reload | Both side | Reloads the server config | | | resetconst | resetconst [all] | player.resetconstellation | Client only | Resets the constellation level on your currently selected character, will need to relog after using the command to see any changes. | resetconstellation | | restart | | | Both side | Restarts the current session | | -| say | say | server.sendmessage | Both side | Sends a message to a player as the server | `sendservmsg` `sendservermessage` `sendmessage` | -| setfetterlevel | setfetterlevel | player.setfetterlevel | Client only | Sets the friendship level for your currently selected character | setfetterlvl | -| setstats | setstats | player.setstats | Client only | Sets a stat for your currently selected character | stats | -| setworldlevel | setworldlevel | player.setworldlevel | Client only | Sets your world level (Relog to see proper effects) | setworldlvl | +| say | say \ \ | server.sendmessage | Both side | Sends a message to a player as the server | `sendservmsg` `sendservermessage` `sendmessage` | +| setfetterlevel | setfetterlevel \ | player.setfetterlevel | Client only | Sets the friendship level for your currently selected character | setfetterlvl | +| setstats | setstats \ \ | player.setstats | Client only | Sets a stat for your currently selected character | stats | +| setworldlevel | setworldlevel \ | player.setworldlevel | Client only | Sets your world level (Relog to see proper effects) | setworldlvl | | 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 | +| 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 | | tpall | | player.tpall | Client only | Teleports all players in your world to your position | | -| weather | weather | player.weather | Client only | Changes the weather | w | +| weather | weather \ \ | player.weather | Client only | Changes the weather | w | ### Bonus diff --git a/README_zh-CN.md b/README_zh-CN.md index 6d3c92626..63a328f9f 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -109,18 +109,19 @@ chmod +x gradlew | -------------- | -------------------------------------------- | ------------------------- | -------- | ------------------------------------------ | ----------------------------------------------- | | account | account <用户名> [uid] | | 仅服务端 | 通过指定用户名和uid增删账户 | | | broadcast | broadcast <消息内容> | server.broadcast | 均可使用 | 给所有玩家发送公告 | b | -| coop | coop <目标uid> | server.coop | 均可使用 | 强制某位玩家进入指定玩家的多人世界 | | +| coop | coop \ <目标uid> | server.coop | 均可使用 | 强制某位玩家进入指定玩家的多人世界 | | | changescene | changescene <场景ID> | player.changescene | 仅客户端 | 切换到指定场景 | scene | | clearartifacts | clearartifacts | player.clearartifacts | 仅客户端 | 删除所有未装备及未解锁的圣遗物,包括五星 | clearart | | clearweapons | clearweapons | player.clearweapons | 仅客户端 | 删除所有未装备及未解锁的武器,包括五星 | clearwp | | drop | drop <物品ID\|物品名称> [数量] | server.drop | 仅客户端 | 在指定玩家周围掉落指定物品 | `d` `dropitem` | | give | give [uid] <物品ID\|物品名称> [数量] [等级] [精炼等级] | | | 给予指定玩家一定数量及等级的物品 (精炼等级仅适用于武器) | `g` `item` `giveitem` | -| givechar | givechar <角色ID> [等级] | player.givechar | 均可使用 | 给予指定玩家对应角色 | givec | +| givechar | givechar \ <角色ID> [等级] | player.givechar | 均可使用 | 给予指定玩家对应角色 | givec | +| giveart | giveart [uid] \<圣遗物ID> \<主属性ID> [\<副属性ID>[,<次数>]]... [等级] | player.giveart | 均可使用 | 给予玩家指定属性的圣遗物 | givea | | giveall | giveall [uid] [数量] | player.giveall | 均可使用 | 给予指定玩家全部物品 | givea | | godmode | godmode [uid] | player.godmode | 仅客户端 | 保护你不受到任何伤害(依然会被击退) | | | heal | heal | player.heal | 仅客户端 | 治疗队伍中所有角色 | h | | help | help [命令] | | 均可使用 | 显示帮助或展示指定命令的帮助 | | -| kick | kick | server.kick | 均可使用 | 从服务器中踢出指定玩家 (WIP) | k | +| kick | kick \ | server.kick | 均可使用 | 从服务器中踢出指定玩家 (WIP) | k | | killall | killall [uid] [场景ID] | server.killall | 均可使用 | 杀死指定玩家世界中所在或指定场景的全部生物 | | | list | list | | 均可使用 | 列出在线玩家 | | | permission | permission <用户名> <权限节点> | * | 均可使用 | 添加或移除玩家的权限 | | @@ -128,14 +129,14 @@ chmod +x gradlew | reload | reload | server.reload | 均可使用 | 重载服务器配置 | | | resetconst | resetconst [all] | player.resetconstellation | 仅客户端 | 重置当前角色的命座,重新登录即可生效 | resetconstellation | | restart | restart | | 均可使用 | 重启服务端 | | -| say | say <消息> | server.sendmessage | 均可使用 | 作为服务器发送消息给玩家 | `sendservmsg` `sendservermessage` `sendmessage` | +| say | say \ <消息> | server.sendmessage | 均可使用 | 作为服务器发送消息给玩家 | `sendservmsg` `sendservermessage` `sendmessage` | | setfetterlevel | setfetterlevel <好感等级> | player.setfetterlevel | 仅客户端 | 设置当前角色的好感等级 | `setfetterlvl` `setfriendship` | | setstats | setstats <属性> <数值> | player.setstats | 仅客户端 | 直接修改当前角色的面板 | stats | | setworldlevel | setworldlevel <世界等级> | player.setworldlevel | 仅客户端 | 设置世界等级(重新登陆即可生效) | setworldlvl | | spawn | spanw <实体ID\|实体名称> [等级] [数量] | server.spawn | 仅客户端 | 在你周围生成实体 | | | stop | stop | server.stop | 均可使用 | 停止服务器 | | | talent | talent <天赋ID> <等级> | player.settalent | 仅客户端 | 设置当前角色的天赋等级 | | -| teleport | teleport | player.teleport | 仅客户端 | 传送玩家到指定坐标 | tp | +| teleport | teleport \ \ \ | player.teleport | 仅客户端 | 传送玩家到指定坐标 | tp | | tpall | | player.tpall | 仅客户端 | 传送多人世界中所有的玩家到自身地点 | | | weather | weather <天气ID> <气候ID> | player.weather | 仅客户端 | 改变天气 | w | diff --git a/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java new file mode 100644 index 000000000..e33a287e3 --- /dev/null +++ b/src/main/java/emu/grasscutter/command/commands/GiveArtifactCommand.java @@ -0,0 +1,88 @@ +package emu.grasscutter.command.commands; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.def.ItemData; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.inventory.ItemType; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; + +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") +public final class GiveArtifactCommand implements CommandHandler { + @Override + public void execute(Player sender, List args) { + int size = args.size(), target, itemId, mainPropId, level; + ArrayList appendPropIdList = new ArrayList<>(); + String msg = "Usage: giveart|givea [player] [[,]]... [level]"; + + if (sender == null && size < 2) { + CommandHandler.sendMessage(null, msg); + return; + } + + if (size >= 2) { + try { + level = Integer.parseInt(args.get(size - 1)); + if (level <= 21) size--; + else level = 1; + target = Integer.parseInt(args.get(0)); + int fromIdx; + if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) { + target = sender.getUid(); + itemId = Integer.parseInt(args.get(0)); + mainPropId = Integer.parseInt(args.get(1)); + fromIdx = 2; + } else { + target = Integer.parseInt(args.get(0)); + itemId = Integer.parseInt(args.get(1)); + mainPropId = Integer.parseInt(args.get(2)); + fromIdx = 3; + } + args.subList(fromIdx, size).forEach(it -> { + String[] arr; + int n = 1; + if ((arr = it.split(",")).length == 2) { + it = arr[0]; + n = Integer.parseInt(arr[1]); + } + appendPropIdList.addAll(Collections.nCopies(n, Integer.parseInt(it))); + }); + } catch (Exception ignored) { + CommandHandler.sendMessage(sender, msg); + return; + } + } else { + CommandHandler.sendMessage(sender, msg); + return; + } + + Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target); + if (targetPlayer == null) { + CommandHandler.sendMessage(sender, "Player not found."); + return; + } + + ItemData itemData = GameData.getItemDataMap().get(itemId); + + if (itemData.getItemType() != ItemType.ITEM_RELIQUARY) { + CommandHandler.sendMessage(sender, "Invalid artifact ID."); + return; + } + + GameItem item = new GameItem(itemData); + item.setLevel(level); + item.setMainPropId(mainPropId); + item.getAppendPropIdList().addAll(appendPropIdList); + targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop); + + CommandHandler.sendMessage(sender, String.format("Given %s to %s.", itemId, target)); + } +} + diff --git a/src/main/java/emu/grasscutter/game/inventory/GameItem.java b/src/main/java/emu/grasscutter/game/inventory/GameItem.java index 8f3bef7f2..252c0a01c 100644 --- a/src/main/java/emu/grasscutter/game/inventory/GameItem.java +++ b/src/main/java/emu/grasscutter/game/inventory/GameItem.java @@ -244,6 +244,10 @@ public class GameItem { return mainPropId; } + public void setMainPropId(int mainPropId) { + this.mainPropId = mainPropId; + } + public List getAppendPropIdList() { return appendPropIdList; } From 7e6b20de1a42d1e86027c5275cd24b93ea8738bd Mon Sep 17 00:00:00 2001 From: BaiSugar <97774724+BaiSugar@users.noreply.github.com> Date: Sat, 30 Apr 2022 00:20:46 +0800 Subject: [PATCH 04/16] Added interface display for multiplayer games (#360) --- .../command/commands/GiveAllCommand.java | 3 ++ .../recv/HandlerGetOnlinePlayerListReq.java | 15 ++++++ .../send/PacketGetOnlinePlayerListRsp.java | 53 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerGetOnlinePlayerListReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java diff --git a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java index 94437e0e2..cdf2adbc1 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java @@ -83,6 +83,9 @@ public class GiveAllCommand implements CommandHandler { Avatar avatar = new Avatar(avatarData); avatar.setLevel(90); avatar.setPromoteLevel(6); + for(int i = 1;i <= 6;++i){ + avatar.getTalentIdList().add((avatar.getAvatarId()-10000000)*10+i); + } // This will handle stats and talents avatar.recalcStats(); player.addAvatar(avatar); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetOnlinePlayerListReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetOnlinePlayerListReq.java new file mode 100644 index 000000000..16dc591d5 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetOnlinePlayerListReq.java @@ -0,0 +1,15 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketGetOnlinePlayerListRsp; + +@Opcodes(PacketOpcodes.GetOnlinePlayerListReq) +public class HandlerGetOnlinePlayerListReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + session.send(new PacketGetOnlinePlayerListRsp(session.getPlayer())); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java new file mode 100644 index 000000000..85cf5429e --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetOnlinePlayerListRsp.java @@ -0,0 +1,53 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.GetOnlinePlayerListReqOuterClass; +import emu.grasscutter.net.proto.GetOnlinePlayerListRspOuterClass.*; +import emu.grasscutter.net.proto.MpSettingTypeOuterClass; +import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; +import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class PacketGetOnlinePlayerListRsp extends BasePacket { + public PacketGetOnlinePlayerListRsp(Player session){ + super(PacketOpcodes.GetOnlinePlayerListRsp); + Map playersMap = Grasscutter.getGameServer().getPlayers(); + 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(); + } + } + this.setData(proto); + } +} From 59ff79e23a0f5f98c426049fdf8dbd5a9a8cf067 Mon Sep 17 00:00:00 2001 From: lilmayofuksu Date: Fri, 29 Apr 2022 22:01:07 +0300 Subject: [PATCH 05/16] Limit the amount of vehicles that a player can spawn (#340) --- .../game/entity/EntityVehicle.java | 13 ++++++- .../packet/send/PacketVehicleInteractRsp.java | 38 ++++++++++++++++++- .../packet/send/PacketVehicleSpawnRsp.java | 25 +++++++++++- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java index c7609f89b..09f80e15b 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java @@ -18,24 +18,30 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.net.proto.VehicleInfoOuterClass.*; - +import emu.grasscutter.net.proto.VehicleMemberOuterClass.*; import emu.grasscutter.utils.Position; import emu.grasscutter.utils.ProtoHelper; import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; +import java.util.List; +import java.util.ArrayList; + public class EntityVehicle extends EntityBaseGadget { + private final Player owner; private final Int2FloatOpenHashMap fightProp; private final Position pos; private final Position rot; - private float curStamina; private final int pointId; private final int gadgetId; + private float curStamina; + private List vehicleMembers; + public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) { super(scene); this.owner = player; @@ -46,6 +52,7 @@ public class EntityVehicle extends EntityBaseGadget { this.gadgetId = gadgetId; this.pointId = pointId; this.curStamina = 240; + this.vehicleMembers = new ArrayList(); } @Override @@ -61,6 +68,8 @@ public class EntityVehicle extends EntityBaseGadget { public int getPointId() { return pointId; } + public List getVehicleMembers() { return vehicleMembers; } + @Override public Int2FloatOpenHashMap getFightProperties() { return fightProp; diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleInteractRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleInteractRsp.java index 73476e821..989aa3876 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleInteractRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleInteractRsp.java @@ -1,6 +1,7 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.entity.EntityVehicle; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.entity.GameEntity; @@ -17,16 +18,49 @@ public class PacketVehicleInteractRsp extends BasePacket { VehicleInteractRsp.Builder proto = VehicleInteractRsp.newBuilder(); GameEntity vehicle = player.getScene().getEntityById(entityId); - if(vehicle != null) { + + if(vehicle instanceof EntityVehicle) { proto.setEntityId(vehicle.getId()); - proto.setInteractType(interactType); VehicleMember vehicleMember = VehicleMember.newBuilder() .setUid(player.getUid()) .setAvatarGuid(player.getTeamManager().getCurrentCharacterGuid()) .build(); + proto.setInteractType(interactType); proto.setMember(vehicleMember); + + switch(interactType){ + case VEHICLE_INTERACT_IN -> { + ((EntityVehicle) vehicle).getVehicleMembers().add(vehicleMember); + } + case VEHICLE_INTERACT_OUT -> { + ((EntityVehicle) vehicle).getVehicleMembers().remove(vehicleMember); + } + default -> {} + } + } + this.setData(proto.build()); + } + + public PacketVehicleInteractRsp(EntityVehicle vehicle, VehicleMember vehicleMember, VehicleInteractType interactType) { + super(PacketOpcodes.VehicleInteractRsp); + VehicleInteractRsp.Builder proto = VehicleInteractRsp.newBuilder(); + + if(vehicle != null) { + proto.setEntityId(vehicle.getId()); + proto.setInteractType(interactType); + proto.setMember(vehicleMember); + + switch(interactType){ + case VEHICLE_INTERACT_IN -> { + vehicle.getVehicleMembers().add(vehicleMember); + } + case VEHICLE_INTERACT_OUT -> { + vehicle.getVehicleMembers().remove(vehicleMember); + } + default -> {} + } } this.setData(proto.build()); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleSpawnRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleSpawnRsp.java index 69b3d8e6f..fe8b2a1f1 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleSpawnRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleSpawnRsp.java @@ -8,10 +8,16 @@ import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; + +import emu.grasscutter.net.proto.VehicleMemberOuterClass.VehicleMember; import emu.grasscutter.net.proto.VehicleSpawnRspOuterClass.VehicleSpawnRsp; import emu.grasscutter.utils.Position; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; + +import java.util.List; + + +import static emu.grasscutter.net.proto.VehicleInteractTypeOuterClass.VehicleInteractType.VEHICLE_INTERACT_OUT; public class PacketVehicleSpawnRsp extends BasePacket { @@ -19,6 +25,23 @@ public class PacketVehicleSpawnRsp extends BasePacket { super(PacketOpcodes.VehicleSpawnRsp); VehicleSpawnRsp.Builder proto = VehicleSpawnRsp.newBuilder(); + // Eject vehicle members and Kill previous vehicles if there are any + List previousVehicles = player.getScene().getEntities().values().stream() + .filter(entity -> entity instanceof EntityVehicle + && ((EntityVehicle) entity).getGadgetId() == vehicleId + && ((EntityVehicle) entity).getOwner().equals(player)) + .toList(); + + previousVehicles.stream().forEach(entity -> { + List vehicleMembers = ((EntityVehicle) entity).getVehicleMembers().stream().toList(); + + vehicleMembers.stream().forEach(vehicleMember -> { + player.getScene().broadcastPacket(new PacketVehicleInteractRsp(((EntityVehicle) entity), vehicleMember, VEHICLE_INTERACT_OUT)); + }); + + player.getScene().killEntity(entity, 0); + }); + EntityVehicle vehicle = new EntityVehicle(player.getScene(), player, vehicleId, pointId, pos, rot); switch (vehicleId) { From 92b1ba7a183d90159f1729d215f726fe703c433d Mon Sep 17 00:00:00 2001 From: omg-xtao <100690902+omg-xtao@users.noreply.github.com> Date: Sat, 30 Apr 2022 04:33:13 +0800 Subject: [PATCH 06/16] Workflow supports manual and minimum enablement (#168) --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b61ac08c8..49a9d8b53 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,15 @@ name: "Build" on: + workflow_dispatch: ~ push: + paths: + - "**.java" branches: - "stable" - "development" pull_request: + paths: + - "**.java" types: - opened - synchronize From 8a9dab7d74357c01669df07f69f10015709a8a38 Mon Sep 17 00:00:00 2001 From: muhammadeko Date: Sat, 30 Apr 2022 06:49:49 +0700 Subject: [PATCH 07/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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) {