From aa3b923a6ff9bfccb626becb85a423a546b1beae Mon Sep 17 00:00:00 2001 From: milimoe Date: Thu, 24 Jul 2025 01:27:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=AC=E5=91=8A=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OshimaServers/AnonymousServer.cs | 344 ++---------------- OshimaServers/Model/NoticeModel.cs | 22 ++ OshimaServers/Service/FunGameService.cs | 212 ++++++++++- OshimaServers/Service/WebSocketService.cs | 196 ++++++++++ OshimaWebAPI/Controllers/FunGameController.cs | 4 +- OshimaWebAPI/Services/RainBOTService.cs | 80 +++- 6 files changed, 521 insertions(+), 337 deletions(-) create mode 100644 OshimaServers/Model/NoticeModel.cs create mode 100644 OshimaServers/Service/WebSocketService.cs diff --git a/OshimaServers/AnonymousServer.cs b/OshimaServers/AnonymousServer.cs index d1c29a9..b9b6535 100644 --- a/OshimaServers/AnonymousServer.cs +++ b/OshimaServers/AnonymousServer.cs @@ -1,13 +1,9 @@ -using System.Data; -using Milimoe.FunGame.Core.Api.Transmittal; -using Milimoe.FunGame.Core.Api.Utility; -using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Api.Utility; using Milimoe.FunGame.Core.Interface.Base; using Milimoe.FunGame.Core.Library.Common.Addon; using Milimoe.FunGame.Core.Library.Constant; using Oshima.Core.Configs; using Oshima.Core.Constant; -using Oshima.FunGame.OshimaServers.Model; using Oshima.FunGame.OshimaServers.Service; using TaskScheduler = Milimoe.FunGame.Core.Api.Utility.TaskScheduler; @@ -31,6 +27,13 @@ namespace Oshima.FunGame.OshimaServers public static HashSet Instances { get; } = []; + public WebSocketService Service { get; } + + public AnonymousServer() + { + Service = new(this); + } + /// /// 向客户端推送事件 /// @@ -107,12 +110,14 @@ namespace Oshima.FunGame.OshimaServers Controller.NewMailSender(); FunGameService.InitFunGame(); FunGameSimulation.InitFunGameSimulation(); + FunGameService.RefreshNotice(); TaskScheduler.Shared.AddTask("重置每日运势", new TimeSpan(0, 0, 0), () => { Controller.WriteLine("已重置所有人的今日运势"); Daily.ClearDaily(); // 刷新活动缓存 FunGameService.GetEventCenter(); + FunGameService.RefreshNotice(); }); TaskScheduler.Shared.AddTask("上九", new TimeSpan(9, 0, 0), () => { @@ -128,153 +133,30 @@ namespace Oshima.FunGame.OshimaServers }); TaskScheduler.Shared.AddRecurringTask("刷新存档缓存", TimeSpan.FromMinutes(1), () => { - string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; - if (Directory.Exists(directoryPath)) - { - string[] filePaths = Directory.GetFiles(directoryPath); - foreach (string filePath in filePaths) - { - string fileName = Path.GetFileNameWithoutExtension(filePath); - PluginConfig pc = FunGameService.GetUserConfig(fileName, out _); - if (pc.Count > 0) - { - User user = FunGameService.GetUser(pc); - // 将用户存入缓存 - FunGameConstant.UserIdAndUsername[user.Id] = user; - bool updateQuest = false; - bool updateExplore = false; - // 任务结算 - EntityModuleConfig quests = new("quests", user.Id.ToString()); - quests.LoadConfig(); - if (quests.Count > 0 && FunGameService.SettleQuest(user, quests)) - { - quests.SaveConfig(); - updateQuest = true; - } - // 探索结算 - PluginConfig pc2 = new("exploring", user.Id.ToString()); - pc2.LoadConfig(); - if (pc2.Count > 0 && FunGameService.SettleExploreAll(pc2, user)) - { - pc2.SaveConfig(); - updateExplore = true; - } - if (updateQuest || updateExplore) - { - FunGameService.SetUserConfigAndReleaseSemaphoreSlim(user.Id, pc, user); - } - if (FunGameConstant.UserLastVisitStore.TryGetValue(user.Id, out LastStoreModel? value) && value != null && (DateTime.Now - value.LastTime).TotalMinutes > 2) - { - FunGameConstant.UserLastVisitStore.Remove(user.Id); - } - } - FunGameService.ReleaseUserSemaphoreSlim(fileName); - } - Controller.WriteLine("读取 FunGame 存档缓存", LogLevel.Debug); - } + FunGameService.RefreshSavedCache(); + Controller.WriteLine("读取 FunGame 存档缓存", LogLevel.Debug); }, true); TaskScheduler.Shared.AddTask("刷新每日任务", new TimeSpan(4, 0, 0), () => { // 刷新每日任务 Task.Run(() => { - string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/quests"; - if (Directory.Exists(directoryPath)) - { - string[] filePaths = Directory.GetFiles(directoryPath); - foreach (string filePath in filePaths) - { - string fileName = Path.GetFileNameWithoutExtension(filePath); - EntityModuleConfig quests = new("quests", fileName); - quests.Clear(); - FunGameService.CheckQuestList(quests); - quests.SaveConfig(); - } - Controller.WriteLine("刷新每日任务"); - } + FunGameService.RefreshDailyQuest(); + Controller.WriteLine("刷新每日任务"); }); Task.Run(() => { - // 刷新每天登录 - FunGameService.UserNotice.Clear(); - // 刷新签到 - string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; - if (Directory.Exists(directoryPath)) - { - string[] filePaths = Directory.GetFiles(directoryPath); - foreach (string filePath in filePaths) - { - string fileName = Path.GetFileNameWithoutExtension(filePath); - PluginConfig pc = FunGameService.GetUserConfig(fileName, out _); - pc.Add("signed", false); - pc.Add("logon", false); - pc.Add("exploreTimes", FunGameConstant.MaxExploreTimes); - pc.SaveConfig(); - FunGameService.ReleaseUserSemaphoreSlim(fileName); - } - Controller.WriteLine("刷新签到"); - } + FunGameService.RefreshDailySignIn(); + Controller.WriteLine("刷新签到"); }); Task.Run(() => { - // 刷新商店 - string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/storeNames"; - if (Directory.Exists(directoryPath)) - { - string[] filePaths = Directory.GetFiles(directoryPath); - foreach (string filePath in filePaths) - { - string fileName = Path.GetFileNameWithoutExtension(filePath); - EntityModuleConfig stores = new("storeNames", fileName); - stores.LoadConfig(); - string[] storeNames = [.. stores.Keys]; - if (long.TryParse(fileName, out long userId) && FunGameConstant.UserIdAndUsername.TryGetValue(userId, out User? user) && user != null) - { - // 更新玩家商店数据,移除所有当天刷新的商店 - FunGameConstant.UserLastVisitStore.Remove(userId); - stores.Remove("daily"); - foreach (string key in storeNames) - { - Store? store = stores.Get(key); - if (store != null && (store.GlobalStock || (store.AutoRefresh && store.NextRefreshDate.Date <= DateTime.Today))) - { - stores.Remove(key); - } - } - FunGameService.CheckDailyStore(stores, user); - } - else - { - // 非玩家商店数据,需要更新模板的商品 - foreach (string key in storeNames) - { - Store? store = stores.Get(key); - if (store != null) - { - if (store.ExpireTime != null && store.ExpireTime.Value.Date <= DateTime.Today) - { - stores.Remove(key); - continue; - } - if (store.AutoRefresh && store.NextRefreshDate.Date <= DateTime.Today) - { - store.Goods.Clear(); - foreach (long goodsId in store.NextRefreshGoods.Keys) - { - store.Goods[goodsId] = store.NextRefreshGoods[goodsId]; - } - store.NextRefreshDate = DateTime.Today.AddHours(4).AddDays(store.RefreshInterval); - } - } - } - } - stores.SaveConfig(); - } - Controller.WriteLine("刷新商店"); - } + FunGameService.RefreshStoreData(); + Controller.WriteLine("刷新商店"); }); // 刷新活动缓存 FunGameService.GetEventCenter(); + FunGameService.RefreshNotice(); }); TaskScheduler.Shared.AddRecurringTask("刷新boss", TimeSpan.FromHours(1), () => { @@ -326,13 +208,13 @@ namespace Oshima.FunGame.OshimaServers switch (command.Trim().ToLower()) { case "scadd": - msg = SCAdd(data); + msg = Service.SCAdd(data); break; case "sclist": - msg = SCList(data); + msg = Service.SCList(data); break; case "screcord": - msg = SCRecord(data); + msg = Service.SCRecord(data); break; case "att": break; @@ -350,188 +232,6 @@ namespace Oshima.FunGame.OshimaServers return result; } - public string SCAdd(Dictionary data) - { - string result = ""; - - using SQLHelper? sql = Controller.GetSQLHelper(); - if (sql != null) - { - try - { - long qq = Controller.JSON.GetObject(data, "qq"); - long groupid = Controller.JSON.GetObject(data, "groupid"); - double sc = Controller.JSON.GetObject(data, "sc"); - sql.NewTransaction(); - sql.Script = "select * from saints where qq = @qq and `group` = @group"; - sql.Parameters.Add("qq", qq); - sql.Parameters.Add("group", groupid); - sql.ExecuteDataSet(); - string content = Controller.JSON.GetObject(data, "content") ?? ""; - string record = ""; - if (sql.Success) - { - record = Convert.ToString(sql.DataSet.Tables[0].Rows[0]["record"]) ?? ""; - } - record = $"{DateTime.Now:MM/dd HH:mm}:{content}({(sc < 0 ? "-" : "+") + Math.Abs(sc)})\r\n{record}"; - record = string.Join("\r\n", record.Split("\r\n", StringSplitOptions.RemoveEmptyEntries).Take(10)); - if (sql.Success) - { - sql.Script = "update saints set sc = sc + @sc, record = @record where qq = @qq and `group` = @group"; - } - else - { - sql.Script = "insert into saints(qq, sc, `group`, record) values(@qq, @sc, @group, @record)"; - } - sql.Parameters.Add("sc", sc); - sql.Parameters.Add("qq", qq); - sql.Parameters.Add("group", groupid); - sql.Parameters.Add("record", record); - sql.Execute(); - if (sql.Success) - { - Controller.WriteLine($"用户 {qq} 的圣人点数增加了 {sc}", LogLevel.Debug); - sql.Commit(); - } - else - { - sql.Rollback(); - } - } - catch (Exception e) - { - result = e.ToString(); - sql.Rollback(); - } - } - else result = "无法调用此接口:SQL 服务不可用。"; - - return result; - } - - public string SCList(Dictionary data) - { - string result; - - SQLHelper? sql = Controller.SQLHelper; - if (sql != null) - { - long userQQ = Controller.JSON.GetObject(data, "qq"); - (bool userHas, double userSC, int userTop, string userRemark) = (false, 0, 0, ""); - long groupid = Controller.JSON.GetObject(data, "groupid"); - bool reverse = Controller.JSON.GetObject(data, "reverse"); - if (!reverse) - { - result = $"☆--- OSMTV 圣人排行榜 TOP10 ---☆\r\n统计时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}\r\n"; - } - else - { - result = $"☆--- OSMTV 出生排行榜 TOP10 ---☆\r\n统计时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}\r\n"; - } - sql.Script = "select * from saints where `group` = @group order by sc" + (!reverse ? " desc" : ""); - sql.Parameters.Add("group", groupid); - sql.ExecuteDataSet(); - if (sql.Success && sql.DataSet.Tables.Count > 0) - { - int count = 0; - foreach (DataRow dr in sql.DataSet.Tables[0].Rows) - { - count++; - long qq = Convert.ToInt64(dr["qq"]); - double sc = Convert.ToDouble(dr["sc"]); - string remark = Convert.ToString(dr["remark"]) ?? ""; - if (reverse) - { - sc = -sc; - remark = remark.Replace("+", "-"); - } - if (qq == userQQ) - { - userHas = true; - userSC = sc; - userTop = count; - userRemark = remark; - } - if (count > 10) continue; - if (!reverse) - { - result += $"{count}. 用户:{qq},圣人点数:{sc} 分{(remark.Trim() != "" ? $" ({remark})" : "")}\r\n"; - } - else - { - result += $"{count}. 用户:{qq},出生点数:{sc} 分{(remark.Trim() != "" ? $" ({remark})" : "")}\r\n"; - } - } - if (!reverse && userHas) - { - result += $"你的圣人点数为:{userSC} 分{(userRemark.Trim() != "" ? $"({userRemark})" : "")},排在第 {userTop} / {sql.DataSet.Tables[0].Rows.Count} 名。\r\n" + - $"本排行榜仅供娱乐,不代表任何官方立场或真实情况。"; - } - if (reverse && userHas) - { - result += $"你的出生点数为:{userSC} 分{(userRemark.Trim() != "" ? $"({userRemark})" : "")},排在出生榜第 {userTop} / {sql.DataSet.Tables[0].Rows.Count} 名。\r\n" + - $"本排行榜仅供娱乐,不代表任何官方立场或真实情况。"; - } - } - else - { - if (reverse) - { - result = "出生榜目前没有任何数据。"; - } - else - { - result = "圣人榜目前没有任何数据。"; - } - } - } - else result = "无法调用此接口:SQL 服务不可用。"; - - return result.Trim(); - } - - public string SCRecord(Dictionary data) - { - string result = ""; - - SQLHelper? sql = Controller.SQLHelper; - if (sql != null) - { - long userQQ = Controller.JSON.GetObject(data, "qq"); - long groupid = Controller.JSON.GetObject(data, "groupid"); - result = $"☆--- 圣人点数信息 ---☆\r\n统计时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}\r\n"; - sql.Script = "select * from saints where `group` = @group order by sc desc"; - sql.Parameters.Add("group", groupid); - sql.Parameters.Add("qq", userQQ); - sql.ExecuteDataSet(); - if (sql.Success && sql.DataSet.Tables.Count > 0) - { - Dictionary dict = sql.DataSet.Tables[0].AsEnumerable().Select((r, i) => new { Index = i + 1, Row = r }).ToDictionary(c => c.Index, c => c.Row); - int index = dict.Where(kv => Convert.ToInt64(kv.Value["qq"]) == userQQ).Select(r => r.Key).FirstOrDefault(); - if (index != 0 && dict.TryGetValue(index, out DataRow? dr) && dr != null) - { - long qq = Convert.ToInt64(dr["qq"]); - double sc = Convert.ToDouble(dr["sc"]); - string remark = Convert.ToString(dr["remark"]) ?? ""; - string record = Convert.ToString(dr["record"]) ?? ""; - result += $"用户:{qq},圣人点数:{sc} 分{(remark.Trim() != "" ? $" ({remark})" : "")},排在圣人榜第 {index} / {sql.DataSet.Tables[0].Rows.Count} 名。\r\n" + - $"{(record != "" ? "显示近期点数变动信息:\r\n" + record + "\r\n" : "")}本系统仅供娱乐,不代表任何官方立场或真实情况。"; - } - else - { - result = "你在这个群没有任何历史记录。"; - } - } - else - { - result = "你在这个群没有任何历史记录。"; - } - } - else result = "无法调用此接口:SQL 服务不可用。"; - - return result.Trim(); - } - public override Task> GamingMessageHandler(IServerModel model, GamingType type, Dictionary data) { throw new NotImplementedException(); diff --git a/OshimaServers/Model/NoticeModel.cs b/OshimaServers/Model/NoticeModel.cs new file mode 100644 index 0000000..946ba58 --- /dev/null +++ b/OshimaServers/Model/NoticeModel.cs @@ -0,0 +1,22 @@ +using Milimoe.FunGame.Core.Entity; +using Milimoe.FunGame.Core.Interface.Entity; +using Milimoe.FunGame.Core.Library.Constant; + +namespace Oshima.FunGame.OshimaServers.Model +{ + public class NoticeModel : BaseEntity + { + public string Title { get; set; } = ""; + public string Content { get; set; } = ""; + public string Author { get; set; } = ""; + public DateTime StartTime { get; set; } = DateTime.MinValue; + public DateTime EndTime { get; set; } = DateTime.MaxValue; + + public override string ToString() + { + return $"系统公告【{Title}】{Author} 发布于 {StartTime.ToString(General.GeneralDateTimeFormatChinese)}\r\n{Content}"; + } + + public override bool Equals(IBaseEntity? other) => other is NoticeModel && other.GetIdName() == GetIdName(); + } +} diff --git a/OshimaServers/Service/FunGameService.cs b/OshimaServers/Service/FunGameService.cs index 4cc59ea..b84b6b4 100644 --- a/OshimaServers/Service/FunGameService.cs +++ b/OshimaServers/Service/FunGameService.cs @@ -29,6 +29,7 @@ namespace Oshima.FunGame.OshimaServers.Service public static Dictionary Bosses { get; } = []; public static ServerPluginLoader? ServerPluginLoader { get; set; } = null; public static WebAPIPluginLoader? WebAPIPluginLoader { get; set; } = null; + public static EntityModuleConfig Notices { get; } = new("notices", "notice"); public static void InitFunGame() { @@ -619,13 +620,6 @@ namespace Oshima.FunGame.OshimaServers.Service } } - if (!pc.TryGetValue("logon", out object? value) || (value is bool logon && !logon)) - { - pc.Add("logon", true); - AddNotice(user.Id, "欢迎回到筽祀牻大陆!请发送【帮助】获取更多玩法指令哦~"); - AddNotice(user.Id, GetEvents()); - } - return user; } @@ -2073,12 +2067,12 @@ namespace Oshima.FunGame.OshimaServers.Service } stores.Add("daily", daily); SetLastStore(user, true, "", ""); - return daily.ToString(); + return daily.ToString(user); } else { SetLastStore(user, true, "", ""); - return daily.ToString(); + return daily.ToString(user); } } @@ -3989,7 +3983,7 @@ namespace Oshima.FunGame.OshimaServers.Service { Store? store = value.VisitStore(stores, user, storeName); exist = store != null; - msg = store?.ToString() ?? ""; + msg = store?.ToString(user) ?? ""; } if (!exist) @@ -4004,6 +3998,203 @@ namespace Oshima.FunGame.OshimaServers.Service return msg; } + public static void RefreshNotice() + { + Notices.LoadConfig(); + } + + public static void RefreshSavedCache() + { + string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; + if (Directory.Exists(directoryPath)) + { + string[] filePaths = Directory.GetFiles(directoryPath); + foreach (string filePath in filePaths) + { + string fileName = Path.GetFileNameWithoutExtension(filePath); + PluginConfig pc = GetUserConfig(fileName, out _); + if (pc.Count > 0) + { + User user = GetUser(pc); + // 将用户存入缓存 + FunGameConstant.UserIdAndUsername[user.Id] = user; + bool updateQuest = false; + bool updateExplore = false; + // 任务结算 + EntityModuleConfig quests = new("quests", user.Id.ToString()); + quests.LoadConfig(); + if (quests.Count > 0 && SettleQuest(user, quests)) + { + quests.SaveConfig(); + updateQuest = true; + } + // 探索结算 + PluginConfig pc2 = new("exploring", user.Id.ToString()); + pc2.LoadConfig(); + if (pc2.Count > 0 && SettleExploreAll(pc2, user)) + { + pc2.SaveConfig(); + updateExplore = true; + } + if (updateQuest || updateExplore) + { + SetUserConfigButNotRelease(user.Id, pc, user); + } + if (FunGameConstant.UserLastVisitStore.TryGetValue(user.Id, out LastStoreModel? value) && value != null && (DateTime.Now - value.LastTime).TotalMinutes > 2) + { + FunGameConstant.UserLastVisitStore.Remove(user.Id); + } + } + ReleaseUserSemaphoreSlim(fileName); + } + } + } + + public static void RefreshDailyQuest() + { + string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/quests"; + if (Directory.Exists(directoryPath)) + { + string[] filePaths = Directory.GetFiles(directoryPath); + foreach (string filePath in filePaths) + { + string fileName = Path.GetFileNameWithoutExtension(filePath); + EntityModuleConfig quests = new("quests", fileName); + quests.Clear(); + CheckQuestList(quests); + quests.SaveConfig(); + } + } + } + + public static void RefreshDailySignIn() + { + // 刷新每天登录 + UserNotice.Clear(); + // 刷新签到 + string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/saved"; + if (Directory.Exists(directoryPath)) + { + string[] filePaths = Directory.GetFiles(directoryPath); + foreach (string filePath in filePaths) + { + string fileName = Path.GetFileNameWithoutExtension(filePath); + PluginConfig pc = GetUserConfig(fileName, out _); + pc.Add("signed", false); + pc.Add("logon", false); + pc.Add("lunch", false); + pc.Add("dinner", false); + pc.Add("exploreTimes", FunGameConstant.MaxExploreTimes); + pc.SaveConfig(); + ReleaseUserSemaphoreSlim(fileName); + } + } + } + + public static void RefreshStoreData() + { + // 刷新商店 + string directoryPath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/stores"; + if (Directory.Exists(directoryPath)) + { + string[] filePaths = Directory.GetFiles(directoryPath); + foreach (string filePath in filePaths) + { + string fileName = Path.GetFileNameWithoutExtension(filePath); + EntityModuleConfig stores = new("stores", fileName); + stores.LoadConfig(); + string[] storeNames = [.. stores.Keys]; + if (long.TryParse(fileName, out long userId) && FunGameConstant.UserIdAndUsername.TryGetValue(userId, out User? user) && user != null) + { + // 更新玩家商店数据,移除所有当天刷新的商店 + FunGameConstant.UserLastVisitStore.Remove(userId); + stores.Remove("daily"); + foreach (string key in storeNames) + { + Store? store = stores.Get(key); + if (store != null && (store.GlobalStock || (store.AutoRefresh && store.NextRefreshDate.Date <= DateTime.Today))) + { + stores.Remove(key); + } + } + CheckDailyStore(stores, user); + } + else + { + // 非玩家商店数据,需要更新模板的商品 + foreach (string key in storeNames) + { + Store? store = stores.Get(key); + if (store != null) + { + if (store.ExpireTime != null && store.ExpireTime.Value.Date <= DateTime.Today) + { + stores.Remove(key); + continue; + } + if (store.AutoRefresh && store.NextRefreshDate.Date <= DateTime.Today) + { + store.Goods.Clear(); + foreach (long goodsId in store.NextRefreshGoods.Keys) + { + store.Goods[goodsId] = store.NextRefreshGoods[goodsId]; + } + store.NextRefreshDate = DateTime.Today.AddHours(4).AddDays(store.RefreshInterval); + } + } + } + } + stores.SaveConfig(); + } + } + } + + public static void OnUserConfigSaving(PluginConfig pc, User user) + { + DateTime now = DateTime.Now; + if (!pc.TryGetValue("logon", out object? value) || (value is bool logon && !logon)) + { + pc.Add("logon", true); + AddNotice(user.Id, "欢迎回到筽祀牻大陆!请发送【帮助】获取更多玩法指令哦~"); + AddNotice(user.Id, GetEvents()); + foreach (NoticeModel notice in Notices.Values) + { + if (now >= notice.StartTime && now <= notice.EndTime) + { + AddNotice(user.Id, notice.ToString()); + } + } + } + int count1 = 30; + int count2 = 30; + DateTime d1 = DateTime.Today.AddHours(11); + DateTime d2 = DateTime.Today.AddHours(13); + DateTime d3 = DateTime.Today.AddHours(17); + DateTime d4 = DateTime.Today.AddHours(19); + if (now >= d1 && now <= d2 && (!pc.TryGetValue("lunch", out value) || (value is bool lunch && !lunch))) + { + int exploreTimes = FunGameConstant.MaxExploreTimes + count1; + if (pc.TryGetValue("exploreTimes", out object? value2) && int.TryParse(value2.ToString(), out exploreTimes)) + { + exploreTimes += count1; + } + pc.Add("exploreTimes", exploreTimes); + pc.Add("lunch", true); + AddNotice(user.Id, $"在 11-13 点期间登录游戏获得了午餐!(探索许可+{count1}~)"); + } + if (now >= d3 && now <= d4 && (!pc.TryGetValue("dinner", out value) || (value is bool dinner && !dinner))) + { + int exploreTimes = FunGameConstant.MaxExploreTimes + count2; + if (pc.TryGetValue("exploreTimes", out object? value2) && int.TryParse(value2.ToString(), out exploreTimes)) + { + exploreTimes += count2; + } + pc.Add("exploreTimes", exploreTimes); + pc.Add("dinner", true); + AddNotice(user.Id, $"在 17-19 点期间登录游戏获得了晚餐!(探索许可+{count2}~)"); + } + } + public static void ReleaseUserSemaphoreSlim(string key) { if (FunGameConstant.UserSemaphoreSlims.TryGetValue(key, out SemaphoreSlim? obj) && obj != null && obj.CurrentCount == 0) @@ -4016,6 +4207,7 @@ namespace Oshima.FunGame.OshimaServers.Service public static void SetUserConfig(string key, PluginConfig pc, User user, bool updateLastTime = true, bool release = true) { + OnUserConfigSaving(pc, user); if (updateLastTime) user.LastTime = DateTime.Now; pc.Add("user", user); pc.SaveConfig(); diff --git a/OshimaServers/Service/WebSocketService.cs b/OshimaServers/Service/WebSocketService.cs new file mode 100644 index 0000000..2df2323 --- /dev/null +++ b/OshimaServers/Service/WebSocketService.cs @@ -0,0 +1,196 @@ +using System.Data; +using Milimoe.FunGame.Core.Api.Transmittal; +using Milimoe.FunGame.Core.Controller; +using Milimoe.FunGame.Core.Interface.Addons; +using Milimoe.FunGame.Core.Library.Constant; + +namespace Oshima.FunGame.OshimaServers.Service +{ + public class WebSocketService(AnonymousServer server) + { + public AnonymousServer ServerInstance { get; set; } = server; + public ServerAddonController Controller => ServerInstance.Controller; + + public string SCAdd(Dictionary data) + { + string result = ""; + + using SQLHelper? sql = Controller.GetSQLHelper(); + if (sql != null) + { + try + { + long qq = Controller.JSON.GetObject(data, "qq"); + long groupid = Controller.JSON.GetObject(data, "groupid"); + double sc = Controller.JSON.GetObject(data, "sc"); + sql.NewTransaction(); + sql.Script = "select * from saints where qq = @qq and `group` = @group"; + sql.Parameters.Add("qq", qq); + sql.Parameters.Add("group", groupid); + sql.ExecuteDataSet(); + string content = Controller.JSON.GetObject(data, "content") ?? ""; + string record = ""; + if (sql.Success) + { + record = Convert.ToString(sql.DataSet.Tables[0].Rows[0]["record"]) ?? ""; + } + record = $"{DateTime.Now:MM/dd HH:mm}:{content}({(sc < 0 ? "-" : "+") + Math.Abs(sc)})\r\n{record}"; + record = string.Join("\r\n", record.Split("\r\n", StringSplitOptions.RemoveEmptyEntries).Take(10)); + if (sql.Success) + { + sql.Script = "update saints set sc = sc + @sc, record = @record where qq = @qq and `group` = @group"; + } + else + { + sql.Script = "insert into saints(qq, sc, `group`, record) values(@qq, @sc, @group, @record)"; + } + sql.Parameters.Add("sc", sc); + sql.Parameters.Add("qq", qq); + sql.Parameters.Add("group", groupid); + sql.Parameters.Add("record", record); + sql.Execute(); + if (sql.Success) + { + Controller.WriteLine($"用户 {qq} 的圣人点数增加了 {sc}", LogLevel.Debug); + sql.Commit(); + } + else + { + sql.Rollback(); + } + } + catch (Exception e) + { + result = e.ToString(); + sql.Rollback(); + } + } + else result = "无法调用此接口:SQL 服务不可用。"; + + return result; + } + + public string SCList(Dictionary data) + { + string result; + + SQLHelper? sql = Controller.SQLHelper; + if (sql != null) + { + long userQQ = Controller.JSON.GetObject(data, "qq"); + (bool userHas, double userSC, int userTop, string userRemark) = (false, 0, 0, ""); + long groupid = Controller.JSON.GetObject(data, "groupid"); + bool reverse = Controller.JSON.GetObject(data, "reverse"); + if (!reverse) + { + result = $"☆--- OSMTV 圣人排行榜 TOP10 ---☆\r\n统计时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}\r\n"; + } + else + { + result = $"☆--- OSMTV 出生排行榜 TOP10 ---☆\r\n统计时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}\r\n"; + } + sql.Script = "select * from saints where `group` = @group order by sc" + (!reverse ? " desc" : ""); + sql.Parameters.Add("group", groupid); + sql.ExecuteDataSet(); + if (sql.Success && sql.DataSet.Tables.Count > 0) + { + int count = 0; + foreach (DataRow dr in sql.DataSet.Tables[0].Rows) + { + count++; + long qq = Convert.ToInt64(dr["qq"]); + double sc = Convert.ToDouble(dr["sc"]); + string remark = Convert.ToString(dr["remark"]) ?? ""; + if (reverse) + { + sc = -sc; + remark = remark.Replace("+", "-"); + } + if (qq == userQQ) + { + userHas = true; + userSC = sc; + userTop = count; + userRemark = remark; + } + if (count > 10) continue; + if (!reverse) + { + result += $"{count}. 用户:{qq},圣人点数:{sc} 分{(remark.Trim() != "" ? $" ({remark})" : "")}\r\n"; + } + else + { + result += $"{count}. 用户:{qq},出生点数:{sc} 分{(remark.Trim() != "" ? $" ({remark})" : "")}\r\n"; + } + } + if (!reverse && userHas) + { + result += $"你的圣人点数为:{userSC} 分{(userRemark.Trim() != "" ? $"({userRemark})" : "")},排在第 {userTop} / {sql.DataSet.Tables[0].Rows.Count} 名。\r\n" + + $"本排行榜仅供娱乐,不代表任何官方立场或真实情况。"; + } + if (reverse && userHas) + { + result += $"你的出生点数为:{userSC} 分{(userRemark.Trim() != "" ? $"({userRemark})" : "")},排在出生榜第 {userTop} / {sql.DataSet.Tables[0].Rows.Count} 名。\r\n" + + $"本排行榜仅供娱乐,不代表任何官方立场或真实情况。"; + } + } + else + { + if (reverse) + { + result = "出生榜目前没有任何数据。"; + } + else + { + result = "圣人榜目前没有任何数据。"; + } + } + } + else result = "无法调用此接口:SQL 服务不可用。"; + + return result.Trim(); + } + + public string SCRecord(Dictionary data) + { + string result = ""; + + SQLHelper? sql = Controller.SQLHelper; + if (sql != null) + { + long userQQ = Controller.JSON.GetObject(data, "qq"); + long groupid = Controller.JSON.GetObject(data, "groupid"); + result = $"☆--- 圣人点数信息 ---☆\r\n统计时间:{DateTime.Now.ToString(General.GeneralDateTimeFormatChinese)}\r\n"; + sql.Script = "select * from saints where `group` = @group order by sc desc"; + sql.Parameters.Add("group", groupid); + sql.Parameters.Add("qq", userQQ); + sql.ExecuteDataSet(); + if (sql.Success && sql.DataSet.Tables.Count > 0) + { + Dictionary dict = sql.DataSet.Tables[0].AsEnumerable().Select((r, i) => new { Index = i + 1, Row = r }).ToDictionary(c => c.Index, c => c.Row); + int index = dict.Where(kv => Convert.ToInt64(kv.Value["qq"]) == userQQ).Select(r => r.Key).FirstOrDefault(); + if (index != 0 && dict.TryGetValue(index, out DataRow? dr) && dr != null) + { + long qq = Convert.ToInt64(dr["qq"]); + double sc = Convert.ToDouble(dr["sc"]); + string remark = Convert.ToString(dr["remark"]) ?? ""; + string record = Convert.ToString(dr["record"]) ?? ""; + result += $"用户:{qq},圣人点数:{sc} 分{(remark.Trim() != "" ? $" ({remark})" : "")},排在圣人榜第 {index} / {sql.DataSet.Tables[0].Rows.Count} 名。\r\n" + + $"{(record != "" ? "显示近期点数变动信息:\r\n" + record + "\r\n" : "")}本系统仅供娱乐,不代表任何官方立场或真实情况。"; + } + else + { + result = "你在这个群没有任何历史记录。"; + } + } + else + { + result = "你在这个群没有任何历史记录。"; + } + } + else result = "无法调用此接口:SQL 服务不可用。"; + + return result.Trim(); + } + } +} diff --git a/OshimaWebAPI/Controllers/FunGameController.cs b/OshimaWebAPI/Controllers/FunGameController.cs index 021e1b9..8795cab 100644 --- a/OshimaWebAPI/Controllers/FunGameController.cs +++ b/OshimaWebAPI/Controllers/FunGameController.cs @@ -5411,7 +5411,7 @@ namespace Oshima.FunGame.WebAPI.Controllers if (newItem.ItemType != ItemType.MagicCard) newItem.SetLevel(1); itemMsg += $"[ {count} ] {newItem.ToString(false, true)}".Trim(); } - msg = good.ToString().Split("包含物品:")[0].Trim(); + msg = good.ToString(user).Split("包含物品:")[0].Trim(); msg += $"\r\n包含物品:\r\n" + itemMsg + $"\r\n剩余库存:{(good.Stock == -1 ? "不限量提供" : good.Stock)}"; } @@ -7156,7 +7156,7 @@ namespace Oshima.FunGame.WebAPI.Controllers if (newItem.ItemType != ItemType.MagicCard) newItem.SetLevel(1); itemMsg += $"[ {count} ] {newItem.ToString(false, true)}".Trim(); } - msg = good.ToString().Split("包含物品:")[0].Trim(); + msg = good.ToString(user).Split("包含物品:")[0].Trim(); msg += $"\r\n包含物品:\r\n" + itemMsg + $"\r\n剩余库存:{(good.Stock == -1 ? "不限量提供" : good.Stock)}"; } diff --git a/OshimaWebAPI/Services/RainBOTService.cs b/OshimaWebAPI/Services/RainBOTService.cs index 28732fa..b204979 100644 --- a/OshimaWebAPI/Services/RainBOTService.cs +++ b/OshimaWebAPI/Services/RainBOTService.cs @@ -34,9 +34,8 @@ namespace Oshima.FunGame.WebAPI.Services { third.Result += "\r\n" + content.Trim(); third.IsCompleted = true; - return; } - if (msg.IsGroup) + else if (msg.IsGroup) { content = "\r\n" + content.Trim(); await Service.SendGroupMessageAsync(msg.OpenId, content, msgType, media, msg.Id, msgSeq); @@ -49,7 +48,7 @@ namespace Oshima.FunGame.WebAPI.Services if (msg.UseNotice && msg.FunGameUID > 0 && FunGameService.UserNotice.TryGetValue(msg.FunGameUID, out HashSet? msgs) && msgs != null) { FunGameService.UserNotice.Remove(msg.FunGameUID); - await SendAsync(msg, "每日登录提醒", string.Join("\r\n", msgs), msgType, media, 5); + await SendAsync(msg, "离线未读信箱", $"☆--- 离线未读信箱 ---☆\r\n{string.Join("\r\n", msgs)}", msgType, media, 5); } } @@ -154,6 +153,81 @@ namespace Oshima.FunGame.WebAPI.Services return true; } + if (e.Detail == "公告") + { + e.UseNotice = false; + FunGameService.RefreshNotice(); + if (FunGameService.Notices.Count > 0) + { + List msgs = []; + DateTime now = DateTime.Now; + foreach (NoticeModel notice in FunGameService.Notices.Values) + { + if (now >= notice.StartTime && now <= notice.EndTime) + { + msgs.Add(notice.ToString()); + } + } + await SendAsync(e, "公告", string.Join("\r\n", msgs)); + } + else + { + await SendAsync(e, "公告", "当前没有任何系统公告。"); + } + return true; + } + + if (e.Detail == "刷新公告") + { + e.UseNotice = false; + FunGameService.RefreshNotice(); + return true; + } + + if (e.Detail.StartsWith("添加公告")) + { + e.UseNotice = false; + string detail = e.Detail.Replace("添加公告", "").Trim(); + string[] strings = detail.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); + string title = $"#Unknown"; + if (strings.Length > 1) + { + title = strings[0].Trim(); + detail = strings[1].Trim(); + } + else + { + await SendAsync(e, "添加公告", $"格式错误:添加公告 <标题>\r\n<内容> [有效期 <天数>]。"); + return true; + } + strings = detail.Split("有效期"); + int days = 1; + if (strings.Length > 1) + { + if (int.TryParse(strings[1].Trim(), out int d)) + { + days = d; + } + detail = strings[0].Trim(); + } + string author = "FunGame"; + if (FunGameConstant.UserIdAndUsername.TryGetValue(uid, out User? user) && user != null) + { + author = user.Username; + } + FunGameService.Notices.Add(title, new NoticeModel() + { + Title = title, + Author = author, + Content = detail, + StartTime = DateTime.Now, + EndTime = DateTime.Today.AddHours(3).AddMinutes(59).AddSeconds(59).AddDays(days) + }); + FunGameService.Notices.SaveConfig(); + await SendAsync(e, "添加公告", $"添加完毕,请查看【公告】列表!"); + return true; + } + if (e.Detail == "查询服务器启动时间") { e.UseNotice = false;