Skip to content

[Bug] ModelCapabilities 读路径 no-op、写路径抛异常,导致 Get() 成功后首次修改崩溃 #115

Closed as not planned

Description

@Twelve-eight

模块范围

Public API(公开 API)

严重程度

Major / regression(主要问题 / 回归)

发生了什么?

ModelCapabilities 的读路径和写路径对「persistence 尚未注册」这一前置条件处理不一致,导致 API 处于半可用状态。

读路径(CreateCollection,src/Models/Capabilities/ModelCapabilities.cs:90-97)把它当 no-op:

private static ModelCapabilitySet CreateCollection(AbstractModel model)
{
    var collection = new ModelCapabilitySet(model);
    collection.Load(null);
    if (IsInitialized)                    // ← 未初始化就跳过,不抛
        ModelSavedDataRuntime.GetBag(model).Set(SavedDataSlotKey, new ModelCapabilitySaveDocument(), false);
    return collection;
}

写路径(MarkSavedDataDirty,同文件 :72-79)直接抛:

internal static void MarkSavedDataDirty(AbstractModel model)
{
    if (!IsInitialized)
        throw new InvalidOperationException(
            "ModelCapabilities persistence has not been registered. ...");
    ModelSavedDataRuntime.GetBag(model).Set(SavedDataSlotKey, new ModelCapabilitySaveDocument());
}

后果:调用方可以在 mod 初始化早期成功 Get() 到 capability set,然后在第一次修改能力时崩溃。而 EnsureInitialized() 只在 ModContentRegistry 的 3 个注册点被调用,所以「注册前能不能改」这件事完全取决于调用时机。

复现步骤

  1. 在一个 mod 的早期初始化阶段(ModContentRegistry 注册 capability 之前)
  2. 对任意 AbstractModel 调用 ModelCapabilities.Get(model) → 成功返回
  3. 对该 set 做任意修改,触发 MarkSavedDataDirty → InvalidOperationException

期望行为

两条路径对同一前置条件行为一致。要么都抛(明确「必须先注册」),要么都 no-op(先允许内存态存在,注册后再补持久化)。

从 CreateCollection 的写法看,作者的意图似乎是后者。

实际行为

读成功、写崩溃。

建议修法

若采纳 no-op 语义:

internal static void MarkSavedDataDirty(AbstractModel model)
{
    if (!IsInitialized)
        return;                          // 与 CreateCollection 保持一致
    ModelSavedDataRuntime.GetBag(model).Set(SavedDataSlotKey, new ModelCapabilitySaveDocument());
}

版本

  • RitsuLib: v0.6.7(2332d9d0)

Activity

  1. added
    area/apiPublic API, contracts, or compatibility surface.
    priority/p1High priority regression or high-impact work.
    severity/majorSignificant bug with workaround or limited scope.
    on Oct 19, 2026
  2. Twelve-eight commented on Oct 19, 2026

    @Twelve-eight
    Author

    撤回:提交前未完成交叉验证,判断依据不充分。待核对完整证据链后如需要会重新提交。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiPublic API, contracts, or compatibility surface.priority/p1High priority regression or high-impact work.severity/majorSignificant bug with workaround or limited scope.status/needs-triageNeeds maintainer or analyzer triage.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions