mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-12-05 08:09:02 +00:00
添加EntityModuleConfig帮助类;添加AddonDLL的SHA512哈希验证 (#85)
This commit is contained in:
parent
e07d0abb90
commit
d6787de920
107
Api/Utility/EntityModuleConfig.cs
Normal file
107
Api/Utility/EntityModuleConfig.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using Milimoe.FunGame.Core.Entity;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
|
||||
namespace Milimoe.FunGame.Core.Api.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// 简易的实体模组配置文件生成器<para/>
|
||||
/// 仅支持继承了 <see cref="BaseEntity"/> 的实体类型,每个 <see cref="EntityModuleConfig{T}"/> 仅保存一种实体类型的数据
|
||||
/// <para/>文件会保存为:程序目录/configs/<see cref="ModuleName"/>/<see cref="FileName"/>.json
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 新建一个配置文件,文件会保存为:程序目录/configs/<paramref name="module_name"/>/<paramref name="file_name"/>.json
|
||||
/// </remarks>
|
||||
/// <param name="module_name"></param>
|
||||
/// <param name="file_name"></param>
|
||||
public class EntityModuleConfig<T>(string module_name, string file_name) : Dictionary<string, T> where T : BaseEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 模组的名称
|
||||
/// </summary>
|
||||
public string ModuleName { get; set; } = module_name;
|
||||
|
||||
/// <summary>
|
||||
/// 配置文件的名称(后缀将是.json)
|
||||
/// </summary>
|
||||
public string FileName { get; set; } = file_name;
|
||||
|
||||
/// <summary>
|
||||
/// 使用索引器给指定key赋值,不存在key会新增
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public new T this[string key]
|
||||
{
|
||||
get => base[key];
|
||||
set
|
||||
{
|
||||
if (value != null) Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定key的value
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public T? Get(string key)
|
||||
{
|
||||
if (TryGetValue(key, out T? value) && value != null)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个配置,如果已存在key会覆盖
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public new void Add(string key, T value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (TryGetValue(key, out _)) base[key] = value;
|
||||
else base.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从配置文件中读取配置。
|
||||
/// </summary>
|
||||
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<string, T> dict = NetworkUtility.JsonDeserialize<Dictionary<string, T>>(json) ?? [];
|
||||
Clear();
|
||||
foreach (string key in dict.Keys)
|
||||
{
|
||||
T obj = dict[key];
|
||||
base.Add(key, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将配置保存到配置文件。调用此方法会覆盖原有的.json,请注意备份
|
||||
/// </summary>
|
||||
public void SaveConfig()
|
||||
{
|
||||
string json = NetworkUtility.JsonSerialize((Dictionary<string, T>)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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,6 +42,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
/// </summary>
|
||||
public Dictionary<GameModule, GameModuleServer?> AssociatedServers { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 已加载的模组DLL名称对应的路径
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> ModuleFilePaths => new(AddonManager.ModuleFilePaths);
|
||||
|
||||
private GameModuleLoader() { }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -340,50 +340,63 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
public class Encryption
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用HMACSHA512算法加密
|
||||
/// 使用 HMAC-SHA512 算法对文本进行加密
|
||||
/// </summary>
|
||||
/// <param name="Message">需要加密的值</param>
|
||||
/// <param name="Key">秘钥</param>
|
||||
/// <returns></returns>
|
||||
internal static string HmacSha512(string Message, string Key)
|
||||
/// <param name="text">需要加密的文本</param>
|
||||
/// <param name="key">用于加密的秘钥</param>
|
||||
/// <returns>加密后的 HMAC-SHA512 哈希值</returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算文件的 SHA-256 哈希值
|
||||
/// </summary>
|
||||
/// <param name="file_path">要计算哈希值的文件路径</param>
|
||||
/// <returns>文件的 SHA-256 哈希值</returns>
|
||||
public static string FileSha512(string file_path)
|
||||
{
|
||||
using SHA256 sha256 = SHA256.Create();
|
||||
using FileStream stream = File.OpenRead(file_path);
|
||||
byte[] hash = sha256.ComputeHash(stream);
|
||||
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用 RSA 算法加密
|
||||
/// </summary>
|
||||
/// <param name="PlainText">明文</param>
|
||||
/// <param name="PublicKey">公钥</param>
|
||||
/// <param name="plain_text">明文</param>
|
||||
/// <param name="plublic_key">公钥</param>
|
||||
/// <returns></returns>
|
||||
public static string RSAEncrypt(string PlainText, string PublicKey)
|
||||
public static string RSAEncrypt(string plain_text, string plublic_key)
|
||||
{
|
||||
byte[] Plain = Encoding.UTF8.GetBytes(PlainText);
|
||||
using RSACryptoServiceProvider RSA = new();
|
||||
RSA.FromXmlString(PublicKey);
|
||||
byte[] Encrypted = RSA.Encrypt(Plain, false);
|
||||
return Convert.ToBase64String(Encrypted);
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用 RSA 算法解密
|
||||
/// </summary>
|
||||
/// <param name="SecretText">密文</param>
|
||||
/// <param name="PrivateKey">私钥</param>
|
||||
/// <param name="secret_text">密文</param>
|
||||
/// <param name="private_key">私钥</param>
|
||||
/// <returns></returns>
|
||||
public static string RSADecrypt(string SecretText, string PrivateKey)
|
||||
public static string RSADecrypt(string secret_text, string private_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[] 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
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用HMACSHA512算法加密
|
||||
/// 使用 HMAC-SHA512 算法对文本进行加密<para/>
|
||||
/// 注意:此方法会先将 <paramref name="key" /> 转为小写并计算两次哈希。
|
||||
/// </summary>
|
||||
/// <param name="msg">需要加密的值</param>
|
||||
/// <param name="key">秘钥</param>
|
||||
/// <returns></returns>
|
||||
public static string Encrypt(this string msg, string key)
|
||||
/// <param name="text">需要加密的文本</param>
|
||||
/// <param name="key">用于加密的秘钥</param>
|
||||
/// <returns>加密后的 HMAC-SHA512 哈希值</returns>
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
/// <para/>文件会保存为:程序目录/configs/<see cref="PluginName"/>/<see cref="FileName"/>.json
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 新建一个配置文件,文件会保存为:程序目录/configs/<see cref="PluginName"/>/<see cref="FileName"/>.json
|
||||
/// 新建一个配置文件,文件会保存为:程序目录/configs/<paramref name="plugin_name"/>/<paramref name="file_name"/>.json
|
||||
/// </remarks>
|
||||
/// <param name="plugin_name"></param>
|
||||
/// <param name="file_name"></param>
|
||||
|
||||
@ -13,6 +13,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
/// </summary>
|
||||
public Dictionary<string, Plugin> Plugins { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 已加载的插件DLL名称对应的路径
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> PluginFilePaths => new(AddonManager.PluginFilePaths);
|
||||
|
||||
private PluginLoader()
|
||||
{
|
||||
|
||||
|
||||
@ -130,7 +130,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
/// <summary>
|
||||
/// 读取TXT文件内容
|
||||
/// </summary>
|
||||
/// <param name="filename">文件名</param>
|
||||
/// <param name="filename">文件名(需要包含扩展名)</param>
|
||||
/// <param name="path">相对路径</param>
|
||||
/// <returns>内容</returns>
|
||||
public static string ReadTXT(string filename, string path = "")
|
||||
@ -154,13 +154,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入TXT文件内容(如不存在文件会创建,反之新起一行追加)
|
||||
/// 写入TXT文件内容(如不存在文件会创建)<para/>
|
||||
/// <paramref name="overwrite" /> 选项用于覆盖或追加文本
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="filename">文件名</param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="filename">文件名(需要包含扩展名)</param>
|
||||
/// <param name="path">相对路径</param>
|
||||
/// <returns>内容</returns>
|
||||
public static void WriteTXT(string message, string filename, string path = "")
|
||||
/// <param name="overwrite">是否覆盖</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入并覆盖TXT文件内容
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="filename">文件名(需要包含扩展名)</param>
|
||||
/// <param name="path">相对路径</param>
|
||||
public static void OverwriteTXT(string content, string filename, string path = "") => WriteTXT(content, filename, path, true);
|
||||
|
||||
/// <summary>
|
||||
/// 追加错误日志 默认写入logs文件夹下的当日日期.log文件
|
||||
/// </summary>
|
||||
|
||||
@ -8,6 +8,16 @@ namespace Milimoe.FunGame.Core.Service
|
||||
{
|
||||
internal class AddonManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 已加载的插件DLL名称对应的路径
|
||||
/// </summary>
|
||||
internal static Dictionary<string, string> PluginFilePaths { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 已加载的模组DLL名称对应的路径
|
||||
/// </summary>
|
||||
internal static Dictionary<string, string> ModuleFilePaths { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 从plugins目录加载所有插件
|
||||
/// </summary>
|
||||
@ -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
|
||||
/// <param name="type">循环程序集的类型</param>
|
||||
/// <param name="dictionary">实例的字典</param>
|
||||
/// <param name="isadd">加载时触发的检查方法,返回false不添加</param>
|
||||
private static void AddAddonInstances<T>(Type type, Dictionary<string, T> dictionary, Func<T, bool>? isadd = null) where T : IAddon
|
||||
private static bool AddAddonInstances<T>(Type type, Dictionary<string, T> dictionary, Func<T, bool>? 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<string, string> dict, Assembly assembly, string dllpath)
|
||||
{
|
||||
string filename = assembly.GetName().Name?.Trim() ?? "";
|
||||
if (filename != "") dict.TryAdd(filename, dllpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user