diff --git a/DataBase/DataAPI.cs b/API/DataAPI.cs similarity index 87% rename from DataBase/DataAPI.cs rename to API/DataAPI.cs index fad3c11..4d1ef0b 100644 --- a/DataBase/DataAPI.cs +++ b/API/DataAPI.cs @@ -1,9 +1,9 @@ -using EasyTools.DataBase.Serialization; +using EasyTools.DataStructures; using EasyTools.Events; using LiteDB; using System.Collections.Generic; -namespace EasyTools.DataBase +namespace EasyTools.API { public static class DataAPI { @@ -16,7 +16,7 @@ public static bool TryGetData(string id, out PlayerData data) { return true; } - using LiteDatabase database = new(CustomEventHandler.DataBaseConfig.database_path); + using LiteDatabase database = new(CustomEventHandler.Config.DataBasePath); if ((data = database.GetCollection("Players")?.FindById(id)) != null) { diff --git a/BadgeSystem/Badge.cs b/BadgeSystem/Badge.cs deleted file mode 100644 index 182ac77..0000000 --- a/BadgeSystem/Badge.cs +++ /dev/null @@ -1,131 +0,0 @@ -using EasyTools.Events; -using LabApi.Features.Wrappers; -using MEC; -using NewXp.IniApi; -using System.Collections.Generic; -using System.IO; -using Log = LabApi.Features.Console.Logger; - -namespace EasyTools.BadgeSystem -{ - public class Badge - { - public static string[] FMoreColo = - [ - "pink", - "silver", - "cyan", - "aqua", - "tomato", - "yellow", - "magenta", - "orange", - "lime", - "green", - "red", - "brown", - "red", - "orange", - "yellow", - "green", - "blue_green", - "magenta", - "pink", - "brown", - "silver", - "light_green", - "crimson", - "cyan", - "aqua", - "deep_pink", - "tomato", - "blue_green", - "lime", - "emerald", - "carmine", - "nickel", - "mint", - "army_green", - "pumpkin" - ]; - - public static List rainbw = new List(); - - public static IEnumerator Rainbw() - { - while (true) - { - foreach (var item in rainbw) - { - item.GroupColor = FMoreColo.RandomItem(); - } - yield return Timing.WaitForSeconds(CustomEventHandler.BadgeConfig.each); - } - - } - - public static void Handler(Player player) - { - string filePath = Path.Combine(CustomEventHandler.BadgeConfig.Pach, player.UserId + ".ini"); - - if (!File.Exists(filePath)) - { - IniFile iniFile = new IniFile(); - iniFile.Section("DIR").Set("称号", "空", "称号"); - iniFile.Section("DIR").Set("称号颜色", "空"); - iniFile.Section("DIR").Set("管理权限组", "空"); - iniFile.Save(filePath); - } - else - { - - IniFile iniFile = new IniFile(filePath); - iniFile.Save(filePath); - if (iniFile.Section("DIR").Get("管理权限组") == "空") - { - if (iniFile.Section("DIR").Get("称号") != "空") - { - player.GroupName = iniFile.Section("DIR").Get("称号"); - switch (iniFile.Section("DIR").Get("称号颜色")) - { - case "rainbow": - rainbw.Add(player); - break; - default: - player.GroupColor = iniFile.Section("DIR").Get("称号颜色"); - break; - } - } - - } - else - { - Server.RunCommand($"/setgroup {player.PlayerId} {iniFile.Section("DIR").Get("管理权限组")}"); - Log.Info($"已经给予{player.Nickname}-{player.UserId}==={iniFile.Section("DIR").Get("管理权限组")}权限"); - if (iniFile.Section("DIR").Get("称号") != "空") - { - player.GroupName = iniFile.Section("DIR").Get("称号"); - switch (iniFile.Section("DIR").Get("称号颜色")) - { - case "rainbow": - rainbw.Add(player); - break; - default: - player.GroupColor = iniFile.Section("DIR").Get("称号颜色"); - break; - } - } - } - } - } - - public static void Remove(Player player) - { - if (Badge.rainbw.Contains(player)) - { - Badge.rainbw.Remove(player); - } - } - - } -} diff --git a/Commands/Chat/AcCommand.cs b/Commands/Chat/AcCommand.cs index 0c2f14a..bb59d58 100644 --- a/Commands/Chat/AcCommand.cs +++ b/Commands/Chat/AcCommand.cs @@ -1,7 +1,7 @@ using CommandSystem; using EasyTools.Configs; using EasyTools.Events; -using EasyTools.Utils; +using EasyTools.Extensions; using LabApi.Features.Wrappers; using System; using Log = LabApi.Features.Console.Logger; @@ -24,7 +24,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s if (sender is null || (player = Player.Get(sender)) is null) { - response = TranslateConfig.ChatCommandError; + response = TranslateConfig.CommandNotAllowed; return false; } @@ -34,7 +34,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s return false; } - ChatUtils.SendMessage(player, ChatMessage.MessageType.AdminPrivateChat, $"{string.Join(" ", arguments)}"); + player.SendHintMessage(ChatMessage.MessageType.AdminPrivateChat, $"{string.Join(" ", arguments)}"); Log.Info(player.Nickname + " 发送了 " + arguments.At(0)); response = TranslateConfig.ChatCommandOk; diff --git a/Commands/Chat/BcCommand.cs b/Commands/Chat/BcCommand.cs index e1c77ec..837d241 100644 --- a/Commands/Chat/BcCommand.cs +++ b/Commands/Chat/BcCommand.cs @@ -1,7 +1,7 @@ using CommandSystem; using EasyTools.Configs; using EasyTools.Events; -using EasyTools.Utils; +using EasyTools.Extensions; using LabApi.Features.Wrappers; using System; using Log = LabApi.Features.Console.Logger; @@ -24,7 +24,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s if (sender is null || (player = Player.Get(sender)) is null) { - response = TranslateConfig.ChatCommandError; + response = TranslateConfig.CommandNotAllowed; return false; } @@ -34,10 +34,10 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s return false; } - ChatUtils.SendMessage(player, ChatMessage.MessageType.BroadcastChat, $"{string.Join(" ", arguments)}"); + player.SendHintMessage(ChatMessage.MessageType.BroadcastChat, $"{string.Join(" ", arguments)}"); Log.Info(player.Nickname + " 发送了 " + arguments.At(0)); - response = TranslateConfig.RescueCommandOk; + response = TranslateConfig.ChatCommandOk; return true; } } diff --git a/Commands/Chat/CCommand.cs b/Commands/Chat/CCommand.cs index 2f77026..4963a04 100644 --- a/Commands/Chat/CCommand.cs +++ b/Commands/Chat/CCommand.cs @@ -1,7 +1,7 @@ using CommandSystem; using EasyTools.Configs; using EasyTools.Events; -using EasyTools.Utils; +using EasyTools.Extensions; using LabApi.Features.Wrappers; using System; using Log = LabApi.Features.Console.Logger; @@ -24,7 +24,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s if (sender is null || (player = Player.Get(sender)) is null) { - response = TranslateConfig.ChatCommandError; + response = TranslateConfig.CommandNotAllowed; return false; } @@ -34,7 +34,7 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s return false; } - ChatUtils.SendMessage(player, ChatMessage.MessageType.TeamChat, $"{string.Join(" ", arguments)}"); + player.SendHintMessage(ChatMessage.MessageType.TeamChat, $"{string.Join(" ", arguments)}"); Log.Info(player.Nickname + " 发送了 " + arguments.At(0)); diff --git a/Commands/Level/XpCommand.cs b/Commands/Level/XpCommand.cs new file mode 100644 index 0000000..deced71 --- /dev/null +++ b/Commands/Level/XpCommand.cs @@ -0,0 +1,46 @@ +using CommandSystem; +using EasyTools.Configs; +using EasyTools.DataStructures; +using EasyTools.Events; +using EasyTools.Extensions; +using LabApi.Features.Wrappers; +using System; + +namespace EasyTools.Commands.Level +{ + [CommandHandler(typeof(ClientCommandHandler))] + public class XpCommand : ICommand + { + public string Command => "xp"; + + public string[] Aliases => []; + + public string Description => "查询经验"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + TranslateConfig TranslateConfig = CustomEventHandler.TranslateConfig; + Player player; + + if (sender is null || (player = Player.Get(sender)) is null) + { + response = TranslateConfig.CommandFailed; + return false; + } + + if (!CustomEventHandler.LevelSystemConfig.EnableLevelSystem) + { + response = CustomEventHandler.TranslateConfig.CommandNotEnabled; + return false; + } + + PlayerData data = player.GetData(); + double xp = data.PlayerXp; + int level = LevelExtensions.GetLevelFromXp(xp, CustomEventHandler.LevelSystemConfig.XpScaleFactor); + double needXp = LevelExtensions.GetXpUntilNextLevel(xp, CustomEventHandler.LevelSystemConfig.XpScaleFactor); + + response = $"你的等级: {level} | 当前经验: {xp} | 升级还需: {needXp} XP"; + return true; + } + } +} diff --git a/Commands/Scp/ReplaceScpCommand.cs b/Commands/Scp/ReplaceScpCommand.cs new file mode 100644 index 0000000..bf0e400 --- /dev/null +++ b/Commands/Scp/ReplaceScpCommand.cs @@ -0,0 +1,72 @@ +using CommandSystem; +using EasyTools.Events; +using LabApi.Features.Wrappers; +using PlayerRoles; +using System; +using UnityEngine; + +namespace EasyTools.Commands.Scp +{ + [CommandHandler(typeof(ClientCommandHandler))] + public class ReplaceScpCommand : ICommand + { + public string Command => "replace"; + + public string[] Aliases => ["rscp"]; + + public string Description => "申请补位一个断线SCP"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + Player player; + + if (sender is null || (player = Player.Get(sender)) is null || !(player = Player.Get(sender)).IsSCP) + { + response = CustomEventHandler.TranslateConfig.CommandNotAllowed; + return false; + } + + if (CustomEventHandler.Config.EnableSCPReplace) + { + response = CustomEventHandler.TranslateConfig.CommandNotEnabled; + return false; + } + + if (arguments.Count == 0) + { + response = "请指定要补位的 SCP 编号(Scp079|Scp096|Scp106|Scp173|Scp049|Scp3114)"; + return false; + } + + if (arguments.Count == 0) + { + response = "失败,未指定你要交换的目标(Scp079|Scp096|Scp106|Scp173|Scp049|Scp3114)"; + return false; + } + + string input = arguments.At(0); + if (!Enum.TryParse(input, out RoleTypeId targetRole)) + { + response = $"无效的 SCP 编号:{input}。可用的有 Scp079|Scp096|Scp106|Scp173|Scp049|Scp3114 (必须带Scp)"; + return false; + } + + if (!CustomEventHandler.Replacements.TryGetValue(targetRole, out var entry) || Time.time > entry.ExpireTime) + { + response = $"当前没有 {targetRole} 的补位名额或已过期。"; + return false; + } + + if (entry.Applicants.Contains(player)) + { + response = "你已经申请过该角色了,请等待系统分配。"; + return false; + } + + entry.Applicants.Add(player); + float remaining = entry.ExpireTime - Time.time; + response = $"你已申请补位 {targetRole},等待 {remaining:0.0} 秒后系统随机选择。"; + return true; + } + } +} diff --git a/Commands/Scp/SwapAcceptCommand.cs b/Commands/Scp/SwapAcceptCommand.cs new file mode 100644 index 0000000..d910bfd --- /dev/null +++ b/Commands/Scp/SwapAcceptCommand.cs @@ -0,0 +1,73 @@ +using CommandSystem; +using EasyTools.Events; +using LabApi.Features.Wrappers; +using System; +using Log = LabApi.Features.Console.Logger; + +namespace EasyTools.Commands.Scp +{ + [CommandHandler(typeof(ClientCommandHandler))] + public class SwapAcceptCommand : ICommand + { + public string Command => "swapaccept"; + + public string[] Aliases => ["spa"]; + + public string Description => "同意与其他SCP的交换请求"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + Player player; + + if (sender is null || (player = Player.Get(sender)) is null || !(player = Player.Get(sender)).IsSCP) + { + response = CustomEventHandler.TranslateConfig.CommandNotAllowed; + return false; + } + + if (CustomEventHandler.Config.EnableSCPStartExchange) + { + response = CustomEventHandler.TranslateConfig.CommandNotEnabled; + return false; + } + + if ((DateTime.Now - CustomEventHandler.RoundStartTime).TotalSeconds > CustomEventHandler.Config.SCPStartExchangeTime) + { + response = CustomEventHandler.TranslateConfig.SwapCommandTimeLimitBroadcastTemplate; + return false; + } + + // 检查是否有发给自己的请求 + if (!CustomEventHandler.SwapRequests.TryGetValue(player, out Player requester)) + { + response = CustomEventHandler.TranslateConfig.SwapCommandNoRequestBroadcastTemplate; + return false; + } + + // 检查发起请求的玩家是否仍然在线且为 SCP + if (requester == null || !requester.IsSCP) + { + CustomEventHandler.SwapRequests.Remove(player); + response = "请求已失效,对方已离线或不再是 SCP。"; + return false; + } + + // 交换并从列表中移除 + var tempRole = requester.Role; + requester.Role = player.Role; + player.Role = tempRole; + + CustomEventHandler.SwapRequests.Remove(player); + + // 通知玩家 + string msg = $"交换成功! {requester.Nickname} 与 {player.Nickname} 已交换 SCP 身份。"; + requester.SendBroadcast(msg, 5); + player.SendBroadcast(msg, 5); + + Log.Info($"{player.Nickname} 与 {requester.Nickname} 交换成功"); + + response = "交换成功"; + return true; + } + } +} diff --git a/Commands/Scp/SwapDenyCommand.cs b/Commands/Scp/SwapDenyCommand.cs new file mode 100644 index 0000000..13bb609 --- /dev/null +++ b/Commands/Scp/SwapDenyCommand.cs @@ -0,0 +1,61 @@ +using CommandSystem; +using EasyTools.Events; +using LabApi.Features.Wrappers; +using System; +using Log = LabApi.Features.Console.Logger; + +namespace EasyTools.Commands.Scp +{ + [CommandHandler(typeof(ClientCommandHandler))] + public class SwapDenyCommand : ICommand + { + public string Command => "swapdeny"; + + public string[] Aliases => ["spd"]; + + public string Description => "拒绝与其他SCP的交换请求"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + Player player; + + if (sender is null || (player = Player.Get(sender)) is null || !(player = Player.Get(sender)).IsSCP) + { + response = CustomEventHandler.TranslateConfig.CommandNotAllowed; + return false; + } + + if (CustomEventHandler.Config.EnableSCPStartExchange) + { + response = CustomEventHandler.TranslateConfig.CommandNotEnabled; + return false; + } + + if ((DateTime.Now - CustomEventHandler.RoundStartTime).TotalSeconds > CustomEventHandler.Config.SCPStartExchangeTime) + { + response = CustomEventHandler.TranslateConfig.SwapCommandTimeLimitBroadcastTemplate; + return false; + } + + // 检查是否有发给自己的请求 + if (!CustomEventHandler.SwapRequests.TryGetValue(player, out Player requester)) + { + response = CustomEventHandler.TranslateConfig.SwapCommandNoRequestBroadcastTemplate; + return false; + } + + // 清理请求 + CustomEventHandler.SwapRequests.Remove(player); + + // 通知玩家 + player.SendBroadcast($"你拒绝了与 {requester.Nickname} 的交换请求", 5); + requester.SendBroadcast($"{player.Nickname} 拒绝了你的交换请求", 5); + + + Log.Info($"{player.Nickname} 与 {requester.Nickname} 交换失败"); + + response = "交换失败"; + return true; + } + } +} diff --git a/Commands/Scp/SwapScpCommand.cs b/Commands/Scp/SwapScpCommand.cs new file mode 100644 index 0000000..72724b4 --- /dev/null +++ b/Commands/Scp/SwapScpCommand.cs @@ -0,0 +1,89 @@ +using CommandSystem; +using EasyTools.Events; +using LabApi.Features.Wrappers; +using PlayerRoles; +using System; +using System.Linq; +using Log = LabApi.Features.Console.Logger; + +namespace EasyTools.Commands.Scp +{ + [CommandHandler(typeof(ClientCommandHandler))] + public class SwapScpCommand : ICommand + { + public string Command => "swap"; + + public string[] Aliases => ["sp"]; + + public string Description => "申请与其他SCP交换"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + Player player; + + if (sender is null || (player = Player.Get(sender)) is null || !(player = Player.Get(sender)).IsSCP) + { + response = CustomEventHandler.TranslateConfig.CommandNotAllowed; + return false; + } + + if (CustomEventHandler.Config.EnableSCPStartExchange) + { + response = CustomEventHandler.TranslateConfig.CommandNotEnabled; + return false; + } + + if ((DateTime.Now - CustomEventHandler.RoundStartTime).TotalSeconds > CustomEventHandler.Config.SCPStartExchangeTime) + { + response = CustomEventHandler.TranslateConfig.SwapCommandTimeLimitBroadcastTemplate; + return false; + } + + if (arguments.Count == 0) + { + response = "失败,未指定你要交换的目标(Scp079|Scp096|Scp106|Scp173|Scp049|Scp3114)"; + return false; + } + + string input = arguments.At(0); + if (!Enum.TryParse(input, out RoleTypeId targetRole)) + { + response = $"无效的 SCP 编号:{input}。可用的有 Scp079|Scp096|Scp106|Scp173|Scp049|Scp3114 (必须带Scp)"; + return false; + } + + // 防止与自己交换 + if (player.Role == targetRole) + { + response = "你不能与自己交换。"; + return false; + } + + // 确保目标SCP存在 + Player target = Player.List.FirstOrDefault(p => p.IsSCP && p.Role == targetRole); + if (target == null) + { + response = $"当前没有 {targetRole} 在线。"; + return false; + } + + // 检查是否已存在请求 + if (CustomEventHandler.SwapRequests.ContainsKey(target)) + { + response = $"已有一个交换请求发送给 {target.Nickname},请等待对方回应。"; + return false; + } + + // 保存请求 + CustomEventHandler.SwapRequests[target] = player; + + // 通知目标玩家 + target.SendBroadcast($"{player.Nickname} 想与你交换 SCP 身份!输入 .swapaccept 接受,或 .swapdeny 拒绝。", 10); + + Log.Info($"{player.Nickname} 申请与 {arguments.At(0)} 交换"); + + response = "申请成功"; + return true; + } + } +} diff --git a/Commands/System/BadgeCommand.cs b/Commands/System/BadgeCommand.cs new file mode 100644 index 0000000..99eec12 --- /dev/null +++ b/Commands/System/BadgeCommand.cs @@ -0,0 +1,91 @@ +using CommandSystem; +using EasyTools.DataStructures; +using EasyTools.Events; +using EasyTools.Extensions; +using LabApi.Features.Wrappers; +using System; + +namespace EasyTools.Commands.System +{ + [CommandHandler(typeof(ClientCommandHandler))] + public class BadgeCommand : ICommand + { + public string Command => "badge"; + + public string[] Aliases => []; + + public string Description => "设置玩家称号"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + Player player; + + if (sender is null || (player = Player.Get(sender)) is null) + { + response = CustomEventHandler.TranslateConfig.CommandFailed; + return false; + } + + PlayerData data = player.GetData(); + + if (data.PermissionLevel == PermissionLevel.Player) + { + response = CustomEventHandler.TranslateConfig.CommandNotAllowed; + return false; + } + + if (arguments.Count == 0) + { + response = "请输入要给予称号的 SteamId"; + return false; + } + + Player target = Player.Get(arguments.At(0)); + + if (target == null) + { + response = "无法查找到玩家"; + return false; + } + + PlayerData targetData = target.GetData(); + + if (arguments.Count < 2) + { + response = "请输入要设置的称号"; + return false; + } + + if (targetData.PermissionLevel != PermissionLevel.Player) + { + switch (targetData.PermissionLevel) + { + case PermissionLevel.Moderator: + targetData.Badge = $"{arguments.At(1)}(Lv{(int)PermissionLevel.Moderator}.MODERATOR)"; + break; + case PermissionLevel.Admin: + targetData.Badge = $"{arguments.At(1)}(Lv{(int)PermissionLevel.Admin}.ADMIN)"; + break; + case PermissionLevel.Owner: + targetData.Badge = $"{arguments.At(1)}(Lv{(int)PermissionLevel.Owner}.OWNER)"; + break; + default: + targetData.Badge = $"{arguments.At(1)}(Lv{(int)PermissionLevel.Moderator}.MODERATOR)"; + break; + } + } + else targetData.Badge = arguments.At(1); + + // 无颜色参数时默认为 rainbow + string color = arguments.Count >= 3 ? arguments.At(2) : "rainbow"; + targetData.BadgeColor = color; + + targetData.UpdateData(); + target.ApplyBadge(); + + string colorDisplay = color == "rainbow" ? "彩虹色" : color; + response = $"已将 {arguments.At(0)} 的称号设置为 {targetData.Badge},颜色为 {colorDisplay}"; + return true; + } + } +} diff --git a/Commands/KillMeCommand.cs b/Commands/System/KillMeCommand.cs similarity index 69% rename from Commands/KillMeCommand.cs rename to Commands/System/KillMeCommand.cs index 47f8718..c02ea4a 100644 --- a/Commands/KillMeCommand.cs +++ b/Commands/System/KillMeCommand.cs @@ -5,7 +5,7 @@ using RelativePositioning; using System; -namespace EasyTools.Commands +namespace EasyTools.Commands.System { [CommandHandler(typeof(ClientCommandHandler))] public class KillMeCommand : ICommand @@ -23,21 +23,27 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s if (sender is null || (player = Player.Get(sender)) is null) { - response = TranslateConfig.RescueCommandError; + response = TranslateConfig.CommandFailed; return false; } WaypointBase.GetRelativePosition(player.Position, out byte id, out _); - if (!player.IsAlive || !CustomEventHandler.Config.KillMeCommand) + if (!CustomEventHandler.Config.KillMeCommand) { - response = TranslateConfig.RescueCommandFailed; + response = TranslateConfig.CommandNotEnabled; + return false; + } + + if (!player.IsAlive) + { + response = TranslateConfig.CommandNotAllowed; return false; } player.Kill(); - response = TranslateConfig.RescueCommandOk; + response = TranslateConfig.CommandOk; return true; } } diff --git a/Commands/System/PermissionCommand.cs b/Commands/System/PermissionCommand.cs new file mode 100644 index 0000000..83210ce --- /dev/null +++ b/Commands/System/PermissionCommand.cs @@ -0,0 +1,71 @@ +using CommandSystem; +using EasyTools.DataStructures; +using EasyTools.Events; +using EasyTools.Extensions; +using LabApi.Features.Wrappers; +using System; + +namespace EasyTools.Commands.System +{ + [CommandHandler(typeof(GameConsoleCommandHandler))] + public class PermissionCommand : ICommand + { + public string Command => "eperm"; + + public string[] Aliases => []; + + public string Description => "玩家权限管理"; + + public bool Execute(ArraySegment arguments, ICommandSender sender, out string response) + { + if (!CustomEventHandler.Config.EnableAdmin) + { + response = CustomEventHandler.TranslateConfig.CommandNotEnabled; + return false; + } + + if (arguments.Count == 0) + { + response = "请输入要给予权限的 SteamId"; + return false; + } + + Player player = Player.Get(arguments.At(0)); + + if (player == null) + { + response = "无法查找到玩家"; + return false; + } + + if (arguments.Count == 1) + { + response = "请输入要给予的权限组 (moderator|admin|owner)"; + return false; + } + + if (!Enum.TryParse(arguments.At(1), true, out PermissionLevel level)) + { + response = "权限组无效,请输入 (moderator|admin|owner)"; + return false; + } + + PlayerData data = player.GetData(); + data.PermissionLevel = level; + data.Badge = level switch + { + PermissionLevel.Moderator => "(Lv1.MODERATOR)", + PermissionLevel.Admin => "(Lv2.ADMIN)", + PermissionLevel.Owner => "(Lv3.OWNER)", + _ => data.Badge + }; + data.BadgeColor = "rainbow"; + data.UpdateData(); + player.ApplyPermission(); + player.ApplyBadge(); + + response = $"设置成功"; + return true; + } + } +} diff --git a/Configs/BadgeConfig.cs b/Configs/BadgeConfig.cs index a31c8a1..b3eed6d 100644 --- a/Configs/BadgeConfig.cs +++ b/Configs/BadgeConfig.cs @@ -6,9 +6,7 @@ public class BadgeConfig { [Description("是否启用称号系统")] public bool Enable { get; set; } = true; - [Description("存储路径")] - public string Pach { get; set; } = "/home/shiroko/.config/DIRSave"; [Description("彩色称号更新频率")] - public int each { get; set; } = 1; + public int Each { get; set; } = 1; } } diff --git a/Configs/CoinConfig.cs b/Configs/CoinConfig.cs new file mode 100644 index 0000000..d811bdb --- /dev/null +++ b/Configs/CoinConfig.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.ComponentModel; + +namespace EasyTools.Configs +{ + public class CoinConfig + { + [Description("开启硬币抽卡?")] + public bool Enable { get; set; } = true; + + [Description("开局发放硬币?")] + public bool EnableRoundCoin { get; set; } = true; + + [Description("抽卡奖励列表,权重总和为 100(自动归一化也可),支持修改概率和奖励内容")] + public List Rewards { get; set; } = new List + { + // ---- 变成 SCP(每种0.075%,总和0.3%) ---- + new RewardSetting { Weight = 0.075f, Type = RewardType.ChangeRole, Param = "Scp939", Name = "SCP-939" }, + new RewardSetting { Weight = 0.075f, Type = RewardType.ChangeRole, Param = "Scp3114", Name = "SCP-3114" }, + new RewardSetting { Weight = 0.075f, Type = RewardType.ChangeRole, Param = "Scp106", Name = "SCP-106" }, + new RewardSetting { Weight = 0.075f, Type = RewardType.ChangeRole, Param = "Scp049", Name = "SCP-049" }, + + // ---- 0.7% 特殊武器 ---- + new RewardSetting { Weight = 0.7f, Type = RewardType.GiveItem, Param = "GunSCP127", Name = "SCP-127" }, + + // ---- 4% 指挥官卡 ---- + new RewardSetting { Weight = 4.0f, Type = RewardType.GiveItem, Param = "KeycardMTFCaptain", Name = "指挥官卡" }, + + // ---- 5% 可乐 ---- + new RewardSetting { Weight = 5.0f, Type = RewardType.GiveItem, Param = "SCP207", Name = "可乐" }, + + // ---- 15% 随机枪械(两种枪各7.5%) ---- + new RewardSetting { Weight = 7.5f, Type = RewardType.GiveItem, Param = "GunE11SR", Name = "狗官枪" }, + new RewardSetting { Weight = 7.5f, Type = RewardType.GiveItem, Param = "GunAK", Name = "AK-47" }, + + // ---- 10% 中士卡 ---- + new RewardSetting { Weight = 10.0f, Type = RewardType.GiveItem, Param = "KeycardMTFOperative", Name = "中士卡" }, + + // ---- 10% 再来一次 ---- + new RewardSetting { Weight = 10.0f, Type = RewardType.ExtraCoin, Name = "又获得了一个硬币" }, + + // ---- 10% 随机传送 ---- + new RewardSetting { Weight = 10.0f, Type = RewardType.TeleportToSCP, Name = "被传送到SCP旁边" }, + + // ---- 20% 医疗物品(SCP-500 和医疗包各10%) ---- + new RewardSetting { Weight = 10.0f, Type = RewardType.GiveItem, Param = "SCP500", Name = "SCP-500" }, + new RewardSetting { Weight = 10.0f, Type = RewardType.GiveItem, Param = "Medkit", Name = "医疗物品" }, + + // ---- 25% 什么都没有 ---- + new RewardSetting { Weight = 25.0f, Type = RewardType.None, Name = "损失了一个硬币" }, + }; + } + + public class RewardSetting + { + [Description("显示名称")] + public string Name { get; set; } = "未知奖励"; + + [Description("相对权重")] + public float Weight { get; set; } = 10f; + + [Description("奖励类型")] + public RewardType Type { get; set; } = RewardType.None; + + [Description("额外参数")] + public string Param { get; set; } = string.Empty; + } + + public enum RewardType + { + None, // 什么都没发生 + ChangeRole, // 变身SCP(Param = 角色ID) + GiveItem, // 给物品(Param = 物品ID) + GiveRandomGun, // 随机给一把枪(Param = 逗号分隔的枪械ID) + TeleportToSCP, // 传送到随机SCP旁(Param留空) + ExtraCoin, // 返还硬币(Param留空) + GiveMedical // 随机给医疗包或SCP500(Param留空) + } +} diff --git a/Configs/Config.cs b/Configs/Config.cs index de3d032..1087ab9 100644 --- a/Configs/Config.cs +++ b/Configs/Config.cs @@ -1,5 +1,4 @@ -using LabApi.Features.Wrappers; -using LabApi.Loader.Features.Paths; +using LabApi.Loader.Features.Paths; using System; using System.Collections.Generic; using System.ComponentModel; @@ -9,16 +8,23 @@ namespace EasyTools.Configs { public class Config { + [Description("数据库存储路径")] + public string DataBasePath { get; set; } = Path.Combine(PathManager.Configs.FullName ?? Environment.CurrentDirectory, @"EasyTools.db"); + + /// ///////////////////////////////////////////////// [Description("是否打开开局给D级人员一张卡")] public bool EnableRoundSupplies { get; set; } = true; + [Description("给D级人员什么卡?")] public ItemType ClassDCard { get; set; } = ItemType.KeycardJanitor; /// ///////////////////////////////////////////////// [Description("启用服务器定时广播")] public bool EnableAutoServerMessage { get; set; } = true; + [Description("服务器定时广播多久一次")] public int AutoServerMessageTime { get; set; } = 5; + [Description("服务器定时广播显示多久")] public ushort AutoServerMessageTimer { get; set; } = 5; @@ -28,30 +34,41 @@ public class Config /// ///////////////////////////////////////////////// [Description("启用.bc和.c聊天系统")] public bool EnableChatSystem { get; set; } = true; + [Description("聊天系统大小,默认20")] public int ChatSystemSize { get; set; } = 20; [Description("启用玩家反馈管理系统")] public bool EnableAcSystem { get; set; } = true; + [Description("一个人的聊天信息显示多久,单位为秒")] public int MessageTime { get; set; } = 10; [Description("聊天消息的格式,可用的标签为{Message},{MessageType}, {MessageTypeColor}, {SenderNickname},{SenderTeam},{SenderRole} ,{SenderTeamColor}, {CountDown}")] public string MessageTemplate { get; set; } = "[{CountDown}][{SenderTeam}][{SenderRole}][{MessageType}]{SenderNickname}: {Message}"; + + /// ///////////////////////////////////////////////// + [Description("是否启用管理权限系统")] + public bool EnableAdmin { get; set; } = true; // ///////////////////////////////////////////////// + [Description("是否启用玩家在线时长统计")] + public bool EnablePlayTime { get; set; } = true; + + /// ///////////////////////////////////////////////// [Description("防卡死命令")] public bool KillMeCommand { get; set; } = true; /// ///////////////////////////////////////////////// [Description("启用修改SCP血量系统")] public bool EnableChangeSCPHPSystem { get; set; } = true; + [Description("SCP173,SCP939,SCP049,SCP049-2,SCP096,SCP106血量")] - public List SCPsHP { get; set; } = [4200, 2700, 2300, 400, 2500, 2300]; + public List SCPsHP { get; set; } = [5200, 3000, 2800, 600, 3100, 2800]; /// ///////////////////////////////////////////////// [Description("是否开启保安下班")] - public bool GuardsCanEscape { get; set; } = false; + public bool GuardsCanEscape { get; set; } = true; [Description("选择保安下班变成的角色 (NtfSergeant, NtfCaptain, NtfPrivate, NtfSpecialist)")] public string EscapedGuardRole { get; set; } = "NtfCaptain"; @@ -64,8 +81,11 @@ public class Config public int PinkCandyWeight { get; set; } = 2; /// ///////////////////////////////////////////////// - [Description("Logger module settings / 日志模块设置")] - public bool EnableLogger { get; set; } = true; + [Description("是否记录玩家进出日志")] + public bool EnablePlayerLogger { get; set; } = true; + + [Description("是否记录管理员操作相关日志")] + public bool EnableAdminLogger { get; set; } = true; [Description("Player logger settings / 玩家日志保存路径")] public string PlayerLogPath { get; set; } = Path.Combine(PathManager.Configs.FullName ?? Environment.CurrentDirectory, "JoinLogs"); @@ -75,18 +95,15 @@ public class Config /// ///////////////////////////////////////////////// [Description("Is 207 harmless? / 是否开启207(可乐)无害?")] - public bool Harmless207 { get; set; } = true; - + public bool Harmless207 { get; set; } = false; [Description("Is 1853 harmless? / 是否开启1853(洗手液)无害?")] public bool Harmless1853 { get; set; } = true; - /// ///////////////////////////////////////////////// [Description("SCP静止回血?")] public bool EnableHealSCP { get; set; } = true; - [Description("等待多少秒后开始回血")] public float HealSCPSecend { get; set; } = 6; @@ -97,14 +114,31 @@ public class Config public int HealSCPQuantity { get; set; } = 2; /// ///////////////////////////////////////////////// - [Description("开启硬币抽卡?")] - public bool Coin { get; set; } = true; + [Description("开启回合结束友伤?")] + public bool EnableFriendFire { get; set; } = true; + + /// ///////////////////////////////////////////////// + + [Description("开启SCP开局交换?")] + public bool EnableSCPStartExchange { get; set; } = true; - [Description("开局发放硬币?")] - public bool EnableRoundCoin { get; set; } = true; + [Description("允许SCP开局交换的时间(以秒为单位)")] + public int SCPStartExchangeTime { get; set; } = 300; + + [Description("开启SCP掉线时补位?")] + public bool EnableSCPReplace { get; set; } = true; + + [Description("允许玩家输入补位指令的时间(以秒为单位)")] + public float SCPReplaceTime { get; set; } = 15f; /// ///////////////////////////////////////////////// - [Description("开启回合结束友伤?")] - public bool EnableFriendFire { get; set; } = true; + [Description("开启开局生成 SCP-3114?")] + public bool EnableSCP3114 { get; set; } = false; + + [Description("当服务器有多少玩家时才会生成 SCP-3114?")] + public int SCP3114Limit { get; set; } = 8; + + [Description("SCP-3114的生成概率(默认50%)")] + public float SCP3114Weight { get; set; } = 0.1f; } } diff --git a/Configs/CustomRoleConfig.cs b/Configs/CustomRoleConfig.cs deleted file mode 100644 index cec486b..0000000 --- a/Configs/CustomRoleConfig.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.ComponentModel; - -namespace EasyTools.Configs -{ - public class CustomRoleConfig - { - [Description("开启3114?")] - public bool spawn_scp_3114 { get; set; } = false; - [Description("当有多少人时才会生成3114?")] - public int spawn_scp_3114_limit { get; set; } = 8; - } -} diff --git a/Configs/DataBaseConfig.cs b/Configs/DataBaseConfig.cs deleted file mode 100644 index 382d648..0000000 --- a/Configs/DataBaseConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using LabApi.Loader.Features.Paths; -using System; -using System.ComponentModel; -using System.IO; - -namespace EasyTools.Configs -{ - public class DataBaseConfig - { - [Description("是否启用玩家数据储存系统")] - public bool database_enable { get; set; } = true; - [Description("数据库存储路径")] - public string database_path { get; set; } = Path.Combine(PathManager.Configs.FullName ?? Environment.CurrentDirectory, @"EasyTools.db"); - } -} diff --git a/Configs/HUDInfoConfig.cs b/Configs/HUDInfoConfig.cs index 4e29d95..261f621 100644 --- a/Configs/HUDInfoConfig.cs +++ b/Configs/HUDInfoConfig.cs @@ -5,27 +5,27 @@ namespace EasyTools.Configs public class HUDInfoConfig { [Description("是否显示SCP914提示信息")] - public bool info_914 { get; set; } = true; + public bool EnableScp914Info { get; set; } = true; [Description("是否显示电梯提示信息")] - public bool info_elevator { get; set; } = true; + public bool EnableElevatorInfo { get; set; } = true; /// ///////////////////////////////////////////////// [Description("914显示,X轴坐标(0为正中,-为左,+为右):")] - public float _914_x { get; set; } = 0; + public float Scp914DisplayX { get; set; } = 0; [Description("914显示,Y轴坐标(屏幕最上端大概100,最下端大概1000):")] - public float _914_y { get; set; } = 80; + public float Scp914DisplayY { get; set; } = 80; [Description("914显示,字体大小:")] - public int _914_font { get; set; } = 20; + public int Scp914FontSize { get; set; } = 20; /// ///////////////////////////////////////////////// [Description("电梯显示,X轴坐标(0为正中,-为左,+为右):")] - public float _elev_x { get; set; } = 0; + public float ElevatorDisplayX { get; set; } = 0; [Description("电梯显示,Y轴坐标(屏幕最上端大概100,最下端大概1000):")] - public float _elev_y { get; set; } = 800; + public float ElevatorDisplayY { get; set; } = 800; [Description("电梯显示,字体大小:")] - public int _elev_font { get; set; } = 20; + public int ElevatorFontSize { get; set; } = 20; [Description("电梯提示显示可见范围(操作者为中心):")] - public float elev_range { get; set; } = 10f; + public float ElevatorHintRange { get; set; } = 10f; } } diff --git a/Configs/LevelSystemConfig.cs b/Configs/LevelSystemConfig.cs new file mode 100644 index 0000000..4f75124 --- /dev/null +++ b/Configs/LevelSystemConfig.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; + +namespace EasyTools.Configs +{ + public class LevelSystemConfig + { + [Description("是否启用等级系统")] + public bool EnableLevelSystem { get; set; } = true; + [Description("是否计入机器人")] + public bool CountBot { get; set; } = false; + [Description("经验值缩放系数")] + public double XpScaleFactor { get; set; } = 1.0; + [Description("人类阵营击杀SCP时奖励的经验")] + public double HumanKillSCPXp { get; set; } = 100.0; + [Description("人类阵营击杀SCP-049-2时奖励的经验")] + public double HumanKillSCP0492Xp { get; set; } = 30.0; + [Description("人类阵营击杀敌对人类阵营时奖励的经验")] + public double HumanKillHumanXp { get; set; } = 5.0; + [Description("SCP击杀人类阵营时奖励的经验")] + public double SCPKillHumanXp { get; set; } = 5.0; + [Description("人类阵营逃离设施时奖励的经验")] + public double HumanEscapeXp { get; set; } = 20.0; + } +} diff --git a/Configs/TranslateConfig.cs b/Configs/TranslateConfig.cs index 0f38434..6f53c72 100644 --- a/Configs/TranslateConfig.cs +++ b/Configs/TranslateConfig.cs @@ -1,4 +1,4 @@ -using EasyTools.Utils; +using EasyTools.Extensions; using PlayerRoles; using Scp914; using System.Collections.Generic; @@ -8,17 +8,17 @@ namespace EasyTools.Configs { public class TranslateConfig { - [Description("自救指令_错误")] - public string RescueCommandError { get; set; } = "执行指令时发生错误,请稍后再试"; - [Description("自救指令_失败")] - public string RescueCommandFailed { get; set; } = "失败,可能指令未启用或者身份不允许等"; - [Description("自救指令_成功")] - public string RescueCommandOk { get; set; } = "成功"; - [Description("聊天指令_错误")] - public string ChatCommandError { get; set; } = "发送消息时出现错误,请稍后重试"; - [Description("聊天指令_失败")] + [Description("命令未启用时的提示")] + public string CommandNotEnabled { get; set; } = "该命令未启用"; + [Description("当前身份不允许执行命令时的提示")] + public string CommandNotAllowed { get; set; } = "当前身份不允许执行该命令"; + [Description("命令执行失败时的提示")] + public string CommandFailed { get; set; } = "执行失败,可能是参数错误等"; + [Description("命令执行成功时的提示")] + public string CommandOk { get; set; } = "执行成功"; + [Description("聊天信息发送失败时提示")] public string ChatCommandFailed { get; set; } = "发送失败,你被禁言或者信息为空或者聊天系统未启用"; - [Description("聊天指令_成功")] + [Description("聊天信息发送成功时提示")] public string ChatCommandOk { get; set; } = "发送成功"; /// /// @@ -78,11 +78,11 @@ public class TranslateConfig /// /// [Description("电梯显示模板(HEX color写死, {p_operator}表示操作人, 没有的话自动为未知):")] - public string elev_template { get; set; } = "[Elevator] 电梯使用者: {p_operator}"; - [Description("SCP914显示模板(HEX color写死, {mode}表示操作模式, {p_operator}表示操作人, 没有的话自动为未知):")] - public string scp914_template { get; set; } = "[Scp914] 已启动! 模式: {mode}, 操作人: {p_operator}"; - [Description("SCP914, Rough模式翻译:")] - public Dictionary scp914_trans { get; set; } = new Dictionary() + public string ElevatorTemplate { get; set; } = "[Elevator] 电梯使用者: {p_operator}"; + [Description("SCP-914 显示模板(HEX color写死, {mode}表示操作模式, {p_operator}表示操作人, 没有的话自动为未知):")] + public string Scp914Template { get; set; } = "[Scp914] 已启动! 模式: {mode}, 操作人: {p_operator}"; + [Description("SCP-914 模式翻译:")] + public Dictionary Scp914ModeTranslations { get; set; } = new Dictionary() { { Scp914KnobSetting.Rough, "粗加" }, { Scp914KnobSetting.Coarse, "半粗" }, @@ -90,5 +90,24 @@ public class TranslateConfig { Scp914KnobSetting.Fine, "精加" }, { Scp914KnobSetting.VeryFine, "超精加工" } }; + /// + /// + /// + [Description("等级系统_查询失败")] + public string LevelCommandFailed { get; set; } = "查询失败,等级系统未启用"; + /// + /// + /// + [Description("使用硬币抽卡时背包空间不足提示")] + public string RewardFailedBroadcastTemplate { get; set; } = "\n你的背包空间不足,无法继续抽卡!"; + [Description("使用硬币抽卡成功提示")] + public string RewardOkBroadcastTemplate { get; set; } = "\n🎉 恭喜!玩家 {nickName} 通过抛硬币{result}!"; + /// + /// + /// + [Description("开局三分钟后使用交换指令的禁止提示")] + public string SwapCommandTimeLimitBroadcastTemplate { get; set; } = "交换指令只能在开局三分钟内使用"; + [Description("没有待处理交换请求时提示")] + public string SwapCommandNoRequestBroadcastTemplate { get; set; } = "没有待处理的交换请求"; } } diff --git a/DataBase/Serialization/HintData.cs b/DataStructures/HintData.cs similarity index 84% rename from DataBase/Serialization/HintData.cs rename to DataStructures/HintData.cs index becfc59..9e6bb54 100644 --- a/DataBase/Serialization/HintData.cs +++ b/DataStructures/HintData.cs @@ -1,4 +1,4 @@ -namespace EasyTools.DataBase.Serialization +namespace EasyTools.DataStructures { public struct HintData { diff --git a/DataBase/Serialization/PlayerData.cs b/DataStructures/PlayerData.cs similarity index 58% rename from DataBase/Serialization/PlayerData.cs rename to DataStructures/PlayerData.cs index 5933e59..324f270 100644 --- a/DataBase/Serialization/PlayerData.cs +++ b/DataStructures/PlayerData.cs @@ -1,7 +1,7 @@ using LiteDB; using System; -namespace EasyTools.DataBase.Serialization +namespace EasyTools.DataStructures { [Serializable] public class PlayerData @@ -16,7 +16,20 @@ public class PlayerData public float PlayerDamage { get; set; } public int RolePlayed { get; set; } public int PlayerShot { get; set; } + public double PlayerXp { get; set; } + public double PlayerLevel { get; set; } + public PermissionLevel PermissionLevel { get; set; } = PermissionLevel.Player; + public string Badge { get; set; } = ""; + public string BadgeColor { get; set; } = "rainbow"; [BsonId] public string ID { get; set; } } + + public enum PermissionLevel + { + Player = 0, + Moderator = 1, + Admin = 2, + Owner = 3 + } } diff --git a/DataBase/Serialization/PlayerHint.cs b/DataStructures/PlayerHint.cs similarity index 97% rename from DataBase/Serialization/PlayerHint.cs rename to DataStructures/PlayerHint.cs index f3f9f0d..1fc7366 100644 --- a/DataBase/Serialization/PlayerHint.cs +++ b/DataStructures/PlayerHint.cs @@ -3,10 +3,10 @@ using HintServiceMeow.Core.Models.Hints; using HintServiceMeow.Core.Utilities; using LabApi.Features.Wrappers; -using System.Collections.Generic; using System; +using System.Collections.Generic; -namespace EasyTools.DataBase.Serialization +namespace EasyTools.DataStructures { public struct PlayerHint : IDisposable { diff --git a/EasyTools.csproj b/EasyTools.csproj index de27bde..5cdac5a 100644 --- a/EasyTools.csproj +++ b/EasyTools.csproj @@ -121,31 +121,39 @@ - + + + - + + + + + + + - - + - - - - - + + + + + - - + + + - - + + diff --git a/Events/CustomEventHandler.cs b/Events/CustomEventHandler.cs index e1e8fe9..29b3f64 100644 --- a/Events/CustomEventHandler.cs +++ b/Events/CustomEventHandler.cs @@ -1,8 +1,7 @@ -using EasyTools.BadgeSystem; -using EasyTools.Configs; -using EasyTools.DataBase.Serialization; -using EasyTools.Utils; -using Hints; +using EasyTools.Configs; +using EasyTools.DataStructures; +using EasyTools.Extensions; +using EasyTools.Helper; using InventorySystem.Items; using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Arguments.Scp914Events; @@ -30,17 +29,31 @@ public class CustomEventHandler : CustomEventsHandler public static BadgeConfig BadgeConfig; - public static CustomRoleConfig CustomRoleConfig; - - public static DataBaseConfig DataBaseConfig; + public static LevelSystemConfig LevelSystemConfig; public static HUDInfoConfig HUDInfoConfig; - public static CoroutineHandle Badge_Coroutine; + public static CoinConfig CoinConfig; + + public static CoroutineHandle BadgeCoroutine; + + public static readonly Dictionary PlayerHuds = new(); + + public static HintData Scp914HintData, ElevatorHintData; + + public static DateTime RoundStartTime { get; private set; } - public static readonly Dictionary _huds = new(); + // SCP交换列表 + public static volatile Dictionary SwapRequests = new Dictionary(); - public static HintData data_914, data_elevator; + // SCP补位列表 + public static readonly Dictionary Replacements = new(); + + public class ReplacementEntry + { + public List Applicants = new(); + public float ExpireTime; // Time.time + 10f + } public override void OnServerWaitingForPlayers() { @@ -48,8 +61,8 @@ public override void OnServerWaitingForPlayers() if (BadgeConfig.Enable) { - Badge.rainbw.Clear(); - Badge_Coroutine = Timing.RunCoroutine(Badge.Rainbw()); + BadgeExtensions.rainbw.Clear(); + BadgeCoroutine = Timing.RunCoroutine(BadgeExtensions.Rainbw()); } Server.FriendlyFire = false; @@ -57,19 +70,26 @@ public override void OnServerWaitingForPlayers() public override void OnServerRoundStarted() { + RoundStartTime = DateTime.Now; + Timing.CallDelayed(10f, () => { if (Config.EnableAutoServerMessage) { - Timing.RunCoroutine(Util.AutoServerBroadcast()); + Timing.RunCoroutine(ServerBroadcastHelper.AutoServerBroadcast()); } if (Config.EnableHealSCP) { - Timing.RunCoroutine(ScpReal.AutoReal()); + Timing.RunCoroutine(ScpAutoHealHelper.AutoReal()); } - _huds.Values.ToList().ForEach(h => h.Start()); + PlayerHuds.Values.ToList().ForEach(h => h.Start()); }); + + if (Config.EnablePlayTime) + { + Timing.RunCoroutine(DataExtensions.CollectInfo()); + } } public override void OnServerRoundEnded(RoundEndedEventArgs ev) @@ -78,7 +98,7 @@ public override void OnServerRoundEnded(RoundEndedEventArgs ev) if (BadgeConfig.Enable) { - Timing.KillCoroutines(Badge_Coroutine); + Timing.KillCoroutines(BadgeCoroutine); } if (Config.EnableFriendFire) @@ -96,34 +116,72 @@ public override void OnPlayerJoined(PlayerJoinedEventArgs ev) if (player == null || string.IsNullOrEmpty(player.UserId)) return; - ChatUtils.InitForPlayer(player); + player.InitChatHint(); + + DataExtensions.PlayerList.Add(player); + PlayerData data = player.GetData(); + data.NickName = player.Nickname; + data.LastJoinedTime = DateTime.Now; + data.UpdateData(); - if (Config.EnableLogger) + if (LevelSystemConfig.EnableLevelSystem) { - string playerInfo = $"[JOIN] Date: {DateTime.Now} | Player: {ev.Player.Nickname} | IP: {ev.Player.IpAddress} | Steam64ID: {ev.Player.UserId}"; - string path = Path.Combine(CustomEventHandler.Config.PlayerLogPath, $"{Server.Port}.log"); - Log.Info(playerInfo); + player.UpdatePlayerNameWithLevelPrefix(); + } - File.AppendAllText(path, playerInfo + Environment.NewLine); + if (Config.EnableAdmin) + { + player.ApplyPermission(); } + if (BadgeConfig.Enable) { - Badge.Handler(player); + player.ApplyBadge(); } - _huds[player] = new PlayerHint(player, data_914, data_elevator); + if (Config.EnablePlayerLogger) + { + string playerInfo = $"[JOIN] Date: {DateTime.Now} | Player: {ev.Player.Nickname} | IP: {ev.Player.IpAddress} | Steam64ID: {ev.Player.UserId}"; + string path = Path.Combine(CustomEventHandler.Config.PlayerLogPath, $"{Server.Port}.log"); + Log.Info(playerInfo); + + try + { + // 递归创建目录 + string dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) + { + Directory.CreateDirectory(dir); + } + + File.AppendAllText(path, playerInfo + Environment.NewLine); + } + catch (Exception e) + { + Log.Error(e.Message); + } + } + + PlayerHuds[player] = new PlayerHint(player, Scp914HintData, ElevatorHintData); } public override void OnPlayerLeft(PlayerLeftEventArgs ev) { Player player = ev.Player; + string nickName = player.Nickname; + string userId = player.UserId; if (player == null || string.IsNullOrEmpty(player.UserId)) return; - if (Config.EnableLogger) + DataExtensions.PlayerList.Remove(player); + PlayerData data = player.GetData(); + data.LastJoinedTime = DateTime.Now; + data.UpdateData(); + + if (Config.EnablePlayerLogger) { - string playerInfo = $"[EXIT] Date: {DateTime.Now} | Player: {ev.Player.Nickname} | IP: {ev.Player.IpAddress} | Steam64ID: {ev.Player.UserId}"; + string playerInfo = $"[EXIT] Date: {DateTime.Now} | Player: {nickName} | Steam64ID: {userId}"; string path = Path.Combine(CustomEventHandler.Config.PlayerLogPath, $"{Server.Port}.log"); Log.Info(playerInfo); @@ -132,37 +190,74 @@ public override void OnPlayerLeft(PlayerLeftEventArgs ev) if (BadgeConfig.Enable) { - Badge.Remove(player); + if (BadgeExtensions.rainbw.Contains(player)) + { + BadgeExtensions.rainbw.Remove(player); + } } - if (_huds.ContainsKey(player)) + if (PlayerHuds.ContainsKey(player)) { - _huds.Remove(player); + PlayerHuds.Remove(player); + } + + if (Config.EnableSCPReplace) + { + // 清理该玩家在所有补位申请中的记录(防止幽灵申请) + foreach (var entry in Replacements.Values) + entry.Applicants.Remove(player); + + if (player.IsSCP && player.Health > 0) + { + var role = player.Role; + + Replacements[role] = new ReplacementEntry + { + ExpireTime = Time.time + Config.SCPReplaceTime + }; + + Timing.CallDelayed(Config.SCPReplaceTime, () => ExecuteReplacement(role)); + } } } - public static volatile bool allow_spawn_scp_3114 = true; //用以确保不会重复生成SCP-3114 + private void ExecuteReplacement(RoleTypeId role) + { + if (!Replacements.TryGetValue(role, out var entry)) + return; + + // 从补位名单中筛选仍在线的人类玩家 + var valid = entry.Applicants.Where(p => p != null && p.IsHuman).ToList(); + + if (valid.Count == 0) + { + Server.SendBroadcast($"{role} 补位无人申请,该角色空缺。", 5); + return; + } + + // 随机选择 + var chosen = valid[UnityEngine.Random.Range(0, valid.Count)]; + chosen.Role = role; + + Server.SendBroadcast($"补位成功!{chosen.Nickname} 成为了 {role}。", 10); + Log.Info($"{chosen.Nickname} 补位成为 {role}"); + } + + private static volatile bool AllowSpawnScp3114 = true; //用以确保不会重复生成 SCP-3114 public override void OnPlayerSpawning(PlayerSpawningEventArgs ev) { - if (CustomRoleConfig.spawn_scp_3114 && allow_spawn_scp_3114) + if (Config.EnableSCP3114 && AllowSpawnScp3114) { - if (Player.ReadyList.Count() >= CustomRoleConfig.spawn_scp_3114_limit) + if (Player.ReadyList.Count() >= Config.SCP3114Limit && UnityEngine.Random.value < Config.SCP3114Weight) { - foreach (Player p in Player.ReadyList) + AllowSpawnScp3114 = false; + Timing.CallDelayed(0.5f, () => { - if ((UnityEngine.Random.Range(0, 10) == 3)) - { - Timing.CallDelayed(0.5f, () => - { - ev.Player.Role = RoleTypeId.Scp3114; - ev.IsAllowed = true; - allow_spawn_scp_3114 = false; - }); - } - } + ev.Player.Role = RoleTypeId.Scp3114; + ev.IsAllowed = true; + }); } - allow_spawn_scp_3114 = false; } } @@ -204,7 +299,7 @@ public override void OnPlayerSpawned(PlayerSpawnedEventArgs ev) }); } - if (Config.EnableRoundCoin) + if (CoinConfig.EnableRoundCoin) { if (Player.Role == RoleTypeId.ClassD || Player.Role == RoleTypeId.FacilityGuard || Player.Role == RoleTypeId.Scientist) { @@ -214,11 +309,43 @@ public override void OnPlayerSpawned(PlayerSpawnedEventArgs ev) }); } } - } + public override void OnPlayerDying(PlayerDyingEventArgs ev) + { + if (!LevelSystemConfig.EnableLevelSystem) return; + + // 避免处理非玩家击杀或无效情况 + if (ev.Attacker == null || ev.Player == null) + return; + + if (ev.Player.IsDummy && !LevelSystemConfig.CountBot) return; + + // 给击杀者添加经验 + PlayerData data = ev.Attacker.GetData(); + + if (ev.Attacker.IsSCP) + { + data.PlayerXp += LevelSystemConfig.SCPKillHumanXp; + } + else if (ev.Player.IsSCP) + { + if (ev.Player.Role == RoleTypeId.Scp0492) + { + data.PlayerXp += LevelSystemConfig.HumanKillSCP0492Xp; + } + else + { + data.PlayerXp += LevelSystemConfig.HumanKillSCPXp; + } + } + else + { + data.PlayerXp += LevelSystemConfig.HumanKillHumanXp; } + data.PlayerLevel = LevelExtensions.GetLevelFromXp(data.PlayerXp, LevelSystemConfig.XpScaleFactor); + ev.Attacker.UpdatePlayerNameWithLevelPrefix(); } public override void OnPlayerHurting(PlayerHurtingEventArgs ev) @@ -268,6 +395,18 @@ public override void OnPlayerEscaping(PlayerEscapingEventArgs ev) ev.IsAllowed = true; } } + + if (LevelSystemConfig.EnableLevelSystem) + { + PlayerData data = ev.Player.GetData(); + data.PlayerXp += LevelSystemConfig.HumanEscapeXp; + + data.PlayerLevel = LevelExtensions.GetLevelFromXp(data.PlayerXp, LevelSystemConfig.XpScaleFactor); + ev.Player.UpdatePlayerNameWithLevelPrefix(); + + // 通知玩家 + ev.Player.SendBroadcast("\n逃脱成功,获得20经验值", 3); + } } public override void OnPlayerInteractingScp330(PlayerInteractingScp330EventArgs ev) @@ -289,32 +428,24 @@ public override void OnServerCommandExecuted(CommandExecutedEventArgs ev) Player player = Player.Get(sender); - if (player != null && !string.IsNullOrEmpty(command) && Config.EnableLogger) + if (player != null && !string.IsNullOrEmpty(command) && Config.EnableAdminLogger) { if (!player.RemoteAdminAccess) return; - string note = $"Date: {DateTime.Now} | Player: {player.Nickname} | Command: {command} | Steam64ID: {player.UserId}"; + string note = $"[AC] Date: {DateTime.Now} | Player: {player.Nickname} | Command: {command} | Steam64ID: {player.UserId}"; string path = Path.Combine(CustomEventHandler.Config.AdminLogPath, $"{Server.Port}.log"); Log.Info(note); try { - if (!File.Exists(path)) - { - FileStream fs1 = new(path, FileMode.Create, FileAccess.Write); - StreamWriter sw = new(fs1); - sw.WriteLine(note); - sw.Close(); - fs1.Close(); - } - else + // 递归创建目录 + string dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) { - FileStream fs = new(path, FileMode.Append, FileAccess.Write); - StreamWriter sr = new(fs); - sr.WriteLine(note); - sr.Close(); - fs.Close(); + Directory.CreateDirectory(dir); } + + File.AppendAllText(path, note + Environment.NewLine); } catch (Exception e) { @@ -325,11 +456,12 @@ public override void OnServerCommandExecuted(CommandExecutedEventArgs ev) public override void OnPlayerFlippingCoin(PlayerFlippingCoinEventArgs ev) { - if (!ev.IsAllowed) return; - if (!Config.Coin) return; + if (!ev.IsAllowed || !CoinConfig.Enable) return; + if (ev.Player.Items.Count() == 8) { - ev.Player.SendBroadcast($"\n你的背包空间不足,无法继续抽卡!", 2); + ev.Player.SendBroadcast(TranslateConfig.RewardFailedBroadcastTemplate, 2); + ev.IsAllowed = false; return; } @@ -337,159 +469,50 @@ public override void OnPlayerFlippingCoin(PlayerFlippingCoinEventArgs ev) player.RemoveItem(ItemType.Coin); - // 生成0-100的随机数 - float randomValue = UnityEngine.Random.Range(0f, 100f); + // 按权重随机选择奖励 + RewardSetting reward = CoinConfig.Rewards.PickReward(); + if (reward == null) return; - // 初始化奖励变量 - string rewardName = ""; - bool success = false; - - // 概率判断(从低到高) - if (randomValue < 0.3f) // 0.3% 变成SCP - { - int scpType = UnityEngine.Random.Range(0, 4); - switch (scpType) - { - case 0: - player.Role = RoleTypeId.Scp939; - rewardName = "变成了狗子"; - break; - case 1: - player.Role = RoleTypeId.Scp3114; - rewardName = "变成了3114"; - break; - case 2: - player.Role = RoleTypeId.Scp106; - rewardName = "变成了老头"; - break; - case 3: - player.Role = RoleTypeId.Scp049; - rewardName = "变成了49"; - break; - default: - player.Role = RoleTypeId.Scp939; - rewardName = "变成了狗子"; - break; - } - success = true; - } - else if (randomValue < 1f && !success) // 0.7% 特殊武器 - { - player.AddItem(ItemType.GunSCP127); - rewardName = "获得了127"; - success = true; - } - else if (randomValue < 5f && !success) // 4% 黑卡 - { - player.AddItem(ItemType.KeycardMTFCaptain); - rewardName = "获得了指挥官卡"; - success = true; - } - else if (randomValue < 10f && !success) // 5% 可乐 - { - player.AddItem(ItemType.SCP207); - rewardName = "获得了可乐"; - success = true; - } - else if (randomValue < 25f && !success) // 10% 枪 - { - bool weaponIndex = UnityEngine.Random.Range(0, 2) == 0; - if (weaponIndex) - { - player.AddItem(ItemType.GunE11SR); - rewardName = "获得了狗官枪"; - } - else - { - player.AddItem(ItemType.GunAK); - rewardName = "获得了大机枪"; - } - success = true; - } - else if (randomValue < 35f && !success) // 10% 红卡 - { - player.AddItem(ItemType.KeycardMTFOperative); - rewardName = "获得了中士卡"; - success = true; - } - else if (randomValue < 45f && !success) // 10% 再来一次 - { - player.AddItem(ItemType.Coin); - rewardName = "又获得了一个硬币"; - success = true; - } - else if (randomValue < 55f && !success) // 10% 随机传送 - { - foreach (Player p in Player.ReadyList) - { - if (p.IsSCP && p.Role != RoleTypeId.Scp079) - { - player.Position = p.Position + Vector3.right; - player.Rotation = p.Rotation; - } - } - rewardName = "被传送到SCP旁边"; - success = true; - } - else if (randomValue < 75f && !success) // 20% 医疗 - { - bool healthIndex = UnityEngine.Random.Range(0, 2) == 0; - - if (healthIndex) - { - player.AddItem(ItemType.SCP500); - } - else - { - player.AddItem(ItemType.Medkit); - } - rewardName = "获得了医疗物品"; - success = true; - } - else // 25% 什么都没有 - { - rewardName = "损失了一个硬币"; - success = true; - } + // 执行奖励 + string result = player.ApplyReward(reward); // 通知玩家 - Server.SendBroadcast($"\n🎉 恭喜!玩家 {player.Nickname} 通过抛硬币{rewardName}!", 3); - + Server.SendBroadcast(TranslateConfig.RewardOkBroadcastTemplate.Replace("{nickName}", player.Nickname).Replace("{result}", result), 3); } public override void OnScp914Activating(Scp914ActivatingEventArgs ev) { - if (HUDInfoConfig.info_914 == false) return; + if (HUDInfoConfig.EnableScp914Info == false) return; Scp914.Scp914KnobSetting knob = ev.KnobSetting; - string mode = TranslateConfig.scp914_trans[knob]; + string mode = TranslateConfig.Scp914ModeTranslations[knob]; var p_operator = ev.Player.Nickname ?? "未知"; - string msg = TranslateConfig.scp914_template.Replace("{mode}", mode) + string msg = TranslateConfig.Scp914Template.Replace("{mode}", mode) .Replace("{p_operator}", p_operator); foreach (var p in Player.List) { if (p.IsAlive && p != null && p.Room.Name == RoomName.Lcz914)// 检测914附近玩家,然后告诉他们914正在运行 { - _huds[p].Show914(msg); + PlayerHuds[p].Show914(msg); } } } public override void OnPlayerInteractingElevator(PlayerInteractingElevatorEventArgs ev) { - if (HUDInfoConfig.info_elevator == false) return; + if (HUDInfoConfig.EnableElevatorInfo == false) return; IEnumerable near = Player.List.Where(p => - Vector3.Distance(p.Position, ev.Player.Position) <= HUDInfoConfig.elev_range); + Vector3.Distance(p.Position, ev.Player.Position) <= HUDInfoConfig.ElevatorHintRange); var p_operator = ev.Player.Nickname ?? "未知"; - string text = TranslateConfig.elev_template.Replace("{p_operator}", p_operator); + string text = TranslateConfig.ElevatorTemplate.Replace("{p_operator}", p_operator); foreach (var p in near) { - _huds[p].ShowElevator(text); + PlayerHuds[p].ShowElevator(text); } } } diff --git a/Extensions/BadgeExtensions.cs b/Extensions/BadgeExtensions.cs new file mode 100644 index 0000000..e855441 --- /dev/null +++ b/Extensions/BadgeExtensions.cs @@ -0,0 +1,120 @@ +using EasyTools.DataStructures; +using EasyTools.Events; +using LabApi.Features.Wrappers; +using MEC; +using System; +using System.Collections.Generic; +using Log = LabApi.Features.Console.Logger; + +namespace EasyTools.Extensions +{ + public static class BadgeExtensions + { + public static string[] FMoreColo = + [ + "pink", + "silver", + "cyan", + "aqua", + "tomato", + "yellow", + "magenta", + "orange", + "lime", + "green", + "red", + "brown", + "red", + "orange", + "yellow", + "green", + "blue_green", + "magenta", + "pink", + "brown", + "silver", + "light_green", + "crimson", + "cyan", + "aqua", + "deep_pink", + "tomato", + "blue_green", + "lime", + "emerald", + "carmine", + "nickel", + "mint", + "army_green", + "pumpkin" + ]; + + public static List rainbw = new List(); + + public static IEnumerator Rainbw() + { + while (true) + { + foreach (var item in rainbw) + { + item.GroupColor = FMoreColo.RandomItem(); + } + yield return Timing.WaitForSeconds(CustomEventHandler.BadgeConfig.Each); + } + } + + public static void ApplyBadge(this Player player) + { + PlayerData data = player.GetData(); + + if (data.Badge != "") + { + player.GroupName = data.Badge; + + if (data.BadgeColor != "") + { + switch (data.BadgeColor) + { + case "rainbow": + rainbw.Add(player); + break; + default: + player.GroupColor = data.BadgeColor; + break; + } + } + } + } + + public static void ApplyPermission(this Player player) + { + PlayerData data = player.GetData(); + if (data.PermissionLevel != PermissionLevel.Player) + { + string group; + switch (data.PermissionLevel) + { + case PermissionLevel.Moderator: + group = "moderator"; + break; + case PermissionLevel.Admin: + group = "admin"; + break; + case PermissionLevel.Owner: + group = "owner"; + break; + default: + group = "moderator"; + break; + }; + + Server.RunCommand($"/setgroup {player.PlayerId} {group}"); + + if (CustomEventHandler.Config.EnableAdminLogger) + { + Log.Info($"[AC] Date: {DateTime.Now} | Player: {player.Nickname} | Perm: {group} | Steam64ID: {player.UserId}"); + } + } + } + } +} diff --git a/Utils/ChatUtils.cs b/Extensions/ChatHintExtensions.cs similarity index 94% rename from Utils/ChatUtils.cs rename to Extensions/ChatHintExtensions.cs index 382c408..de964cf 100644 --- a/Utils/ChatUtils.cs +++ b/Extensions/ChatHintExtensions.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Linq; -namespace EasyTools.Utils +namespace EasyTools.Extensions { public class ChatMessage(Player sender, ChatMessage.MessageType type, string message) @@ -39,7 +39,7 @@ public enum MessageType public RoleTypeId SenderRole { get; } = sender.Role; } - public class ChatUtils + public static class ChatHintExtensions { private static CoroutineHandle _coroutine; @@ -117,7 +117,7 @@ private static IEnumerator MessageCoroutineMethod() } } - public static void InitForPlayer(Player player) + public static void InitChatHint(this Player player) { if (!_coroutine.IsRunning) _coroutine = Timing.RunCoroutine(MessageCoroutineMethod()); @@ -138,7 +138,7 @@ public static void InitForPlayer(Player player) PlayerDisplay.Get(player.ReferenceHub).AddHint(MessageSlot[player]); } - public static void SendMessage(Player sender, ChatMessage.MessageType type, string message) => SendMessage(new ChatMessage(sender, type, message)); + public static void SendHintMessage(this Player sender, ChatMessage.MessageType type, string message) => SendMessage(new ChatMessage(sender, type, message)); public static void SendMessage(ChatMessage message) { diff --git a/DataBase/InfoExtension.cs b/Extensions/DataExtensions.cs similarity index 92% rename from DataBase/InfoExtension.cs rename to Extensions/DataExtensions.cs index 8c01266..427ba4d 100644 --- a/DataBase/InfoExtension.cs +++ b/Extensions/DataExtensions.cs @@ -1,4 +1,5 @@ -using EasyTools.DataBase.Serialization; +using EasyTools.API; +using EasyTools.DataStructures; using EasyTools.Events; using LabApi.Features.Wrappers; using LiteDB; @@ -6,9 +7,9 @@ using System; using System.Collections.Generic; -namespace EasyTools.DataBase +namespace EasyTools.Extensions { - public static class InfoExtension + public static class DataExtensions { /// @@ -35,8 +36,10 @@ public static PlayerData GetData(this Player ply) PlayerDamage = 0, RolePlayed = 0, PlayerShot = 0, + PlayerXp = 0.0, + PlayerLevel = 0.0 }; - using LiteDatabase database = new(CustomEventHandler.DataBaseConfig.database_path); + using LiteDatabase database = new(CustomEventHandler.Config.DataBasePath); database.GetCollection("Players").Insert(toInsert); } @@ -66,7 +69,7 @@ public static PlayerData GetData(this ReferenceHub ply) RolePlayed = 0, PlayerShot = 0, }; - using LiteDatabase database = new(CustomEventHandler.DataBaseConfig.database_path); + using LiteDatabase database = new(CustomEventHandler.Config.DataBasePath); database.GetCollection("Players").Insert(toInsert); } @@ -77,7 +80,7 @@ public static PlayerData GetData(this ReferenceHub ply) public static void UpdateData(this PlayerData data) { - using LiteDatabase database = new(CustomEventHandler.DataBaseConfig.database_path); + using LiteDatabase database = new(CustomEventHandler.Config.DataBasePath); database.GetCollection("Players").Update(data); } diff --git a/Extensions/LevelExtensions.cs b/Extensions/LevelExtensions.cs new file mode 100644 index 0000000..eb5e274 --- /dev/null +++ b/Extensions/LevelExtensions.cs @@ -0,0 +1,50 @@ +using LabApi.Features.Wrappers; +using System; + +namespace EasyTools.Extensions +{ + public static class LevelExtensions + { + /// + /// 根据经验值计算当前等级 + /// + public static int GetLevelFromXp(double xp, double a) + { + if (xp < 0) xp = 0; + double level = -50.0 + Math.Sqrt((4.0 * xp / a) + 9800.0) / 2.0; + return (int)Math.Ceiling(level); + } + + /// + /// 从0级升到指定等级所需的总经验 + /// + public static double GetTotalXpForLevel(int level, double a) + { + if (level < 0) level = 0; + return Math.Ceiling((level * level + 100.0 * level + 50.0) * a); + } + + /// + /// 当前经验值下,升级到下一级还需要的经验 + /// + public static double GetXpUntilNextLevel(double currentXp, double a) + { + int currentLevel = GetLevelFromXp(currentXp, a); + if (currentLevel < 0) currentLevel = 0; + double nextLevelTotal = GetTotalXpForLevel(currentLevel + 1, a); + return Math.Max(0, nextLevelTotal - currentXp); + } + + // 玩家名称更新方法 + public static void UpdatePlayerNameWithLevelPrefix(this Player player) + { + if (player == null || player.IsNpc) return; + + string originalName = player.Nickname; + + // 设置新名称(前缀+原始名称) + string newName = $"[Level.{player.GetData().PlayerLevel}]{originalName}"; + player.DisplayName = newName; + } + } +} diff --git a/Extensions/RewardExtensions.cs b/Extensions/RewardExtensions.cs new file mode 100644 index 0000000..7280967 --- /dev/null +++ b/Extensions/RewardExtensions.cs @@ -0,0 +1,84 @@ +using EasyTools.Configs; +using LabApi.Features.Wrappers; +using PlayerRoles; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace EasyTools.Extensions +{ + public static class RewardExtensions + { + public static RewardSetting PickReward(this List rewards) + { + float totalWeight = rewards.Sum(r => r.Weight); + float roll = UnityEngine.Random.Range(0f, totalWeight); + float cumulative = 0f; + foreach (var reward in rewards) + { + cumulative += reward.Weight; + if (roll < cumulative) + return reward; + } + return rewards.LastOrDefault(); + } + + public static string ApplyReward(this Player player, RewardSetting reward) + { + switch (reward.Type) + { + case RewardType.ChangeRole: + if (Enum.TryParse(reward.Param, out RoleTypeId role)) + { + player.Role = role; + return $"变成了 {reward.Name}"; + } + return "变身失败(配置错误)"; + + case RewardType.GiveItem: + if (Enum.TryParse(reward.Param, out ItemType item)) + { + player.AddItem(item); + return $"获得了 {reward.Name}"; + } + return "获得物品失败(配置错误)"; + + case RewardType.GiveRandomGun: + string[] guns = reward.Param.Split(','); + string chosen = guns[UnityEngine.Random.Range(0, guns.Length)]; + if (Enum.TryParse(chosen.Trim(), out ItemType gun)) + { + player.AddItem(gun); + return $"获得了 {chosen}"; + } + return "获得武器失败(配置错误)"; + + case RewardType.TeleportToSCP: + var scps = Player.ReadyList.Where(p => p.IsSCP && p.Role != RoleTypeId.Scp079).ToList(); + if (scps.Any()) + { + var target = scps[UnityEngine.Random.Range(0, scps.Count)]; + player.Position = target.Position + Vector3.right; + player.Rotation = target.Rotation; + return "被传送到SCP旁边"; + } + // 没有SCP时返还硬币(防止纯损失) + player.AddItem(ItemType.Coin); + return "...SCP都不在了,返还硬币"; + + case RewardType.ExtraCoin: + player.AddItem(ItemType.Coin); + return "又获得了一个硬币"; + + case RewardType.GiveMedical: + bool give500 = UnityEngine.Random.Range(0, 2) == 0; + player.AddItem(give500 ? ItemType.SCP500 : ItemType.Medkit); + return "获得了医疗物品"; + + default: + return "损失了一个硬币"; + } + } + } +} diff --git a/Utils/ScpReal.cs b/Helper/ScpAutoHealHelper.cs similarity index 97% rename from Utils/ScpReal.cs rename to Helper/ScpAutoHealHelper.cs index 0bf955a..6f524d8 100644 --- a/Utils/ScpReal.cs +++ b/Helper/ScpAutoHealHelper.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using UnityEngine; -namespace EasyTools.Utils +namespace EasyTools.Helper { - public class ScpReal + public class ScpAutoHealHelper { private static readonly Dictionary _lastMove = []; diff --git a/Utils/Util.cs b/Helper/ServerBroadcastHelper.cs similarity index 79% rename from Utils/Util.cs rename to Helper/ServerBroadcastHelper.cs index ffd34e7..64ffd64 100644 --- a/Utils/Util.cs +++ b/Helper/ServerBroadcastHelper.cs @@ -1,12 +1,11 @@ using EasyTools.Events; using LabApi.Features.Wrappers; using MEC; -using System; using System.Collections.Generic; -namespace EasyTools.Utils +namespace EasyTools.Helper { - public class Util + public static class ServerBroadcastHelper { public static IEnumerator AutoServerBroadcast() { @@ -18,7 +17,7 @@ public static IEnumerator AutoServerBroadcast() } //随机公告 - int tmp = new Random().Next(0, CustomEventHandler.Config.AutoServerMessageText.Count - 1); + int tmp = UnityEngine.Random.Range(0, CustomEventHandler.Config.AutoServerMessageText.Count); Server.SendBroadcast(CustomEventHandler.Config.AutoServerMessageText[tmp], CustomEventHandler.Config.AutoServerMessageTimer, global::Broadcast.BroadcastFlags.Normal); yield return Timing.WaitForSeconds(CustomEventHandler.Config.AutoServerMessageTime * 60f); diff --git a/Plugins.cs b/Plugins.cs index 72556f6..bf27e00 100644 --- a/Plugins.cs +++ b/Plugins.cs @@ -1,11 +1,10 @@ using EasyTools.Configs; -using EasyTools.DataBase.Serialization; +using EasyTools.DataStructures; using EasyTools.Events; using LabApi.Events.CustomHandlers; using LabApi.Features; using LabApi.Loader; using LabApi.Loader.Features.Plugins; -using System.IO; namespace EasyTools { @@ -19,28 +18,23 @@ public override void LoadConfigs() CustomEventHandler.Config = this.LoadConfig("config.yml"); CustomEventHandler.TranslateConfig = this.LoadConfig("translateConfig.yml"); CustomEventHandler.BadgeConfig = this.LoadConfig("badgeConfig.yml"); - CustomEventHandler.CustomRoleConfig = this.LoadConfig("customRoleConfig.yml"); - CustomEventHandler.DataBaseConfig = this.LoadConfig("dataBaseConfig.yml"); + CustomEventHandler.LevelSystemConfig = this.LoadConfig("dataBaseConfig.yml"); CustomEventHandler.HUDInfoConfig = this.LoadConfig("HUDInfoConfig.yml"); + CustomEventHandler.CoinConfig = this.LoadConfig("coinConfig.yml"); - CustomEventHandler.data_914 = new HintData + CustomEventHandler.Scp914HintData = new HintData ( - CustomEventHandler.HUDInfoConfig._914_x, - CustomEventHandler.HUDInfoConfig._914_y, - CustomEventHandler.HUDInfoConfig._914_font + CustomEventHandler.HUDInfoConfig.Scp914DisplayX, + CustomEventHandler.HUDInfoConfig.Scp914DisplayY, + CustomEventHandler.HUDInfoConfig.Scp914FontSize ); - CustomEventHandler.data_elevator = new HintData + CustomEventHandler.ElevatorHintData = new HintData ( - CustomEventHandler.HUDInfoConfig._elev_x, - CustomEventHandler.HUDInfoConfig._elev_y, - CustomEventHandler.HUDInfoConfig._elev_font + CustomEventHandler.HUDInfoConfig.ElevatorDisplayX, + CustomEventHandler.HUDInfoConfig.ElevatorDisplayY, + CustomEventHandler.HUDInfoConfig.ElevatorFontSize ); - - if (!Directory.Exists(CustomEventHandler.BadgeConfig.Pach)) - { - Directory.CreateDirectory(CustomEventHandler.BadgeConfig.Pach); - } } @@ -54,7 +48,7 @@ public override void LoadConfigs() public override string Author => "3cxc"; - public override System.Version Version => new(1, 0, 1); + public override System.Version Version => new(1, 1, 0); public override System.Version RequiredApiVersion => new(LabApiProperties.CompiledVersion); @@ -71,8 +65,8 @@ public override void Disable() Instance = null; - foreach (var hud in CustomEventHandler._huds.Values) hud.Dispose(); - CustomEventHandler._huds.Clear(); + foreach (var hud in CustomEventHandler.PlayerHuds.Values) hud.Dispose(); + CustomEventHandler.PlayerHuds.Clear(); } } diff --git a/Utils/Ini.cs b/Utils/Ini.cs deleted file mode 100644 index 4a0d3a3..0000000 --- a/Utils/Ini.cs +++ /dev/null @@ -1,298 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace NewXp.IniApi -{ - /// - /// Represents a property in an INI file. - /// - public class IniProperty - { - /// - /// Property name (key). - /// - public string Name { get; set; } - - /// - /// Property value. - /// - public string Value { get; set; } - - /// - /// Set the comment to display above this property. - /// - public string Comment { get; set; } - } - - /// - /// Represents a section in an INI file. - /// - public class IniSection - { - private readonly IDictionary _properties; - - /// - /// Section name. - /// - public string Name { get; set; } - - /// - /// Set the comment to display above this section. - /// - public string Comment { get; set; } - - /// - /// Get the properties in this section. - /// - public IniProperty[] Properties => _properties.Values.ToArray(); - - /// - /// Create a new IniSection. - /// - /// - public IniSection(string name) - { - Name = name; - _properties = new Dictionary(); - } - - /// - /// Get a property value. - /// - /// Name of the property. - /// Value of the property or null if it doesn't exist. - public string Get(string name) - { - if (_properties.ContainsKey(name)) - return _properties[name].Value; - - return null; - } - - /// - /// Get a property value, coercing the type of the value - /// into the type given by the generic parameter. - /// - /// Name of the property. - /// The type to coerce the value into. - /// - public T Get(string name) - { - if (_properties.ContainsKey(name)) - return (T)Convert.ChangeType(_properties[name].Value, typeof(T)); - - return default(T); - } - - /// - /// Set a property value. - /// - /// Name of the property. - /// Value of the property. - /// A comment to display above the property. - public void Set(string name, string value, string comment = null) - { - if (string.IsNullOrWhiteSpace(value)) - { - RemoveProperty(name); - return; - } - - if (!_properties.ContainsKey(name)) - _properties.Add(name, new IniProperty { Name = name, Value = value, Comment = comment }); - else - { - _properties[name].Value = value; - if (comment != null) - _properties[name].Comment = comment; - } - } - - /// - /// Remove a property from this section. - /// - /// The property name to remove. - public void RemoveProperty(string propertyName) - { - if (_properties.ContainsKey(propertyName)) - _properties.Remove(propertyName); - } - } - - /// - /// Represenst an INI file that can be read from or written to. - /// - public class IniFile - { - private readonly IDictionary _sections; - - /// - /// If True, writes extra spacing between the property name and the property value. - /// (foo=bar) vs (foo = bar) - /// - public bool WriteSpacingBetweenNameAndValue { get; set; } - - /// - /// The character a comment line will begin with. Default '#'. - /// - public char CommentChar { get; set; } - - /// - /// Get the sections in this IniFile. - /// - public IniSection[] Sections => _sections.Values.ToArray(); - - /// - /// Create a new IniFile instance. - /// - public IniFile() - { - _sections = new Dictionary(); - CommentChar = '#'; - } - - /// - /// Load an INI file from the file system. - /// - /// Path to the INI file. - public IniFile(string path) : this() - { - Load(path); - } - - /// - /// Load an INI file. - /// - /// A TextReader instance. - public IniFile(TextReader reader) : this() - { - Load(reader); - } - - private void Load(string path) - { - using (var file = new StreamReader(path)) - Load(file); - } - - private void Load(TextReader reader) - { - IniSection section = null; - - string line; - while ((line = reader.ReadLine()) != null) - { - line = line.Trim(); - - // skip empty lines - if (line == string.Empty) - continue; - - // skip comments - if (line.StartsWith(";") || line.StartsWith("#")) - continue; - - if (line.StartsWith("[") && line.EndsWith("]")) - { - var sectionName = line.Substring(1, line.Length - 2); - if (!_sections.ContainsKey(sectionName)) - { - section = new IniSection(sectionName); - _sections.Add(sectionName, section); - } - continue; - } - - if (section != null) - { - var keyValue = line.Split(new[] { "=" }, 2, StringSplitOptions.RemoveEmptyEntries); - if (keyValue.Length != 2) - continue; - - section.Set(keyValue[0].Trim(), keyValue[1].Trim()); - } - } - } - - /// - /// Get a section by name. If the section doesn't exist, it is created. - /// - /// The name of the section. - /// A section. If the section doesn't exist, it is created. - public IniSection Section(string sectionName) - { - IniSection section; - if (!_sections.TryGetValue(sectionName, out section)) - { - section = new IniSection(sectionName); - _sections.Add(sectionName, section); - } - - return section; - } - - /// - /// Remove a section. - /// - /// Name of the section to remove. - public void RemoveSection(string sectionName) - { - if (_sections.ContainsKey(sectionName)) - _sections.Remove(sectionName); - } - - /// - /// Create a new INI file. - /// - /// Path to the INI file to create. - public void Save(string path) - { - using (var file = new StreamWriter(path)) - Save(file); - } - - /// - /// Create a new INI file. - /// - /// A TextWriter instance. - public void Save(TextWriter writer) - { - foreach (var section in _sections.Values) - { - if (section.Properties.Length == 0) - continue; - - if (section.Comment != null) - writer.WriteLine($"{CommentChar} {section.Comment}"); - - writer.WriteLine($"[{section.Name}]"); - - foreach (var property in section.Properties) - { - if (property.Comment != null) - writer.WriteLine($"{CommentChar} {property.Comment}"); - - var format = WriteSpacingBetweenNameAndValue ? "{0} = {1}" : "{0}={1}"; - writer.WriteLine(format, property.Name, property.Value); - } - - writer.WriteLine(); - } - } - - /// - /// Returns the content of this INI file as a string. - /// - /// The text content of this INI file. - public override string ToString() - { - using (var sw = new StringWriter()) - { - Save(sw); - return sw.ToString(); - } - } - } -}