diff --git a/Command/Command/Cmd/CommandGive.cs b/Command/Command/Cmd/CommandGive.cs index 86a82847..4e68026d 100644 --- a/Command/Command/Cmd/CommandGive.cs +++ b/Command/Command/Cmd/CommandGive.cs @@ -8,7 +8,7 @@ using Org.BouncyCastle.Ocsp; namespace EggLink.DanhengServer.Command.Cmd { - [CommandInfo("give", "Give item to player", "give l x r")] + [CommandInfo("give", "Game.Command.Give.Desc", "Game.Command.Give.Usage")] public class CommandGive : ICommand { [CommandDefault] diff --git a/Command/Command/Cmd/CommandHelp.cs b/Command/Command/Cmd/CommandHelp.cs index 7fe24971..1e921ae5 100644 --- a/Command/Command/Cmd/CommandHelp.cs +++ b/Command/Command/Cmd/CommandHelp.cs @@ -19,9 +19,15 @@ namespace EggLink.DanhengServer.Command.Cmd { return; } + foreach (var command in commands) { - arg.SendMsg($"/{command.Name} - {I18nManager.Translate(command.Description)}\n{I18nManager.Translate("Game.Command.Help.CommandUsage")} {I18nManager.Translate(command.Usage)}"); + var msg = $"/{command.Name} - {I18nManager.Translate(command.Description)}\n\n{I18nManager.Translate(command.Usage)}"; + if (command.Permission != "") + { + msg += $"\n\n{I18nManager.Translate("Game.Command.Help.CommandPermission")} {command.Permission}"; + } + arg.SendMsg(msg); } } } diff --git a/Command/Command/Cmd/CommandRelic.cs b/Command/Command/Cmd/CommandRelic.cs index e0ba6e77..42e21c57 100644 --- a/Command/Command/Cmd/CommandRelic.cs +++ b/Command/Command/Cmd/CommandRelic.cs @@ -59,7 +59,7 @@ namespace EggLink.DanhengServer.Command.Cmd int mainAffixId; if (arg.BasicArgs[1].Contains(':')) { - // 随机主词条 + // random main affix mainAffixId = mainAffixConfig.Keys.ToList().RandomElement(); } else @@ -91,9 +91,10 @@ namespace EggLink.DanhengServer.Command.Cmd subAffixes.Add((subId, subLevel)); remainLevel -= subLevel - 1; } + if (subAffixes.Count < 4) { - // 随机副词条 + // random sub affix var subAffixGroup = itemConfig.SubAffixGroup; var subAffixGroupConfig = GameData.RelicSubAffixData[subAffixGroup]; var subAffixGroupKeys = subAffixGroupConfig.Keys.ToList(); diff --git a/Command/Command/CommandManager.cs b/Command/Command/CommandManager.cs index 93198f24..fa67c175 100644 --- a/Command/Command/CommandManager.cs +++ b/Command/Command/CommandManager.cs @@ -89,7 +89,7 @@ namespace EggLink.DanhengServer.Command } } else { - // player + // player tempTarget = Listener.GetActiveConnection(sender.GetSender()); if (tempTarget == null) { @@ -110,6 +110,13 @@ namespace EggLink.DanhengServer.Command split.RemoveAt(0); var arg = new CommandArg(split.JoinFormat(" ", ""), sender, tempTarget); + + // judge permission + if (arg.Target?.Player?.Uid != sender.GetSender() && !sender.HasPermission("command.others")) + { + sender.SendMsg(I18nManager.Translate("Game.Command.Notice.NoPermission")); + return; + } // find the proper method with attribute CommandMethod var isFound = false; CommandInfo info = CommandInfo[cmd]; @@ -164,7 +171,7 @@ namespace EggLink.DanhengServer.Command { if (info != null) { - sender.SendMsg(I18nManager.Translate("Game.Command.Help.CommandUsage") + I18nManager.Translate(info.Usage)); + sender.SendMsg(I18nManager.Translate(info.Usage)); } else { diff --git a/Common/Internationalization/Message/LanguageCHS.cs b/Common/Internationalization/Message/LanguageCHS.cs index 0d56b613..c7e2b8cd 100644 --- a/Common/Internationalization/Message/LanguageCHS.cs +++ b/Common/Internationalization/Message/LanguageCHS.cs @@ -183,8 +183,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class HeroTextCHS { - public string Desc { get; } = "切换主角的性别/形态"; - public string Usage { get; } = "/hero /"; + public string Desc { get; } = "切换主角的性别/形态\n当切换性别时,genderId为1代表男性,2代表女性\n当切换形态时,8001代表毁灭命途,8003代表存护命途,8005代表同谐命途。\n注意,切换性别时会清空所有可选命途以及行迹,为不可逆操作!"; + public string Usage { get; } = "用法:/hero gender [genderId]\n\n用法:/hero type [typeId]"; public string GenderNotSpecified { get; } = "性别不存在!"; public string HeroTypeNotSpecified { get; } = "主角类型不存在!"; public string GenderChanged { get; } = "性别已更改!"; @@ -196,8 +196,9 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class UnlockAllTextCHS { - public string Desc { get; } = "解锁所有在类别内的对象"; - public string Usage { get; } = "/unlockall "; + public string Desc { get; } = "解锁所有在类别内的对象\n" + + "使用 /unlockall mission 以完成所有任务,使用后会被踢出,重新登录后可能会被教程卡住,请谨慎使用"; + public string Usage { get; } = "用法:/unlockall mission"; public string AllMissionsUnlocked { get; } = "所有任务已解锁!"; } @@ -206,9 +207,9 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class AvatarTextCHS { - public string Desc { get; } = "设定玩家已有角色的属性"; - public string Usage { get; } = "/avatar ///"; - public string InvalidLevel { get; } = "无效 {0}等级"; + public string Desc { get; } = "设定玩家已有角色的属性\n设置行迹等级时,设置X级即设置所有行迹节点至X级,若大于此节点允许的最高等级,设置为最高等级\n注意:-1意为所有已拥有角色"; + public string Usage { get; } = "用法:/avatar talent [角色ID/-1] [行迹等级]\n\n用法:/avatar get [角色ID]\n\n用法:/avatar rank [角色ID/-1] [星魂]\n\n用法:/avatar level [角色ID/-1] [角色等级]"; + public string InvalidLevel { get; } = "{0}等级无效"; public string AllAvatarsLevelSet { get; } = "已将全部角色 {0}等级设置为 {1}"; public string AvatarLevelSet { get; } = "已将 {0} 角色 {1}等级设置为 {2}"; public string AvatarNotFound { get; } = "角色不存在!"; @@ -221,8 +222,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class GiveTextCHS { - public string Desc { get; } = "给予玩家物品"; - public string Usage { get; } = "/give <物品ID> l<等级> x<数量> r<叠影>"; + public string Desc { get; } = "给予玩家物品,此处可输入角色ID,但无法设置行迹、等级及星魂"; + public string Usage { get; } = "用法:/give <物品ID> l<等级> x<数量> r<叠影>"; public string ItemNotFound { get; } = "未找到物品!"; public string GiveItem { get; } = "给予 @{0} {1} 个物品 {2}"; } @@ -232,8 +233,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class GiveAllTextCHS { - public string Desc { get; } = "给予玩家全部指定类型的物品"; - public string Usage { get; } = "/giveall r<叠影> l<等级> x<数量>"; + public string Desc { get; } = "给予玩家全部指定类型的物品\navatar意为角色,equipment意为光锥,relic意为遗器,unlock意为气泡、手机壁纸、头像"; + public string Usage { get; } = "用法:/giveall avatar r<星魂> l<等级>\n\n用法:/giveall equipment r<叠影> l<等级> x<数量>\n\n用法:/giveall relic l<等级> x<数量>\n\n用法:/giveall unlock"; public string GiveAllItems { get; } = "已给予所有 {0}, 各 {1} 个"; } @@ -242,8 +243,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class LineupTextCHS { - public string Desc { get; } = "管理玩家的队伍"; - public string Usage { get; } = "/lineup /"; + public string Desc { get; } = "管理玩家的队伍\n秘技点一次性只能获得两个"; + public string Usage { get; } = "用法:/lineup mp [秘技点数量]\n\n用法:/lineup heal"; public string PlayerGainedMp { get; } = "玩家已获得 {0} 秘技点"; public string HealedAllAvatars { get; } = "成功治愈当前队伍中的所有角色"; } @@ -254,9 +255,9 @@ namespace EggLink.DanhengServer.Internationalization.Message public class HelpTextCHS { public string Desc { get; } = "显示帮助信息"; - public string Usage { get; } = "/help"; + public string Usage { get; } = "用法:/help"; public string Commands { get; } = "命令:"; - public string CommandUsage { get; } = "用法: "; + public string CommandPermission { get; } = "所需权限: "; } /// @@ -265,7 +266,7 @@ namespace EggLink.DanhengServer.Internationalization.Message public class KickTextCHS { public string Desc { get; } = "踢出玩家"; - public string Usage { get; } = "/kick"; + public string Usage { get; } = "用法:/kick"; public string PlayerKicked { get; } = "玩家 {0} 已被踢出!"; } @@ -274,8 +275,11 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class MissionTextCHS { - public string Desc { get; } = "管理玩家的任务"; - public string Usage { get; } = "/mission ////"; + public string Desc { get; } = "管理玩家的任务\n" + + "使用 pass 完成当前正在进行的所有任务,此命令易造成严重卡顿,请尽量使用 /mission finish 替代\n" + + "使用 running 获取正在进行的任务以及可能卡住的任务,使用后可能会出现较长任务列表,请注意甄别\n" + + "使用 reaccept 可重新进行指定主任务,请浏览 handbook 来获取主任务ID"; + public string Usage { get; } = "用法:/mission pass\n\n用法:/mission finish [子任务ID]\n\n用法:/mission running\n\n用法:/mission reaccept [主任务ID]"; public string AllMissionsFinished { get; } = "所有任务已完成!"; public string AllRunningMissionsFinished { get; } = "共 {0} 个进行中的任务已完成!"; public string MissionFinished { get; } = "任务 {0} 已完成!"; @@ -294,8 +298,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class RelicTextCHS { - public string Desc { get; } = "管理玩家的遗器"; - public string Usage { get; } = "/relic <遗器ID> <主词条ID> <小词条ID1:小词条等级> <小词条ID2:小词条等级> <小词条ID3:小词条等级> <小词条ID4:小词条等级> l<等级> x<数量>"; + public string Desc { get; } = "管理玩家的遗器\n主词条可选,副词条可选,但至少存在其中之一\n等级限制:1≤等级≤9999"; + public string Usage { get; } = "用法:/relic <遗器ID> <主词条ID> <小词条ID1:小词条等级> <小词条ID2:小词条等级> <小词条ID3:小词条等级> <小词条ID4:小词条等级> l<等级> x<数量>"; public string RelicNotFound { get; } = "遗器不存在!"; public string InvalidMainAffixId { get; } = "主词条ID无效"; public string InvalidSubAffixId { get; } = "副词条ID无效"; @@ -307,8 +311,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class ReloadTextCHS { - public string Desc { get; } = "重新加载指定的配置"; - public string Usage { get; } = "/reload <配置名>(banner - 卡池, activity - 活动)"; + public string Desc { get; } = "重新加载指定的配置\n配置名:banner - 卡池, activity - 活动"; + public string Usage { get; } = "用法:/reload <配置名>"; public string ConfigReloaded { get; } = "配置 {0} 已重新加载!"; } @@ -317,8 +321,8 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class RogueTextCHS { - public string Desc { get; } = "管理玩家模拟宇宙中的数据"; - public string Usage { get; } = "/rogue ////"; + public string Desc { get; } = "管理玩家模拟宇宙中的数据\n-1意为所有祝福(已拥有祝福)\n使用 buff 来获取祝福\n使用 enhance 来强化祝福"; + public string Usage { get; } = "用法:/rogue money [宇宙碎片数量]\n\n用法:/rogue buff [祝福ID/-1]\n\n用法:/rogue miracle [奇物ID]\n\n用法:/rogue enhance [祝福ID/-1]\n\n用法:/rogue unstuck - 脱离事件"; public string PlayerGainedMoney { get; } = "玩家已获得 {0} 宇宙碎片"; public string PlayerGainedAllItems { get; } = "玩家已获得所有{0}"; public string PlayerGainedItem { get; } = "玩家已获得{0} {1}"; @@ -333,8 +337,14 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class SceneTextCHS { - public string Desc { get; } = "管理玩家场景"; - public string Usage { get; } = "/scene ////"; + public string Desc { get; } = "管理玩家场景\n" + + "提示:此组大多为调试使用,使用命令前,请确保你清楚你在做什么!\n" + + "使用 prop 来设置道具状态,在Common/Enums/Scene/PropStateEnum.cs获取状态列表\n" + + "使用 unlockall 来解锁场景内所有道具(即将所有能设置为open状态的道具设置为open状态),此命令有较大可能会导致游戏加载卡条约90%,使用 /scene reset 来解决问题\n" + + "使用 change 来进入指定场景,要获取EntryId,请访问 Resources/MapEntrance.json\n" + + "使用 reload 来重新加载当前场景,并回到初始位置\n" + + "使用 reset 来重置指定场景所有道具状态,要获取当前FloorId,请访问数据库 Player 表"; + public string Usage { get; } = "用法:/scene prop [组ID] [道具ID] [状态]\n\n用法:/scene remove [实体ID]\n\n用法:/scene unlockall\n\n用法:/scene change [entryId]\n\n用法:/scene reload\n\n用法:/scene reset "; public string LoadedGroups { get; } = "已加载组: {0}"; public string PropStateChanged { get; } = "道具: {0} 的状态已设置为 {1}"; public string PropNotFound { get; } = "未找到道具!"; @@ -352,7 +362,7 @@ namespace EggLink.DanhengServer.Internationalization.Message public class MailTextCHS { public string Desc { get; } = "管理玩家的邮件"; - public string Usage { get; } = "/mail /"; + public string Usage { get; } = "用法:/mail send [发送名称] [标题] [内容] [模板ID] [过期天数]"; public string MailSent { get; } = "邮件已发送!"; public string MailSentWithAttachment { get; } = "带附件的邮件已发送!"; } @@ -363,7 +373,7 @@ namespace EggLink.DanhengServer.Internationalization.Message public class RaidTextCHS { public string Desc { get; } = "管理玩家的任务临时场景"; - public string Usage { get; } = "/raid "; + public string Usage { get; } = "用法:/raid leave - 离开临时场景"; public string Leaved { get; } = "已离开临时场景!"; } /// @@ -371,9 +381,9 @@ namespace EggLink.DanhengServer.Internationalization.Message /// public class AccountTextCHS { - public string Desc { get; } = "创建账号"; - public string Usage { get; } = "/account create <用户名>"; - public string InvalidUid { get; } = "无效UID参数! "; + public string Desc { get; } = "创建账号\n注意:此命令未经测试,请谨慎使用!"; + public string Usage { get; } = "用法:/account create <用户名>"; + public string InvalidUid { get; } = "无效UID参数!"; public string CreateError { get; } = "出现内部错误 {0} "; public string CreateSuccess { get; } = "新账号 {0} 创建成功!"; public string DuplicateAccount { get; } = "账号 {0} 已存在!"; diff --git a/GameServer/Command/PlayerCommandSender.cs b/GameServer/Command/PlayerCommandSender.cs index 1902f655..341e6e95 100644 --- a/GameServer/Command/PlayerCommandSender.cs +++ b/GameServer/Command/PlayerCommandSender.cs @@ -18,7 +18,7 @@ namespace EggLink.DanhengServer.GameServer.Command public void SendMsg(string msg) { - Player.SendPacket(new PacketRevcMsgScNotify(toUid: (uint)Player.Uid, fromUid: (uint)ConfigManager.Config.ServerOption.ServerProfile.Uid, msg)); + Player.SendPacket(new PacketRevcMsgScNotify(toUid: (uint)Player.Uid, fromUid: (uint)ConfigManager.Config.ServerOption.ServerProfile.Uid, msg.Replace("\n", " "))); } public bool HasPermission(string permission) diff --git a/GameServer/Game/Inventory/InventoryManager.cs b/GameServer/Game/Inventory/InventoryManager.cs index 212792a1..e55a483e 100644 --- a/GameServer/Game/Inventory/InventoryManager.cs +++ b/GameServer/Game/Inventory/InventoryManager.cs @@ -4,6 +4,7 @@ using EggLink.DanhengServer.Database.Avatar; using EggLink.DanhengServer.Database.Inventory; using EggLink.DanhengServer.Enums.Item; using EggLink.DanhengServer.Game.Player; +using EggLink.DanhengServer.GameServer.Server.Packet.Send.Others; using EggLink.DanhengServer.Proto; using EggLink.DanhengServer.Server.Packet.Send.Avatar; using EggLink.DanhengServer.Server.Packet.Send.Player; @@ -64,6 +65,11 @@ namespace EggLink.DanhengServer.Game.Inventory switch (itemConfig.ItemMainType) { case ItemMainTypeEnum.Equipment: + if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_EQUIPMENT) // get the max equipment + { + Player.SendPacket(new PacketRetcodeNotify(Retcode.RetEquipmentExceedLimit)); + break; + } itemData = PutItem(itemId, 1, rank: rank, level: level, uniqueId: ++Data.NextUniqueId); break; case ItemMainTypeEnum.Usable: @@ -90,6 +96,11 @@ namespace EggLink.DanhengServer.Game.Inventory }; break; case ItemMainTypeEnum.Relic: + if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_RELIC) // get the max relic, i dont think one player can have more than max count of relic until i see a player get 50000 relic and the client crashed :( + { + Player.SendPacket(new PacketRetcodeNotify(Retcode.RetRelicExceedLimit)); + break; + } var item = PutItem(itemId, 1, rank: 1, level: 0, uniqueId: ++Data.NextUniqueId); item.AddRandomRelicMainAffix(); item.AddRandomRelicSubAffix(3); @@ -217,9 +228,19 @@ namespace EggLink.DanhengServer.Game.Inventory Data.MaterialItems.Add(item); break; case ItemMainTypeEnum.Equipment: + if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_EQUIPMENT) + { + Player.SendPacket(new PacketRetcodeNotify(Retcode.RetEquipmentExceedLimit)); + return item; + } Data.EquipmentItems.Add(item); break; case ItemMainTypeEnum.Relic: + if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_RELIC) + { + Player.SendPacket(new PacketRetcodeNotify(Retcode.RetRelicExceedLimit)); + return item; + } Data.RelicItems.Add(item); break; } diff --git a/GameServer/Server/Packet/Send/Others/PacketRetcodeNotify.cs b/GameServer/Server/Packet/Send/Others/PacketRetcodeNotify.cs new file mode 100644 index 00000000..20d5beb3 --- /dev/null +++ b/GameServer/Server/Packet/Send/Others/PacketRetcodeNotify.cs @@ -0,0 +1,23 @@ +using EggLink.DanhengServer.Proto; +using EggLink.DanhengServer.Server.Packet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Others +{ + public class PacketRetcodeNotify : BasePacket + { + public PacketRetcodeNotify(Retcode retcode) : base(CmdIds.RetcodeNotify) + { + var proto = new RetcodeNotify + { + Retcode = retcode // original proto is uint, i modify it to Retcode enum + }; + + SetData(proto); + } + } +} diff --git a/Program/Handbook/HandbookGenerator.cs b/Program/Handbook/HandbookGenerator.cs index 13772fe6..c4467c05 100644 --- a/Program/Handbook/HandbookGenerator.cs +++ b/Program/Handbook/HandbookGenerator.cs @@ -34,6 +34,9 @@ namespace EggLink.DanhengServer.Handbook var builder = new StringBuilder(); builder.AppendLine("Handbook generated in " + DateTime.Now.ToString("yyyy/MM/dd HH:mm")); + builder.AppendLine(); + builder.AppendLine("#Command"); + builder.AppendLine(); GenerateCmd(builder); builder.AppendLine(); @@ -83,10 +86,9 @@ namespace EggLink.DanhengServer.Handbook { foreach (var cmd in EntryPoint.CommandManager.CommandInfo) { - builder.Append("Command: " + cmd.Key); - builder.Append(" --- Description: " + I18nManager.Translate(cmd.Value.Description)); - builder.Append(" --- Usage: " + I18nManager.Translate(cmd.Value.Usage)); - builder.AppendLine(); + builder.Append("\t" + cmd.Key); + var desc = I18nManager.Translate(cmd.Value.Description).Replace("\n", "\n\t\t"); + builder.AppendLine(": " + desc); } }