# TaiwuModFramework **Repository Path**: g_yl/taiwu-mod-framework ## Basic Information - **Project Name**: TaiwuModFramework - **Description**: 太吾mod框架 - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2023-03-23 - **Last Updated**: 2023-04-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: 太吾绘卷 ## README # 太吾Mod框架 - [开发模板](https://gitee.com/g_yl/taiwu-mod-template) - [gitee](https://gitee.com/g_yl/taiwu-mod-framework) ## 功能 1. 实现组件的自动配置,所有的组件都基于`BaseTaiwuComp`,在mod加载是只需指定使用那些组件即可 1. 自动更新配置选项,使用`[AttrConfigItem("配置项的Key")]`特性,当`OnModSettingUpdate`时会自动更新 1. 前后端同等地位,可互相调用提供的服务 1. 前后端相同的日志工具,输出路径在`~\Mod\TaiwuModFramework\Logs` ## 使用 ### 基础使用 1. 前后端引用常规mod的模块和`common`模块,并分别引用`Frontend`与`Backend` 1. 实际写Patch方法的类继承`BaseTaiwuComp`,实现功能 1. 需要自动配置的属性或字段加上`AttrConfigItem`特性 1. 编写配置类,继承`BaseConfig`或其子类,配置需要管理的`Comp`和`Service` 1. 注册mod ```c# [PluginConfig("mod名称", "mod作者", "1.0.0")] public class PluginEntrance : TaiwuRemakePlugin { public override void Dispose() { } public override void Initialize() { PluginEntrance.AddPlugin(base.ModIdStr, base.PluginName, new PluginConfig()); } } ``` ### 日志 1. 所有的`Comp`都注入了`Log`对象,可以在非静态方法中使用 1. 静态方法需要使用的话可以在类中写上`private static ALogger Log;`,初始化`Comp`时也会自动注入 1. 日志的输出路径也为`~\Mod\TaiwuModFramework\Logs`,输出时会带上上面配置的mod名称,如: ```log 2023-03-31 11:30:08.2912|INFO |FwBackend|0000|配置日志工具,Name:太吾自用工具 LogPath:[D:\Program\Steam\steamapps\common\The Scroll Of Taiwu\Mod\TaiwuModFramework\Logs\Backend.log] 2023-03-31 11:30:08.2964|INFO |太吾自用工具|0000|激活组件补丁 TaiwuSmallTool.Comp.LogLevel ``` 1. 日志等级自动管理.默认日志等级为`INFO`,经过简单配置后就可以直接管理 ```C# // 配置类 public override List GetComps() { return new List() { new LogLevelComp() }; } ``` ```lua -- Config.lua DefaultSettings = { { SettingType = "Dropdown", Key = "loggerLevel", DisplayName = "日志等级", DefaultValue = "2", Options = {"TRACE","DEBUG","INFO","WARN","ERROR","FATAL","CLOSE"}, Description = "INFO: 常用的模式\nCLOSE: 关闭" } } ``` ### 前后端通信 1. 只能调用自身提供的服务和框架本身提供的服务(待完善) 1. 服务类继承自`AService`类,方法使用`AttrService("服务名")`来标注,示例如下 ```C# [AttrService("PrintAllItem")] public static List PrintAllItem(string modIdStr) { var list = ConfigManager.GetItemKeyByModId(modIdStr); foreach(var key in list) { Log.Info(key); } return list; } ``` 1. 在`FwDomain`类中集成了通信的`ReqClient`,调用时,通过`modIdStr`(每个comp都已注入自身的id)来区分服务提供方示例如下 ```C# public static void UpdateBackendConfigItem(string modIdStr, Type type, string configName, object value) { string key = ConfigItemInfo.CalcKey(type, configName); // 发送请求更新 FwDomain.ReqClient.Req(modIdStr, "UpdateConfigItem") .SetArgTypes(typeof(string), typeof(string), typeof(object)) .SetArgs(modIdStr, key, value).SendNotify(); // 发送通知,即不会有返回值 } public static List GetAllConfigItemKey(string modIdStr) { return (List)FwDomain.ReqClient.Req(ModIdStr, "PrintAllItem") .SetArgTypes(typeof(string)) .SetArgs(ModIdStr) .SendReq(out RespInfo resp); // 发送同步请求,该服务方法在后端日志中输出配置项,并以列表形式返回给前端 } public static void PrintAllConfigItemKey(string modIdStr) { FwDomain.ReqClient.Req(ModIdStr, "PrintAllItem") .SetArgTypes(typeof(string)) .SetArgs(ModIdStr) .SetReturnHandler(resp => Log.Info(string.Join("\n", (List)resp.data))) .SendReqAsync(); // 发送异步请求,该服务方法在后端日志中输出配置项,并以列表形式返回给前端,然后交给上面设置的处理方法 } ``` - 注意事项 1. 太吾的mod是先加载前端,后加载后端,所以在后未加载的时候同步调用后端,会直接导致主线程锁死 1. 内置的通信框架十分简陋,短时间大量调用可能会发生丢失消息的情况。 1. 同步调用请求时会阻塞当前线程,若发送的请求或返回的响应因为某些原因丢失,则可能直接导致线程一直阻塞 1. 推荐使用异步调用,或自己使用事件或信号量实现消息超时异常而非一直阻塞 ## 待开发 - 注: 本人代码苦手加懒狗一条,实际开发不知道猴年马月 1. 扫描mod文件夹,自动发现相关mod而不需要在编写注册mod的代码 1. 实现组件管理UI和日志UI,方便mod作者调试 1. 实现动态功能选单UI,便于随时快速的开启或关闭指定功能 1. 添加替换通信客户端的功能,可以使用各路大佬开发的IPC框架 1. 继承`AMsgClient`就可完成消息核心的替换 1. 也可以再继承`AReqClient`从头实现一个请求处理客户端,还需要同步调用阻塞,消息返回,服务调用等 1. 实现服务的代理,即在某端直接声明一个与服务端相同方法签名的空方法或抽象方法,通过动态生成请求。从而可以直接调用该空方法达到与手动请求一样的效果。 1. ···