feat(mod): 新增模组关系页,补全内嵌检测与依赖解析 - #3441
Conversation
Reviewer's Guide添加一个 Jar-in-Jar(嵌入模组)依赖分析系统,包含缓存、UI 和崩溃报告集成,并在模组启用/禁用/删除操作中基于嵌入依赖实现级联行为。 基于 Jar-in-Jar 依赖的模组启用/禁用/删除级联行为序列图sequenceDiagram
actor User
participant PageInstanceCompResource
participant ModJarInJarIndex
User->>PageInstanceCompResource: EDMods(modList, isEnable=false)
activate PageInstanceCompResource
PageInstanceCompResource->>PageInstanceCompResource: _JijFindAffected(list)
PageInstanceCompResource->>ModJarInJarIndex: new ModJarInJarIndex(allMods, mcVersion)
PageInstanceCompResource->>ModJarInJarIndex: FindAffected(targets)
ModJarInJarIndex-->>PageInstanceCompResource: affectedMods
PageInstanceCompResource->>PageInstanceCompResource: _AskJijCascade(affectedMods, false)
PageInstanceCompResource-->>PageInstanceCompResource: choice
alt choice == 1 (cascade disable)
PageInstanceCompResource->>PageInstanceCompResource: EDModsCore(list ∪ affectedMods, false)
else choice == 0 (only selected)
PageInstanceCompResource->>PageInstanceCompResource: EDModsCore(list, false)
end
deactivate PageInstanceCompResource
User->>PageInstanceCompResource: DeleteMods(modList)
activate PageInstanceCompResource
PageInstanceCompResource->>PageInstanceCompResource: _JijFindAffected(list)
PageInstanceCompResource->>ModJarInJarIndex: FindAffected(targets)
ModJarInJarIndex-->>PageInstanceCompResource: affectedMods
PageInstanceCompResource->>PageInstanceCompResource: _AskJijCascade(affectedMods, true)
PageInstanceCompResource-->>PageInstanceCompResource: choice
alt choice == 1 (disable affected)
PageInstanceCompResource->>PageInstanceCompResource: EDModsCore(affectedMods, false)
PageInstanceCompResource->>PageInstanceCompResource: DeleteModsCore(list)
else choice == 2 (delete affected)
PageInstanceCompResource->>PageInstanceCompResource: DeleteModsCore(list ∪ affectedMods)
else choice == 0 (only selected)
PageInstanceCompResource->>PageInstanceCompResource: DeleteModsCore(list)
end
deactivate PageInstanceCompResource
模组加载与崩溃报告导出过程中 Jar-in-Jar 缓存使用的序列图sequenceDiagram
participant ModLocalComp
participant ModJarInJar
participant ModJarInJarCache
participant CrashReportExporter
ModLocalComp->>ModJarInJarCache: UseInstance(instancePath)
ModLocalComp->>ModJarInJar: ResolveCached(path, jar)
ModJarInJar->>ModJarInJarCache: TryGet(path, lastModified, size)
alt cache hit
ModJarInJarCache-->>ModJarInJar: List EmbeddedModNode
ModJarInJar->>ModLocalComp: _FromNodes(nodes, parentPath)
else cache miss
ModJarInJarCache-->>ModJarInJar: null
ModJarInJar->>ModJarInJar: Resolve(parentPath, jar)
ModJarInJar-->>ModLocalComp: EmbeddedMods
ModJarInJar->>ModJarInJarCache: Set(path, lastModified, size, _ToNodes(EmbeddedMods))
end
CrashReportExporter->>ModJarInJarCache: UseInstance(instance.PathInstance)
CrashReportExporter->>CrashReportExporter: _WriteModInfo(reportFolder, instance)
CrashReportExporter->>ModJarInJarCache: Flush()
文件级改动
可能关联的问题
Tips and commandsInteracting with Sourcery
Customizing Your Experience访问你的 dashboard 以:
Getting HelpOriginal review guide in EnglishReviewer's GuideAdds a Jar-in-Jar (embedded mod) dependency analysis system with caching, UI, and crash report integration, plus cascaded enable/disable/delete behavior for mods based on embedded dependencies. Sequence diagram for cascaded mod enable/disable/delete based on Jar-in-Jar dependenciessequenceDiagram
actor User
participant PageInstanceCompResource
participant ModJarInJarIndex
User->>PageInstanceCompResource: EDMods(modList, isEnable=false)
activate PageInstanceCompResource
PageInstanceCompResource->>PageInstanceCompResource: _JijFindAffected(list)
PageInstanceCompResource->>ModJarInJarIndex: new ModJarInJarIndex(allMods, mcVersion)
PageInstanceCompResource->>ModJarInJarIndex: FindAffected(targets)
ModJarInJarIndex-->>PageInstanceCompResource: affectedMods
PageInstanceCompResource->>PageInstanceCompResource: _AskJijCascade(affectedMods, false)
PageInstanceCompResource-->>PageInstanceCompResource: choice
alt choice == 1 (cascade disable)
PageInstanceCompResource->>PageInstanceCompResource: EDModsCore(list ∪ affectedMods, false)
else choice == 0 (only selected)
PageInstanceCompResource->>PageInstanceCompResource: EDModsCore(list, false)
end
deactivate PageInstanceCompResource
User->>PageInstanceCompResource: DeleteMods(modList)
activate PageInstanceCompResource
PageInstanceCompResource->>PageInstanceCompResource: _JijFindAffected(list)
PageInstanceCompResource->>ModJarInJarIndex: FindAffected(targets)
ModJarInJarIndex-->>PageInstanceCompResource: affectedMods
PageInstanceCompResource->>PageInstanceCompResource: _AskJijCascade(affectedMods, true)
PageInstanceCompResource-->>PageInstanceCompResource: choice
alt choice == 1 (disable affected)
PageInstanceCompResource->>PageInstanceCompResource: EDModsCore(affectedMods, false)
PageInstanceCompResource->>PageInstanceCompResource: DeleteModsCore(list)
else choice == 2 (delete affected)
PageInstanceCompResource->>PageInstanceCompResource: DeleteModsCore(list ∪ affectedMods)
else choice == 0 (only selected)
PageInstanceCompResource->>PageInstanceCompResource: DeleteModsCore(list)
end
deactivate PageInstanceCompResource
Sequence diagram for Jar-in-Jar cache usage during mod loading and crash report exportsequenceDiagram
participant ModLocalComp
participant ModJarInJar
participant ModJarInJarCache
participant CrashReportExporter
ModLocalComp->>ModJarInJarCache: UseInstance(instancePath)
ModLocalComp->>ModJarInJar: ResolveCached(path, jar)
ModJarInJar->>ModJarInJarCache: TryGet(path, lastModified, size)
alt cache hit
ModJarInJarCache-->>ModJarInJar: List EmbeddedModNode
ModJarInJar->>ModLocalComp: _FromNodes(nodes, parentPath)
else cache miss
ModJarInJarCache-->>ModJarInJar: null
ModJarInJar->>ModJarInJar: Resolve(parentPath, jar)
ModJarInJar-->>ModLocalComp: EmbeddedMods
ModJarInJar->>ModJarInJarCache: Set(path, lastModified, size, _ToNodes(EmbeddedMods))
end
CrashReportExporter->>ModJarInJarCache: UseInstance(instance.PathInstance)
CrashReportExporter->>CrashReportExporter: _WriteModInfo(reportFolder, instance)
CrashReportExporter->>ModJarInJarCache: Flush()
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - 我已经给出了一些高层次的反馈:
- 平台/加载器的依赖 ID 集合(ModLocalComp 中的
_IgnoredDepIds和 ModJarInJarIndex 中的_platformIds)目前是重复且略有差异的;建议将这些 ID 集中到一个共享的辅助工具中,以避免未来出现不一致。 PageInstanceCompJarInJar.RefreshList假设ModLocalComp.compResourceListLoader.output已经被填充;如果该页面可能在加载器完成之前就被打开,请添加空/空集合检查,或挂钩到加载器生命周期中,以避免潜在的空引用或过期数据。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The platform/loader dependency ID sets (_IgnoredDepIds in ModLocalComp and _platformIds in ModJarInJarIndex) are duplicated and slightly divergent; consider centralizing these IDs into a single shared helper to avoid future inconsistencies.
- PageInstanceCompJarInJar.RefreshList assumes ModLocalComp.compResourceListLoader.output is populated; if this page can be opened before the loader has finished, add a null/empty check or hook into the loader lifecycle to avoid potential null references or stale data.帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've left some high level feedback:
- The platform/loader dependency ID sets (_IgnoredDepIds in ModLocalComp and _platformIds in ModJarInJarIndex) are duplicated and slightly divergent; consider centralizing these IDs into a single shared helper to avoid future inconsistencies.
- PageInstanceCompJarInJar.RefreshList assumes ModLocalComp.compResourceListLoader.output is populated; if this page can be opened before the loader has finished, add a null/empty check or hook into the loader lifecycle to avoid potential null references or stale data.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The platform/loader dependency ID sets (_IgnoredDepIds in ModLocalComp and _platformIds in ModJarInJarIndex) are duplicated and slightly divergent; consider centralizing these IDs into a single shared helper to avoid future inconsistencies.
- PageInstanceCompJarInJar.RefreshList assumes ModLocalComp.compResourceListLoader.output is populated; if this page can be opened before the loader has finished, add a null/empty check or hook into the loader lifecycle to avoid potential null references or stale data.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 63c10f465e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05ed984f7c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 473f259986
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8d68a6393a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb229015d7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15c15f033a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10f669e338
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c13a6af279
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b197eeab80
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| { | ||
| // 加载器/运行时平台伪 id:不作为真实 Mod 依赖收录。不含 minecraft(其版本要求另有用途) | ||
| private static readonly HashSet<string> _loaderIds = new(StringComparer.OrdinalIgnoreCase) | ||
| { "forge", "neoforge", "fabric", "fabricloader", "quilt", "quilt_loader", "java", "mcp" }; |
There was a problem hiding this comment.
Do not classify Fabric API as a loader
When a Fabric mod declares depends.fabric (used by legacy Fabric API distributions; the loader dependency is fabricloader), this new platform-id set causes AddDependency to discard the dependency and IsPlatform to ignore it. Instances missing Fabric API will therefore show no missing-prerequisite warning in the relation page/crash export, and disabling or removing the Fabric API provider will not cascade to mods that require it; keep fabricloader as the pseudo loader id and treat fabric as a real mod id.
Useful? React with 👍 / 👎.
| var ver = McConstraintMatcher.StripV(providerVersion.Trim()); | ||
| if (ver.Length == 0 || !char.IsDigit(ver[0])) return true; | ||
| if (McConstraintMatcher.Satisfies(dep.Raw, dep.Loader, ver)) return true; | ||
| return !McConstraintMatcher.HasComparableLowerBound(dep.Raw); |
There was a problem hiding this comment.
Reject providers above Maven upper bounds
For Forge/NeoForge dependencies with an upper-bound-only Maven range such as (,2.0), an installed provider at 3.0 fails Satisfies but then this fallback returns true because HasComparableLowerBound is false. That reports the incompatible provider as installed and suppresses both missing/version warnings and delete/disable cascade detection; only fail open when the constraint has no comparable bounds, not when a comparable upper bound was violated.
Useful? React with 👍 / 👎.
修复之前在 #3378 中暴露出的问题并基于此为PCL-CE增加模组关系自动分析能力、模组调整时支持级联功能。
TODO:
resolves #3439
resolves #3479
本PR移植自HMCL #6230 ,由Opus4.8对代码进行了审查。
Summary by Sourcery
添加 Jar-in-Jar 模组关系分析、缓存及管理界面,并将具备依赖感知能力的级联处理集成到模组启用/禁用和删除操作中。
新功能:
错误修复:
增强改进:
Original summary in English
Summary by Sourcery
Add Jar-in-Jar mod relationship analysis, caching, and management UI, and integrate dependency-aware cascade handling into mod enable/disable and delete operations.
New Features:
Bug Fixes:
Enhancements: