From d6787de920207ba6dee7b9c2482429ef35f75d81 Mon Sep 17 00:00:00 2001
From: milimoe <110188673+milimoe@users.noreply.github.com>
Date: Sat, 24 Aug 2024 01:17:47 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0EntityModuleConfig=E5=B8=AE?=
=?UTF-8?q?=E5=8A=A9=E7=B1=BB=EF=BC=9B=E6=B7=BB=E5=8A=A0AddonDLL=E7=9A=84S?=
=?UTF-8?q?HA512=E5=93=88=E5=B8=8C=E9=AA=8C=E8=AF=81=20(#85)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Api/Utility/EntityModuleConfig.cs | 107 ++++++++++++++++++++++++++++++
Api/Utility/GameModuleLoader.cs | 5 ++
Api/Utility/General.cs | 88 +++++++++++++-----------
Api/Utility/PluginConfig.cs | 2 +-
Api/Utility/PluginLoader.cs | 5 ++
Api/Utility/TextReader.cs | 25 ++++---
Service/AddonManager.cs | 65 ++++++++++++++----
7 files changed, 238 insertions(+), 59 deletions(-)
create mode 100644 Api/Utility/EntityModuleConfig.cs
diff --git a/Api/Utility/EntityModuleConfig.cs b/Api/Utility/EntityModuleConfig.cs
new file mode 100644
index 0000000..c16fcb3
--- /dev/null
+++ b/Api/Utility/EntityModuleConfig.cs
@@ -0,0 +1,107 @@
+using Milimoe.FunGame.Core.Entity;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.Core.Api.Utility
+{
+ ///
+ /// 简易的实体模组配置文件生成器
+ /// 仅支持继承了 的实体类型,每个 仅保存一种实体类型的数据
+ /// 文件会保存为:程序目录/configs//.json
+ ///
+ ///
+ /// 新建一个配置文件,文件会保存为:程序目录/configs//.json
+ ///
+ ///
+ ///
+ public class EntityModuleConfig(string module_name, string file_name) : Dictionary where T : BaseEntity
+ {
+ ///
+ /// 模组的名称
+ ///
+ public string ModuleName { get; set; } = module_name;
+
+ ///
+ /// 配置文件的名称(后缀将是.json)
+ ///
+ public string FileName { get; set; } = file_name;
+
+ ///
+ /// 使用索引器给指定key赋值,不存在key会新增
+ ///
+ ///
+ ///
+ public new T this[string key]
+ {
+ get => base[key];
+ set
+ {
+ if (value != null) Add(key, value);
+ }
+ }
+
+ ///
+ /// 获取指定key的value
+ ///
+ ///
+ ///
+ public T? Get(string key)
+ {
+ if (TryGetValue(key, out T? value) && value != null)
+ {
+ return value;
+ }
+ return null;
+ }
+
+ ///
+ /// 添加一个配置,如果已存在key会覆盖
+ ///
+ ///
+ ///
+ public new void Add(string key, T value)
+ {
+ if (value != null)
+ {
+ if (TryGetValue(key, out _)) base[key] = value;
+ else base.Add(key, value);
+ }
+ }
+
+ ///
+ /// 从配置文件中读取配置。
+ ///
+ public void LoadConfig()
+ {
+ string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/{ModuleName}";
+ string fpath = $@"{dpath}/{FileName}.json";
+ if (Directory.Exists(dpath) && File.Exists(fpath))
+ {
+ string json = File.ReadAllText(fpath, General.DefaultEncoding);
+ Dictionary dict = NetworkUtility.JsonDeserialize>(json) ?? [];
+ Clear();
+ foreach (string key in dict.Keys)
+ {
+ T obj = dict[key];
+ base.Add(key, obj);
+ }
+ }
+ }
+
+ ///
+ /// 将配置保存到配置文件。调用此方法会覆盖原有的.json,请注意备份
+ ///
+ public void SaveConfig()
+ {
+ string json = NetworkUtility.JsonSerialize((Dictionary)this);
+ string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}configs/{ModuleName}";
+ string fpath = $@"{dpath}/{FileName}.json";
+ if (!Directory.Exists(dpath))
+ {
+ Directory.CreateDirectory(dpath);
+ }
+ using StreamWriter writer = new(fpath, false, General.DefaultEncoding);
+ writer.WriteLine(json);
+ writer.Flush();
+ }
+ }
+}
diff --git a/Api/Utility/GameModuleLoader.cs b/Api/Utility/GameModuleLoader.cs
index e05a694..323a928 100644
--- a/Api/Utility/GameModuleLoader.cs
+++ b/Api/Utility/GameModuleLoader.cs
@@ -42,6 +42,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
///
public Dictionary AssociatedServers { get; } = [];
+ ///
+ /// 已加载的模组DLL名称对应的路径
+ ///
+ public static Dictionary ModuleFilePaths => new(AddonManager.ModuleFilePaths);
+
private GameModuleLoader() { }
///
diff --git a/Api/Utility/General.cs b/Api/Utility/General.cs
index 3f924f6..26aa4cb 100644
--- a/Api/Utility/General.cs
+++ b/Api/Utility/General.cs
@@ -340,50 +340,63 @@ namespace Milimoe.FunGame.Core.Api.Utility
public class Encryption
{
///
- /// 使用HMACSHA512算法加密
+ /// 使用 HMAC-SHA512 算法对文本进行加密
///
- /// 需要加密的值
- /// 秘钥
- ///
- internal static string HmacSha512(string Message, string Key)
+ /// 需要加密的文本
+ /// 用于加密的秘钥
+ /// 加密后的 HMAC-SHA512 哈希值
+ public static string HmacSha512(string text, string key)
{
- byte[] MessageBytes = General.DefaultEncoding.GetBytes(Message);
- Key = Convert.ToBase64String(General.DefaultEncoding.GetBytes(Key));
- byte[] KeyBytes = General.DefaultEncoding.GetBytes(Key);
- HMACSHA512 Hmacsha512 = new(KeyBytes);
- byte[] Hash = Hmacsha512.ComputeHash(MessageBytes);
- string Hmac = BitConverter.ToString(Hash).Replace("-", "");
- return Hmac.ToLower();
+ byte[] text_bytes = General.DefaultEncoding.GetBytes(text);
+ key = Convert.ToBase64String(General.DefaultEncoding.GetBytes(key));
+ byte[] key_bytes = General.DefaultEncoding.GetBytes(key);
+ HMACSHA512 hmacsha512 = new(key_bytes);
+ byte[] hash_bytes = hmacsha512.ComputeHash(text_bytes);
+ string hmac = BitConverter.ToString(hash_bytes).Replace("-", "");
+ return hmac.ToLower();
}
///
- /// 使用RSA算法加密
+ /// 计算文件的 SHA-256 哈希值
///
- /// 明文
- /// 公钥
- ///
- public static string RSAEncrypt(string PlainText, string PublicKey)
+ /// 要计算哈希值的文件路径
+ /// 文件的 SHA-256 哈希值
+ public static string FileSha512(string file_path)
{
- byte[] Plain = Encoding.UTF8.GetBytes(PlainText);
- using RSACryptoServiceProvider RSA = new();
- RSA.FromXmlString(PublicKey);
- byte[] Encrypted = RSA.Encrypt(Plain, false);
- return Convert.ToBase64String(Encrypted);
+ using SHA256 sha256 = SHA256.Create();
+ using FileStream stream = File.OpenRead(file_path);
+ byte[] hash = sha256.ComputeHash(stream);
+ return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
///
- /// 使用RSA算法解密
+ /// 使用 RSA 算法加密
///
- /// 密文
- /// 私钥
+ /// 明文
+ /// 公钥
///
- public static string RSADecrypt(string SecretText, string PrivateKey)
+ public static string RSAEncrypt(string plain_text, string plublic_key)
{
- byte[] Encrypted = Convert.FromBase64String(SecretText);
- using RSACryptoServiceProvider RSA = new();
- RSA.FromXmlString(PrivateKey);
- byte[] Decrypted = RSA.Decrypt(Encrypted, false);
- return Encoding.UTF8.GetString(Decrypted);
+ byte[] plain = Encoding.UTF8.GetBytes(plain_text);
+ using RSACryptoServiceProvider rsa = new();
+ rsa.FromXmlString(plublic_key);
+ byte[] encrypted = rsa.Encrypt(plain, false);
+ return Convert.ToBase64String(encrypted);
+ }
+
+ ///
+ /// 使用 RSA 算法解密
+ ///
+ /// 密文
+ /// 私钥
+ ///
+ public static string RSADecrypt(string secret_text, string private_key)
+ {
+ byte[] secret = Convert.FromBase64String(secret_text);
+ using RSACryptoServiceProvider rsa = new();
+ rsa.FromXmlString(private_key);
+ byte[] decrypted = rsa.Decrypt(secret, false);
+ return Encoding.UTF8.GetString(decrypted);
}
}
@@ -393,14 +406,15 @@ namespace Milimoe.FunGame.Core.Api.Utility
public static class StringExtension
{
///
- /// 使用HMACSHA512算法加密
+ /// 使用 HMAC-SHA512 算法对文本进行加密
+ /// 注意:此方法会先将 转为小写并计算两次哈希。
///
- /// 需要加密的值
- /// 秘钥
- ///
- public static string Encrypt(this string msg, string key)
+ /// 需要加密的文本
+ /// 用于加密的秘钥
+ /// 加密后的 HMAC-SHA512 哈希值
+ public static string Encrypt(this string text, string key)
{
- return Encryption.HmacSha512(msg, Encryption.HmacSha512(msg, key.ToLower()));
+ return Encryption.HmacSha512(text, Encryption.HmacSha512(text, key.ToLower()));
}
}
diff --git a/Api/Utility/PluginConfig.cs b/Api/Utility/PluginConfig.cs
index 894871f..5db7f8c 100644
--- a/Api/Utility/PluginConfig.cs
+++ b/Api/Utility/PluginConfig.cs
@@ -9,7 +9,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// 文件会保存为:程序目录/configs//.json
///
///
- /// 新建一个配置文件,文件会保存为:程序目录/configs//.json
+ /// 新建一个配置文件,文件会保存为:程序目录/configs//.json
///
///
///
diff --git a/Api/Utility/PluginLoader.cs b/Api/Utility/PluginLoader.cs
index 40875a5..a17aaf2 100644
--- a/Api/Utility/PluginLoader.cs
+++ b/Api/Utility/PluginLoader.cs
@@ -13,6 +13,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
///
public Dictionary Plugins { get; } = [];
+ ///
+ /// 已加载的插件DLL名称对应的路径
+ ///
+ public static Dictionary PluginFilePaths => new(AddonManager.PluginFilePaths);
+
private PluginLoader()
{
diff --git a/Api/Utility/TextReader.cs b/Api/Utility/TextReader.cs
index 5521d04..21832f5 100644
--- a/Api/Utility/TextReader.cs
+++ b/Api/Utility/TextReader.cs
@@ -130,7 +130,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
///
/// 读取TXT文件内容
///
- /// 文件名
+ /// 文件名(需要包含扩展名)
/// 相对路径
/// 内容
public static string ReadTXT(string filename, string path = "")
@@ -154,13 +154,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
///
- /// 写入TXT文件内容(如不存在文件会创建,反之新起一行追加)
+ /// 写入TXT文件内容(如不存在文件会创建)
+ /// 选项用于覆盖或追加文本
///
- ///
- /// 文件名
+ ///
+ /// 文件名(需要包含扩展名)
/// 相对路径
- /// 内容
- public static void WriteTXT(string message, string filename, string path = "")
+ /// 是否覆盖
+ public static void WriteTXT(string content, string filename, string path = "", bool overwrite = false)
{
if (path.Trim() != "")
{
@@ -170,11 +171,19 @@ namespace Milimoe.FunGame.Core.Api.Utility
}
else path = $@"{AppDomain.CurrentDomain.BaseDirectory}{filename}";
// 写入内容
- StreamWriter writer = File.Exists(path) ? new(path, true, General.DefaultEncoding) : new(path, false, General.DefaultEncoding);
- writer.WriteLine(message);
+ StreamWriter writer = File.Exists(path) ? new(path, !overwrite, General.DefaultEncoding) : new(path, false, General.DefaultEncoding);
+ writer.WriteLine(content);
writer.Close();
}
+ ///
+ /// 写入并覆盖TXT文件内容
+ ///
+ ///
+ /// 文件名(需要包含扩展名)
+ /// 相对路径
+ public static void OverwriteTXT(string content, string filename, string path = "") => WriteTXT(content, filename, path, true);
+
///
/// 追加错误日志 默认写入logs文件夹下的当日日期.log文件
///
diff --git a/Service/AddonManager.cs b/Service/AddonManager.cs
index af13f15..01777e6 100644
--- a/Service/AddonManager.cs
+++ b/Service/AddonManager.cs
@@ -8,6 +8,16 @@ namespace Milimoe.FunGame.Core.Service
{
internal class AddonManager
{
+ ///
+ /// 已加载的插件DLL名称对应的路径
+ ///
+ internal static Dictionary PluginFilePaths { get; } = [];
+
+ ///
+ /// 已加载的模组DLL名称对应的路径
+ ///
+ internal static Dictionary ModuleFilePaths { get; } = [];
+
///
/// 从plugins目录加载所有插件
///
@@ -28,7 +38,7 @@ namespace Milimoe.FunGame.Core.Service
foreach (Type type in assembly.GetTypes().AsEnumerable().Where(type => type.IsSubclassOf(typeof(Plugin))))
{
- AddAddonInstances(type, plugins, (instance) =>
+ if (AddAddonInstances(type, plugins, (instance) =>
{
if (instance.Load(otherobjs))
{
@@ -36,7 +46,10 @@ namespace Milimoe.FunGame.Core.Service
return true;
}
return false;
- });
+ }))
+ {
+ AddDictionary(PluginFilePaths, assembly, dll);
+ }
}
}
@@ -65,9 +78,11 @@ namespace Milimoe.FunGame.Core.Service
foreach (Type type in assembly.GetTypes().AsEnumerable().Where(type => typeof(IAddon).IsAssignableFrom(type)))
{
+ bool isAdded = false;
+
if (type.IsSubclassOf(typeof(GameModule)))
{
- AddAddonInstances(type, modules, (instance) =>
+ isAdded = AddAddonInstances(type, modules, (instance) =>
{
if (instance.Load(otherobjs))
{
@@ -79,15 +94,20 @@ namespace Milimoe.FunGame.Core.Service
}
else if (type.IsSubclassOf(typeof(CharacterModule)))
{
- AddAddonInstances(type, characters, (instance) => instance.Load(otherobjs));
+ isAdded = AddAddonInstances(type, characters, (instance) => instance.Load(otherobjs));
}
else if (type.IsSubclassOf(typeof(SkillModule)))
{
- AddAddonInstances(type, skills, (instance) => instance.Load(otherobjs));
+ isAdded = AddAddonInstances(type, skills, (instance) => instance.Load(otherobjs));
}
else if (type.IsSubclassOf(typeof(ItemModule)))
{
- AddAddonInstances(type, items, (instance) => instance.Load(otherobjs));
+ isAdded = AddAddonInstances(type, items, (instance) => instance.Load(otherobjs));
+ }
+
+ if (isAdded)
+ {
+ AddDictionary(ModuleFilePaths, assembly, dll);
}
}
}
@@ -118,9 +138,11 @@ namespace Milimoe.FunGame.Core.Service
foreach (Type type in assembly.GetTypes().AsEnumerable().Where(type => typeof(IAddon).IsAssignableFrom(type)))
{
+ bool isAdded = false;
+
if (type.IsSubclassOf(typeof(GameModule)))
{
- AddAddonInstances(type, modules, (instance) =>
+ isAdded = AddAddonInstances(type, modules, (instance) =>
{
if (instance.Load(otherobjs))
{
@@ -132,7 +154,7 @@ namespace Milimoe.FunGame.Core.Service
}
else if (type.IsSubclassOf(typeof(GameModuleServer)))
{
- AddAddonInstances(type, servers, (instance) =>
+ isAdded = AddAddonInstances(type, servers, (instance) =>
{
if (instance.Load(otherobjs))
{
@@ -144,15 +166,20 @@ namespace Milimoe.FunGame.Core.Service
}
else if (type.IsSubclassOf(typeof(CharacterModule)))
{
- AddAddonInstances(type, characters, (instance) => instance.Load(otherobjs));
+ isAdded = AddAddonInstances(type, characters, (instance) => instance.Load(otherobjs));
}
else if (type.IsSubclassOf(typeof(SkillModule)))
{
- AddAddonInstances(type, skills, (instance) => instance.Load(otherobjs));
+ isAdded = AddAddonInstances(type, skills, (instance) => instance.Load(otherobjs));
}
else if (type.IsSubclassOf(typeof(ItemModule)))
{
- AddAddonInstances(type, items, (instance) => instance.Load(otherobjs));
+ isAdded = AddAddonInstances(type, items, (instance) => instance.Load(otherobjs));
+ }
+
+ if (isAdded)
+ {
+ AddDictionary(ModuleFilePaths, assembly, dll);
}
}
}
@@ -178,7 +205,10 @@ namespace Milimoe.FunGame.Core.Service
foreach (Type type in assembly.GetTypes().AsEnumerable().Where(type => type.IsSubclassOf(typeof(GameMap))))
{
- AddAddonInstances(type, maps, (instance) => instance.Load(objs));
+ if (AddAddonInstances(type, maps, (instance) => instance.Load(objs)))
+ {
+ AddDictionary(ModuleFilePaths, assembly, dll);
+ }
}
}
@@ -192,8 +222,9 @@ namespace Milimoe.FunGame.Core.Service
/// 循环程序集的类型
/// 实例的字典
/// 加载时触发的检查方法,返回false不添加
- private static void AddAddonInstances(Type type, Dictionary dictionary, Func? isadd = null) where T : IAddon
+ private static bool AddAddonInstances(Type type, Dictionary dictionary, Func? isadd = null) where T : IAddon
{
+ bool isAdded = false;
T? instance = (T?)Activator.CreateInstance(type);
if (instance != null)
{
@@ -201,8 +232,16 @@ namespace Milimoe.FunGame.Core.Service
if (!string.IsNullOrWhiteSpace(name) && (isadd == null || isadd(instance)))
{
dictionary.TryAdd(name.Trim(), instance);
+ isAdded = true;
}
}
+ return isAdded;
+ }
+
+ private static void AddDictionary(Dictionary dict, Assembly assembly, string dllpath)
+ {
+ string filename = assembly.GetName().Name?.Trim() ?? "";
+ if (filename != "") dict.TryAdd(filename, dllpath);
}
}
}