菜单

Administrator
发布于 2026-05-14 / 23 阅读
0
0

Xeric Library 插件使用说明

编译插件

插件分为 开发版本 `XericLibrary` 和 用户版本 `XericLibrary-Publish` 。

编译工作

新版编译(>=0.3.6)

这一版中 插件部分移动到了 源码部分的外部,这样unity引用时就不会识别到vs工作目录了。

和之前一样,手动添加untiy引擎的引用,随后就可以开始编译了。

不需要每次拉取仓库后手动设置隐藏目录了,编译工作不会和unity工作有冲突,

旧版编译 (<0.3.6)

文件分为 源码部分 和 插件部分,打开 Developer/MainSolution/MainSolution.sln 项目,进入后需手动给所有项目添加unity引擎的引用,并手动在目录中隐藏源码部分的文件夹,随后就可以开始编译了。

注意将插件导入到unity之前,一定要手动在windwos文件管理器中将 Developer 目录隐藏,因为隐藏的文件夹不会被untiy识别,当然前提是你没有生成meta文件,不然也是白搭。

开发事项

  • 插件只能依赖untiyengine,不可以添加其他引用组件,这是为了全平台通用。如果要添加的话,最好添加一个源码编译源进来,然后在Mainsolution中按需部署。

  • 插件作为其他所有插件的前置依赖,不允许出现频繁的api变动,如果要修改,请将旧api改为指向新api的方式,然后标记为过时,丢到文件末尾,用带有过时标记的标注块框起来,直到数个版本后再移除

也可能永远都保留了,因为很多插件后续都不会再更新了,我需要确保这些插件在未来依然可以被使用。

当然,没发布的api就不用这么拘谨了,随便整吧。

  • 插件唯一的依赖是newTownSoft.Json,并且是il2cpp编译的版本(后续会计划将这个依赖排除)。

  • 插件不提供完整的解决方案,而是将功能拆分成更细枝末节可以复用的逻辑代码进行封装,比如一段公式,扩展方法等等。完整的解决方案通常会写成一个单独的插件。

  • 开发编译源文本之前确保工作目录至少有2gb空间(有点大哦)

使用插件

对于新版插件来说,开发版本的工程不能直接导入url到untiy中的,untiy会卡死,必须使用专门的publish仓库连接才可以。

或是手动将开发版本的仓库拉取到untiy的package目录下,手动引用Release/package到unity。

主程序 MainSolution

旧版本(<0.3.6)将主程序设定为启动项目,项目会自动执行编译,如果你正在使用旧版本的插件,可以跳过这一章。

新版本(>=0.3.6)中需要加入启动参数才能开启自动编译,项目默认的release发布目标会自动完成这件事。

这是只有开发版本才可以使用的功能,使用编译版本的插件可以跳过这一步。

启动编译

这是一段简单的编译命令,意思是自动识别目录,将程序编译到发布版本中,然后自动退出。

MainSolution.exe --build null

等待用户确认

加入stay命令,在编译结束后等待用户输入回车确认。

MainSolution.exe --build null --stay

其他命令也支持使用stay命令。

文件拼接

使用manPath指定文件夹路径;manFile指定筛选文件,比如.sql后缀;

MainSolution.exe --manPath "%foldpath%" --manFile ".sql" --manSum
  • manSum 首尾合并文件,文件块会用git合并标记框起来。

数据库统计

mansql命令,让程序读取这个文件,并统计数据库中有多少个库,每个库有多少个数据。

MainSolution.exe --manSQL "%fileName.sql%"

哈希计算

hash命令,后面跟任意文本,即可开始计算文本的哈希值

MainSolution.exe --hash "任意用于计算哈希的文本或路径"

如果传递的文本刚好能够指向一个文件,或文件夹,那么就会先开始扫描目录文件,计算他们的hash256值,如果是一个大文件,那么会先按体积拆分多线程任务,读取过程会吃满硬盘,并且最后会得出一个读取时间。由于这个多线程会完全吃满硬盘,拿来做读取测试也不错。

最后还会返回这段路径文本的hash值,包括 sha1,sha256,sha384, sha512,以及utf7,utf8等等编码情况下的hash。

核心组件 XericLibrary

在编辑器中可以看到有很多项目,但主要的项目是 XericLibrary 和 XericLibraryEditor。插件所有的功能都是写在这里面的。


MacroLibrary

MacroLibrary是日常开发中最常用的代码库部分,所有文件都是用 Macro+功能名称 作为文件名称,表示这个文件中只有与这个相关的功能。


MacroAsync [ ]

异步库

提供一些扩展方法来快速创建异步委托任务。


MacroBool [ ]

布尔扩展

提供一些链式语法来执行委托或流程


MacroCamera [⭐]

摄像机扩展

提供屏幕,摄像机相关api的重载,以及摄像机相关的计算方法。


MacroCecil [⭐⭐]

il指令分析库,基于Cecil。

不太推荐使用,因为体积较大,而且不建议在游戏中使用这种方法,默认部署不会提供这个库。


MacroColor [⭐]

颜色库

扩展了一些常见颜色类型的使用方法,并且提供了对tmp文本的颜色描述支持。


MacroCommandConsole [ ]

控制台

没写完,鸽了。


MacroConfig [ ]

配置库

uri配置
// 保存配置文件 (默认在streamingAsstes下)
MacroConfig.SaveUriConfigFile(null);
// 读取配置文件
MacroConfig.ReadUriConfigFile(null);
// 访问配置文件
MacroConfig.uriConfig;
键值配置
// 增加配置
MacroConfig.AddDynamicOK(key, value);
// 删除配置
MacroConfig.RemoveDynamicOK(key, value);
// 覆盖配置
MacroConfig.SetDynamicOK(key, value);
// 获取配置
MacroConfig.GetDynamicOK(key, out (key, value));


MacroConst (MacroMath) [ ]

常量库

提供了一些常见的常量,如进制单位转换。


MacroCurve [⭐⭐⭐⭐]

曲线库

提供了贝塞尔,卡特摩尔罗曲线计算方法,一维到三维的计算,一阶到任意阶都可以。


MacroDebug [⭐]

调试库

这里尝试自己注册了一个unity日志句柄,将untiy默认的捕获栈帧给去掉了,这样输出的内容中就不能跳转到文件也不能看到问题所在了,可以隐藏你的日志位置,模仿一些特殊的unity底层日志,另外这个日志默认是用富文本的,有颜色输出。

日常开发不建议这样做,徒增调试成本而已,除非你对这段代码非常有把握,且需要压缩日志体积,那么这个会很合适。


MacroDecorators [⭐]

装饰器库

提供装饰器用法,在一个用作装饰器的类上标记 MacroDecorators.XericDecorateAttribute,并实现 MacroDecorators.IDecorator。

使用时创建一个指向目标类型的 DecoratorsManager 管理器类,然后就可以通过 InvokeDecoratorMethod 方法调用另一端的方法了。

装饰器库允许定义分离的两个对象,如一个runtime域,一个editor域,runtime域不能访问editor,但是可以通过装饰器了解当前环境有没有注册到自己的editor部分,从而调用上面的方法。

// 定义一个指向自己的装饰器管理器
var dman = DecoratorsManager(this);
// 初始化管理器,找找当前程序集中所有指向自己的装饰器
dman.Initialize();
// 调用装饰器上的方法,如果装饰器不存在,方法会返回false。
dman.InvokeDecoratorMethod("methodName");


MacroEnum [⭐⭐]

枚举库

枚举封装器

枚举封装器提供了一些数学用法,比如查询最大的枚举值(maxEnum),最小的枚举值(minEnum),获取所有枚举的名称数组,枚举器里定义的枚举数量等等。

你可以将一个枚举经过封装转为一个可以被枚举遍历的对象,或是像操作数组一样操作一个枚举值。

// 使用泛型包装目标的枚举类型
MacroEnum<ETargetEnum>

枚举扩展
检查枚举值
  • 检查一个枚举值A是否包含至少一个枚举值B

// 定义枚举A
var enumA = myEnum.A | myEnum.C;

// 检查枚举是否不为空,返回真
enumA.EnumGreater();
// 检查枚举是否包含A,返回真
enumA.EnumGreater(myEnum.A);
// 检查枚举是否包含B,返回假
enumA.EnumGreater(myEnum.B);
// 检查枚举是否包含A或B,返回真
enumA.EnumGreater(myEnum.A, myEnum.B);

如果一个枚举值没有 [Flags] 标记不能直接或运算,那么可以使用逗号分割,这样枚举检查会逐个检查是否包含。

反之可以使用或运算符拼接枚举进行检查。

  • 检查一个枚举值A不包含枚举值B

// 定义枚举A
var enumA = myEnum.A | myEnum.C;
// 检查枚举是否为空
enumB.EnumLess();
// 检查枚举是否不包含A,返回假
enumB.EnumLess(myEnum.A);
// 检查枚举是否不包含B,返回真
enumB.EnumLess(myEnum.B);
// 检查枚举是否同事不包含A和B,返回假
enumB.EnumLess(myEnum.A, myEnum.B);

枚举计算
var enumA = myEnum.A | myEnum.C;
// 检查枚举值包含值A
MacroEnum.CheckEnum(ref enumA, myEnum.A);
// 添加枚举值B
MacroEnum.SetEnum(ref enumA, myEnum.B);
// 清除枚举值B
MacroEnum.ResetEnum(ref enumA, myEnum.B);

设置摄像机可见层
// 将物体设置到摄像机可见的层
gameobject.SetLayer(mainCamera);


MacroEventTrigger [⭐⭐⭐⭐]

触发器宏

触发器宏是对于ui系统的扩展,位置在Runtime/Helper/下

扩展 EventTrigger 用法

在场景中挂载 EventTrigger 组件后,常见的用法是在编辑器中进行挂载,但那样太难管理了,所以更建议使用代码方式控制流程,但是自行注册的话要创建一个entry,有点麻烦,所以这里提供一个更快捷的方法:

// 正常需要这样编写,创建一个entry并指定事件类型,然后添加到目录里。
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerClick;
entry.callback.AddListener((data) => {
  OnPointerClickDelegate(data);
});
trigger.triggers.Add(entry);

为了方便管理,简化代码,触发器宏里提供快捷的扩展函数可以一键调用:

// 简化后 
trigger.OnPointerClick().AddListener((e) => { /* todo event */ });

这样的调用方式更符合统一的api设计,同时不会占用多余的事件,所有同类型的事件都是放在一个entry里的,不存在创建多余entry的情况。

说到在编辑器中挂载事件委托,这个我深恶痛绝,同事就喜欢在编辑器里到处绑定事件,结果就是后期要甲方要改东西,结果接口是一个挂载脚本的对象放在场景中的,委托是绑在接口上的;模型文件要改,控制模型上脚本动画的事件也是委托,然后这个委托还不知道是谁做的,找也找不到。

为此我还特意写了一个插件,专门扫描场景里的引用,好歹是改完了,绘制引用线的功能并入 XericEditor插件中了,不是xericLibrary的Editor部分,是这个插件就叫XericEditor


MacroFile [⭐⭐⭐⭐⭐]

文件宏

提供跨平台文件处理句柄,多语言支持的序列化句柄。

下面是一个简单的读写示例,这会直接将字符串文本写入到文件中:

// 读取文件字符串
MacroFile.CrossPlatformFileHandle.ActiveFileHandle.ReadTextFromFile("filePath", out string content);
// 写入文件字符串
MacroFile.CrossPlatformFileHandle.ActiveFileHandle.WriteTextIntoFile("filePath", "content");

使用带有byte的方法可以在写入字节流:

MacroFile.CrossPlatformFileHandle.ActiveFileHandle.WriteByteIntoFile("filePath", new byte[]{1,2,3});

使用异步的方法读写文本或字节流:

MacroFile.CrossPlatformFileHandle.ActiveFileHandle.AsyncWriteTextIntoFile("filePath", "content", () => { },
    error => { });

可能不是所有平台都支持流送,所以只能一次性读写。

或者使用自定义的格式化组件来完成加密:

// 使用带有X标记的方法,并传入formatter即可。
MacroFile.CrossPlatformFileHandle.ActiveFileHandle.WriteXIntoFile("filePath", "content", MacroFile.XericSerializerFormatter.formatter);

// 也可以使用json序列化
MacroFile.JsonSerializerFormatter.formatter
// json带压缩
MacroFile.JsonSerializerFormatter.formatterWithZip
// json带超级简单加密
MacroFile.JsonSerializerFormatter.formatterWithCaesarEncrypt
// json带ase加密
MacroFile.JsonSerializerFormatter.formatterWithAESEncrypt
// 或者自定义,将这些东西混合在一起
new MacroFile.JsonSerializerFormatter(true, 39, "aseKey“);

MacroFile.CrossPlatformFileHandle.ActiveFileHandle 表示自动获取当前平台对应的文件操作句柄,随后可以从这个 Handle 中获取对应的文件读/写方法,或文件路径操作方法。


MacroForm [⭐⭐⭐⭐]

窗口库

目前专注于windows窗口api,基于 user32.dll,开放了一些用法可以快速控制窗口。


MacroInching []

缓动库

提供了一些步进扩展


MacroKey [⭐⭐⭐]

按键库

按键库不提供对按键输入的api,统一转为对bool的识别,你可以将任意类型转为bool值,然后对其进行扩展,实现基于时间戳的按键状态判断,按键库支持识别单击,单击释放,长按,长按释放,双击,双击释放,连击,拖拽。

拖拽功能支持使用时间触发,坐标触发的方式来识别拖拽。

按键状态识别
// <= 0.5.7 版本需要这样写,AsKfsStyle是将任意object转为配置表索引,必须和监测的按键对应。
_mouse0KeySheet = Input.GetMouseButton(0).InsertKeyStateCmet(0.AsKfsStyle());
// > 0.5.7 版本可以换到新的api上,可以只带一个函数完成识别。
_mouse0KeySheet = Input.GetMouseButton(0).InsertKeyStateByCrossMotionExtraTime(0);

调用各个 InsertKeyState 函数会返回一个 KeyFlippingStampSheet 表单,里面保存了这帧这个按键的所有状态:

// 当按键按下时
_mouse0KeySheet.IsPressed;
// 当按键释放时
_mouse0KeySheet.IsReleased;
// 当按键长按后释放时
_mouse0KeySheet.IsLongReleased;
// 当按键长按时(持续触发)
_mouse0KeySheet.IsLongPressedState;
// 当按键首次长按时
_mouse0KeySheet.IsFirstLongPressed;
// 当按键双击时
_mouse0KeySheet.IsDoubleClick;
// 按键从长按转为拖拽(需要执行的方法支持拖拽识别,否则无法触发)
_mouse0KeySheet.IsChangeDraggingFromLongPressed;
// 当按键开始长按时(需要执行的方法支持拖拽识别,否则无法触发)
_mouse0KeySheet.IsBeginDragging;
// 当按键拖拽时(需要执行的方法支持拖拽识别,否则无法触发)
_mouse0KeySheet.IsDragging;
// 当按键丢弃时(需要执行的方法支持拖拽识别,否则无法触发)
_mouse0KeySheet.IsDropping;

如果觉得使用if判断不优雅,可以使用对应事件的 OnKeyxxx 事件。

按键状态统计

当使用 var kfs = 0.AsKfsStyle() 这样的方法获取到 KfsStyle 后,可以直接在这里完成按键统计。

var kfs = 0.AsKfsStyle();
// 使用 codekeyState 方法登记按键状态。
kfs.CodeKeyState(true);
kfs.CodeKeyState(.5f);
// 获得按键在过去的一段时间内平均状态。
kfs.GetStateStatisticalProbability()
// 刷新按键状态 
kfs.RefreshKeyQueue();

按键状态统计步骤就是 1.登记,2.统计。

  • CodeKeyState 可以统计布尔值,或是浮点值,底层都是根据浮点值计算平均值的。

  • 按键历史最大值可以设置 MacroKey.RecodeKeyStateQueueLength 的大小,不过太大可能会导致在部分计算时时间变长。

  • 使用期间不需要手动额外在 InsertKeyState 方法后面再添加一道 CodeKeyState , InsertKeyState 里面已经自动完成了历史按键的登记。

  • 二次开发的时候注意 KeyFlippingStampSheet 里面也有一个按键状态表 keySheet, 但是和外部统计的表工作原理不一样,不可以混用或替换。

按键状态趋势

在按键统计的基础上添加了趋势预测

var kfs = 0.AsKfsStyle();
var timedTrendPredictor = new TimedTrendPredictor(MacroKey.RecodeKeyStateQueueLength);
// 填充离散值到预测表中
kfs.GetStateArithmeticTrend(timedTrendPredictor);
// 填充带有时间戳的值到预测表中
kfs.GetStateArithmeticTrendWithTimeFactorTv(timedTrendPredictor);

后续就像使用普通的预测器一样即可。


MacroMath [⭐⭐⭐⭐⭐]

数学库

MacroMath包含多个模块:(和文件名称对应)

  • 格式包裹器

  • 枚举库

  • 时间扩展

  • 常量库

  • 布尔扩展

  • 基本数学扩展

  • 单位转换库

  • 区域与语言文本库

  • 列表算法库 (MacroCollection)

  • PID扩展

  • 2d3d矩形计算扩展

基础数学功能

数学库里带有一些基本的数学计算

MacroMath.Clamp();
  • 可以将一个值a,钳制在大于等于min,小于等于max。支持使用vector2作为minmax范围。

M

随机

你可以直接通过 MacroMath.RandomFloat 获取一个随机数,并且里面会固定维护一个随机种子进行计算,这个随机数是基于System.Random 的。

MacroMath.RandomFloat();  // 获取最大最小值范围内的随机浮点数
MacroMath.RandomInt();  // 获取最大最小值范围内的随机整数
MacroMath.RandomBoolean();  // 获取在指定概率下的随机布尔值
MacroMath.RandomVector2();  // 获取在指定概率下的随机二维矢量
MacroMath.RandomVector3();  // 获取在指定概率下的随机三维矢量
MacroMath.RandomVector4();  // 获取在指定概率下的随机四维矢量
MacroMath.RandomMatrix4();  // 获取在指定概率下的随机矩阵

快捷哈希计算

将给定的以传字节码计算成hash字节流:

bytes.GetHash256(); // bytes 是任意长度的 byte[], 返回以传固定长度的 byte[]
// 另外可以使用以下方法计算其他哈希值
// GetHash384
// GetHash512
// GetHash1

文本与字节码转换

将字符串转为字节流,或是反过来转换。

("文本").ConvertByteArrayFormUTF8(); // 返回这段文本以utf8编码后的字节流 byte[] 
// 也可以这样获得这段文本的哈希值
("文本").ConvertByteArrayFormUTF8().GetHash256();


特殊数据


多项式缓冲预测

// 趋势预测器类
DiscreteTrendPredictor
// 基于时间戳的预测其
TimedTrendPredictor


卡尔曼滤波器

// 创建一个卡尔曼滤波器
var processor = new KalmanFilterProcessor(
    interval: TimeSpan.FromMilliseconds(16.6d),  // 100ms 采样间隔
    config: new KalmanFilterConfig
    {
        ProcessNoise = 0.01f,       // Q: 过程噪声
        MeasurementNoise = 2.0f,    // R: 测量噪声(假设传感器较嘈杂)
        InitialErrorCovariance = 1.0f,
    }
);
// 降噪
var result = processor.Denoise(rawdata);
// 预测
var prediction = processor.PredictNext(rawdata);
// 预测多帧
float[] futurePredictions = processor.PredictFuture(rawdata, 5);
// 降噪,预测多帧,预测下一帧
var (filtered, predictions, nextFrame) = processor.DenoiseAndPredict(rawdata);

// 输入一帧,处理一帧,预测一帧
float filtered_val = processor.ProcessFrame(raw);
float next_pred = processor.GetNextPrediction();

// 缓冲区
Console.WriteLine($"  缓冲区容量: {processor.Buffer.Capacity}");
Console.WriteLine($"  当前条目数: {processor.Buffer.Count}");
Console.WriteLine($"  采样间隔:   {processor.Buffer.Interval}");
Console.WriteLine($"  时间跨度:   {processor.Buffer.GetTimeSpan()}");
Console.WriteLine($"  最新条目:   {processor.Buffer.GetLatest()}");

图论框架

蓝图框架

blueprint 提供了基于图论的 untiy 可视化框架,并扩展出ugui渲染用法。
可以直接在canvas下右键 Xeric Library / BluePrint / xxx
默认会有多个蓝图模板,按需选择。

蓝图提供了节点,端口,连接线的连接结构。开放了工具,配置属性表的可扩展脚本。
所有功能都可以通过添加工具完成,包括默认蓝图 模板中的所有内容都是在蓝图框架下提供了节点渲染工具,连线渲染工具,背景板工具,用户输入工具。
蓝图本身提供了基于树形结构的检索,深度桶的排序结构,可以快速实现光标点击,可见性剔除,节点lod等工作。

已知问题

这里整理了一下使用时遇到的问题疑难解答。

json文件引用冲突

  1. 如果你使用的是旧版本(<0.3.6),检查一下项目中是否已经包含了json相关的dll文件,将插件中的删掉即可。确保项目中通过nuget,asstes包含,其他package的方式引用了json文件即可。

  2. 如果使用新版本(>=0.3.6)编译出来,检查一下目录中是否带有一个 “sponsor/newtonesoftjson” 文件,将这个文件删掉即可,这个是开发过程中使用的,不需要带到生产环境,unity也不需要它。

  3. 如果项目中没有包含json,却提示json冲突在插件中,到untiy项目目录中删掉Library文件夹,重新编译即可。

在webgl环境无法使用

  1. 确保使用的是il2cpp编译过的依赖项目,确保没有使用插件中aot部分代码,只要没有使用相关代码,程序就是安全的(一定程度上)。你也可以手动删除不需要的依赖项目,避免依赖冲突。

  2. webgl平台或其他一些安全为主的平台上无法使用生成树等动态类型的内容,注意减少使用反射宏;不要使用插件自带的cecil,不要使用动态类型空对象模板。

程序兼容性问题

如果遇到无法解决的问题,比如打包后无法运行,程序执行不符合预期。

先确认你使用了哪部分的库,通常这里只是进行了一些冗余逻辑的封装,并不涉及底层,很多时候并非插件兼容性问题。

使用这些库时需要注意兼容性:

  1. MacroFIle:文件宏只提供了部分平台,如果你使用了并不支持的平台,那么程序会退回到默认windows的api,导致程序错误。

  2. MacroCecil:指令分析库,尽量只在编辑器中使用这个库,或者你的平台就是windows平台,否则不建议包含这个库。

  3. MacroReflection:反射库,大部分情况下反射都可以正常工作,不过注意反射为了加速查找性能,会有大量的缓存,如果平台性能极差,或者有非常严厉的剪枝,那么不建议使用反射功能。

  4. MacroForm:窗口库,目前只支持windows端,也没有写多平台自动切换的功能,如果目标开发平台不是windows端则不要使用。


评论