• 注册
  • 语言&环境 语言&环境 关注:102 内容:131

    (原创)【4.0.13】NuGet依赖加载器-DependencyLoaderMod(4.0.13最后一版除必要恶性BUG修复外不更新)

  • 查看作者
  • 打赏作者
  • 当前位置: ODDBA社区 > 语言&环境 > 正文
  • 65
  • 语言&环境
  • 登堂入室

    NuGet依赖加载器

    适配版本:4.0.13(其余版本尚未检测兼容性且无检测计划)

    主要功能:

    DependencyLoaderMod 是一个 SPT 服务端模组的”依赖加载器”,解决了 SPT 4.0 服务端无法自动加载模组依赖 DLL(尤其是 NuGet 包)的限制。核心职责有两个:


    1. 运行时程序集解析(核心)

       – 在 [DependencyLoaderMod.cs]中注册全局 `AppDomain.AssemblyResolve` 事件,从各模组注册的 `dependencies/` 目录里加载依赖 DLL(含原生库 `e_sqlite3.dll` 这类通过 `NativeLibrary.SetDllImportResolver` 解析的文件)。

       – 因为 SPT 的 DI 扫描器会调用 `assembly.GetTypes()`,一旦某个模组类型引用了外部 DLL,就必须先能解析这些 DLL,否则启动即崩。这个 mod 就是提前挂好”钩子”。


    2. NuGet 自动回退下载

       – 当模组的 `dependencies/` 目录缺失或不全时,通过解析该模组的 `*.deps.json`([AutoResolveFromDepsJsonAsync]自动从国内镜像源(Azure 中国、华为云、腾讯云、清华 TUNA、博客园,最后官方源兜底)下载缺失的 NuGet 包并解压 DLL。

       – 配置在 [config.json]:`enableNugetFallback`、`nugetSource`(留空=自动检测)、`enableProgressBar`。


    提供的 API:


    所有 API 都在静态类 `DependencyLoaderMod.Services.DependencyLoadService`内


    | 方法 | 用途 |

    |—|—|

    | `AddResolveDirectory(path)` | 注册一个托管 DLL 解析目录,AssemblyResolve 时按注册顺序搜索 |

    | `AddNativeResolve(assemblyName, nativeDllName, nativeDllPath)` | 注册原生库映射,程序集 DllImport 时从指定路径加载 |

    | `HasRequiredDlls(path)` | 检查目录是否存在且含至少一个 `.dll` |

    | `AutoResolveFromDepsJsonAsync(depsJsonPath, targetDir, sourceUrl=null, showProgress=true)` | 按 deps.json 自动补齐缺失 NuGet 依赖 |

    | `DownloadPackageWithProgressAsync(pkg, ver, targetDir, sourceUrl, showProgress)` | 带进度条下载单个包 |

    | `DetectNuGetSourceAsync(configuredSource)` | 按区域检测最优 NuGet 源 |

    | `CacheDirectory`(属性) | 全局下载缓存目录,默认 `user/cache/DLLCache` |


    如何使用

    1. 编译期引用(不复制 DLL,运行时由 DependencyLoaderMod 提供):

    <ItemGroup>

      <Reference Include=”DependencyLoaderMod”>

        <HintPath>..\DependencyLoaderMod\obj\Release\DependencyLoaderMod.dll</HintPath>

        <Private>false</Private>

      </Reference>

    </ItemGroup>


    2. 自己的依赖 DLL 构建后移入 `dependencies/`,用 csproj 里的 `MoveDependencies` 目标实现,同时把 `*.deps.json` 保留在根目录供自动解析用。


    3. 在插件 `OnLoad()` 里注册依赖:

    var depsDir = Path.Combine(modDir, “dependencies”);

    // ① 缺失时从 NuGet 自动补齐(可先查缓存目录)

    if (!DependencyLoadService.HasRequiredDlls(depsDir))

    {

        var cacheDir = DependencyLoadService.CacheDirectory; // 默认 user/cache/DLLCache

        if (!DependencyLoadService.HasRequiredDlls(cacheDir))

        {

            await DependencyLoadService.AutoResolveFromDepsJsonAsync(

                Path.Combine(modDir, “MyMod.deps.json”), cacheDir);

        }

        // 从缓存复制到 dependencies/

    }


    // ② 注册托管 DLL 解析目录

    DependencyLoadService.AddResolveDirectory(depsDir);


    // ③ 注册原生库(如 SQLite)

    DependencyLoadService.AddNativeResolve(

        “SQLitePCLRaw.provider.e_sqlite3”, “e_sqlite3”,

        Path.Combine(modDir, “runtimes”, “win-x64”, “native”, “e_sqlite3.dll”));

    “`

    注意事项

    – 加载顺序:DependencyLoaderMod 必须在其他模组之前加载(其 `ModMetadata` 静态构造函数在 [DependencyLoaderMod.cs]就提前注册了 `AssemblyResolve`),插件入口标记为 `PreSptModLoader`。所以它是基础设施型模组,其他模组应在 `ModDependencies` 里声明依赖它。

    – `dependencies/` 目录:注册解析目录时若目录不存在会被跳过(只打 Warning),所以要先确保依赖就位再 `AddResolveDirectory`。

    – NuGet.Protocol.dll 必须留在 mod 根目录(不能进 `dependencies/`),因为 CLR 在静态构造函数运行前就需要加载它。

    我不觉得把这个贴子发在语言环境这个板块是一个好主意

    隐藏内容需要回复可以看见

    回复
    登堂入室

    666666

    回复
    登堂入室

    感谢分享

    回复
    圆转纯熟

    666

    回复
    渐入佳境

    666

    回复
    圆转纯熟

    1111111111

    回复
    初窥堂奥

    6666666666


    回复
    略有小成

    666666666666

    回复
    初窥堂奥

    [s-49]

    回复
    略有小成
    2021

    qwq

    回复
    登堂入室

    666

    回复

    请登录之后再进行评论

    登录
    语言&环境
  • 今日 0
  • 内容 131
  • 关注 102
  • 聊天
    关注 4

    【招募】GRIFFIN TKF项目开工 期待你的加入 || 你是否想加入格里芬书写自己与人形的故事

    捐助我们

    • 微信
    • 支付宝
  • 签到
  • 任务
  • 发布
  • 模式切换
  • 偏好设置
  • 帖子间隔 侧栏位置: