Skip to content

refactor: 重构 ModSetup.cs#2877

Open
LuLu-ling wants to merge 4 commits into
devfrom
refactor/ModSetup
Open

refactor: 重构 ModSetup.cs#2877
LuLu-ling wants to merge 4 commits into
devfrom
refactor/ModSetup

Conversation

@LuLu-ling
Copy link
Copy Markdown
Member

@LuLu-ling LuLu-ling commented May 23, 2026

Summary by Sourcery

用显式的观察者和集中式的配置应用逻辑替代基于反射的 ModSetup 配置处理方式,从而将配置值应用到 UI。

新功能:

  • 引入静态辅助方法 ApplyAll,在启动期间以及设置变更时,将当前所有配置值应用到启动器 UI。

增强与改进:

  • 重构 ModSetup,为每个独立的配置项注册强类型的观察者,而不是使用反射和通用的配置作用域接口。
  • 将 ModSetup 的 UI 和系统更新方法转换为静态辅助方法,并从 ModBase 中移除全局 ModSetup 实例。
  • 简化隐藏功能的处理逻辑,通过观察 Hide 配置组并在单一位置刷新设置 UI,从而移除大量基于标志位的处理方法。
  • 通过在主窗口加载流程以及设置 UI 页面更新设置后调用 ModSetup.ApplyAll,实现 UI 初始化逻辑的集中管理。
Original summary in English

Summary by Sourcery

Replace reflection-based ModSetup config handling with explicit observers and centralized application of config values to the UI.

New Features:

  • Introduce a static ApplyAll helper to apply all current configuration values to the launcher UI during startup and when settings change.

Enhancements:

  • Refactor ModSetup to register strongly typed observers for individual config items instead of using reflection and a generic config scope interface.
  • Convert ModSetup UI and system update methods to static helpers and remove the global ModSetup instance from ModBase.
  • Simplify hidden-feature handling by observing the Hide config group and refreshing the setup UI in one place, removing many per-flag handler methods.
  • Centralize UI initialization by invoking ModSetup.ApplyAll from the main window load sequence and after updating settings in the setup UI page.

@pcl-ce-automation pcl-ce-automation Bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: L PR 大小评估:大型 labels May 23, 2026
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 23, 2026

Reviewer's Guide

将 ModSetup 从基于反射的实例级配置观察器重构为显式的、静态的 config-to-UI 绑定,并通过单一的 ApplyAll 初始化器完成启动初始化,从而简化配置变更处理与启动流程。

静态 config-to-UI 绑定与 ApplyAll 初始化的序列图

sequenceDiagram
    actor User
    participant FormMain
    participant PageSetupUI
    participant Config
    participant ConfigObserver
    participant ModSetup

    rect rgb(230,230,250)
    note over FormMain,ModSetup: 启动初始化
    FormMain->>ModSetup: ModSetup() constructor
    ModSetup->>Config: Config.Preference.*.Observe(new ConfigObserver(...))
    Config-->>ConfigObserver: register observer callbacks

    FormMain->>ModSetup: ApplyAll()
    ModSetup->>ModSetup: LaunchRamType(Config.Launch.MemoryAllocationMode)
    ModSetup->>ModSetup: UiLauncherTheme(Config.Preference.Theme.ThemeSelected)
    ModSetup->>ModSetup: UiFont(Config.Preference.Font)
    ModSetup->>ModSetup: SystemHttpProxy(Config.Network.HttpProxy.CustomAddress)
    ModSetup->>PageSetupUI: HiddenRefresh()
    end

    rect rgb(230,255,230)
    note over User,ConfigObserver: 运行时配置变更传播
    User->>PageSetupUI: interact controls
    PageSetupUI->>PageSetupUI: SetByTag(tag, value)
    PageSetupUI->>Config: update Config.Preference.*
    Config-->>ConfigObserver: ConfigEvent.Changed
    ConfigObserver->>ModSetup: UiFont((string)(e.Value ?? ""))
    ModSetup->>PageSetupUI: HiddenRefresh() (via ApplyAll or Hide observer)
    end

    rect rgb(255,250,230)
    note over PageSetupUI,ModSetup: UI 变更后的 ApplyAll
    PageSetupUI->>ModSetup: ApplyAll()
    ModSetup->>ModSetup: UiBlur(Config.Preference.Blur.IsEnabled)
    ModSetup->>ModSetup: UiBlurValue(Config.Preference.Blur.Radius)
    ModSetup->>ModSetup: UiLogoType((int)Config.Preference.WindowTitleType)
    end
Loading

File-Level Changes

Change Details Files
将 ModSetup 中基于反射的动态配置分发替换为显式的观察者注册和静态 ApplyAll 初始化器。
  • 在 ModSetup 中移除 IConfigScope 实现、动态方法缓存以及基于反射的 InvokeEventMethod/OnConfigChanged 调用链
  • 在 ModSetup 构造函数中,为所有相关配置项显式注册 Config 观察者,并让每个观察者直接调用对应的处理方法
  • 新增静态 ApplyAll 方法,在启动初始化时读取当前配置值,并通过这些处理方法将其应用到 UI/系统
Plain Craft Launcher 2/Modules/Base/ModSetup.cs
将配置处理方法转换为静态辅助方法,并添加一些安全检查。
  • 将大部分处理方法(LaunchRamType、ToolDownloadThread/Speed、各类 Ui* 方法,以及 System* 和 Version* 方法)从实例方法改为静态方法,使其在无 ModSetup 实例时也能调用
  • 在 UiBlur 中对 ModMain.FrmSetupUI 添加空值保护,以避免在设置界面尚未创建时应用模糊设置导致空引用
  • 移除大量仅调用 PageSetupUI.HiddenRefresh 的简单 UiHidden* 方法,改为使用单一的 Hide 分组观察者,并在 ApplyAll 中显式调用 HiddenRefresh
Plain Craft Launcher 2/Modules/Base/ModSetup.cs
将启动时的配置初始化移动到 ModSetup.ApplyAll 中,并移除全局 ModSetup 实例。
  • 移除 ModBase.Setup 静态字段及其实例化逻辑,因为 ModSetup 不再需要作为全局对象持有
  • 在 FormMain_Loaded 中,移除手动读取配置并直接调用 UiLogo* 和 HiddenRefresh 的代码,改为在 ThemeManager.ThemeRefresh 之后调用一次 ModSetup.ApplyAll
  • 在 PageSetupUI.Reload 中,不再直接调用 UiCustomType,而是在 SetByTag 更新配置后调用一次 ModSetup.ApplyAll,以批量重新应用当前设置
Plain Craft Launcher 2/Modules/Base/ModBase.cs
Plain Craft Launcher 2/FormMain.xaml.cs
Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs

Tips and commands

Interacting with Sourcery

  • 触发新的审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在审查评论下回复,要求 Sourcery 以此创建一个 issue。你也可以直接回复 @sourcery-ai issue 来从该评论生成 issue。
  • 生成 pull request 标题: 在 pull request 标题任意位置写上 @sourcery-ai,即可随时生成标题。也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文任意位置写上 @sourcery-ai summary,即可在对应位置生成 PR 摘要。也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审查者指南: 在 pull request 中评论 @sourcery-ai guide,即可随时(重新)生成审查者指南。
  • 一次性解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,即可标记所有 Sourcery 评论为已解决。适用于你已经处理完所有评论且不再需要看到它们的情况。
  • 清除所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,即可清除所有现有的 Sourcery 审查。适合希望从头开始新的审查流程的场景——别忘了再评论 @sourcery-ai review 来触发新的审查!

Customizing Your Experience

打开你的 dashboard 以:

  • 启用或禁用审查功能,例如 Sourcery 自动生成的 pull request 摘要、审查者指南等。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查设置。

Getting Help

Original review guide in English

Reviewer's Guide

Refactors ModSetup from a reflection-based, instance-level config observer into an explicit, static config-to-UI wiring with a single ApplyAll initializer, simplifying configuration change handling and startup initialization.

Sequence diagram for static config-to-UI wiring and ApplyAll initialization

sequenceDiagram
    actor User
    participant FormMain
    participant PageSetupUI
    participant Config
    participant ConfigObserver
    participant ModSetup

    rect rgb(230,230,250)
    note over FormMain,ModSetup: Startup initialization
    FormMain->>ModSetup: ModSetup() constructor
    ModSetup->>Config: Config.Preference.*.Observe(new ConfigObserver(...))
    Config-->>ConfigObserver: register observer callbacks

    FormMain->>ModSetup: ApplyAll()
    ModSetup->>ModSetup: LaunchRamType(Config.Launch.MemoryAllocationMode)
    ModSetup->>ModSetup: UiLauncherTheme(Config.Preference.Theme.ThemeSelected)
    ModSetup->>ModSetup: UiFont(Config.Preference.Font)
    ModSetup->>ModSetup: SystemHttpProxy(Config.Network.HttpProxy.CustomAddress)
    ModSetup->>PageSetupUI: HiddenRefresh()
    end

    rect rgb(230,255,230)
    note over User,ConfigObserver: Runtime config change propagation
    User->>PageSetupUI: interact controls
    PageSetupUI->>PageSetupUI: SetByTag(tag, value)
    PageSetupUI->>Config: update Config.Preference.*
    Config-->>ConfigObserver: ConfigEvent.Changed
    ConfigObserver->>ModSetup: UiFont((string)(e.Value ?? ""))
    ModSetup->>PageSetupUI: HiddenRefresh() (via ApplyAll or Hide observer)
    end

    rect rgb(255,250,230)
    note over PageSetupUI,ModSetup: ApplyAll after UI changes
    PageSetupUI->>ModSetup: ApplyAll()
    ModSetup->>ModSetup: UiBlur(Config.Preference.Blur.IsEnabled)
    ModSetup->>ModSetup: UiBlurValue(Config.Preference.Blur.Radius)
    ModSetup->>ModSetup: UiLogoType((int)Config.Preference.WindowTitleType)
    end
Loading

File-Level Changes

Change Details Files
Replace reflection-based dynamic config dispatch in ModSetup with explicit observer registrations and a static ApplyAll initializer.
  • Remove IConfigScope implementation, dynamic method cache, and reflection-based InvokeEventMethod/OnConfigChanged pipeline in ModSetup
  • In ModSetup constructor, explicitly register Config observers for all relevant config entries, each calling the corresponding handler method directly
  • Introduce static ApplyAll method that reads current config values and applies them to UI/system via the handler methods for startup initialization
Plain Craft Launcher 2/Modules/Base/ModSetup.cs
Convert config handler methods to static helpers and add minor safety checks.
  • Change most handler methods (LaunchRamType, ToolDownloadThread/Speed, various Ui* methods, System* and Version* methods) from instance to static methods so they can be called without a ModSetup instance
  • Add null-guard for ModMain.FrmSetupUI in UiBlur to avoid null reference when blur settings are applied before the setup UI exists
  • Remove many trivial UiHidden* methods that only called PageSetupUI.HiddenRefresh, replacing them with a single Hide group observer and explicit HiddenRefresh calls in ApplyAll
Plain Craft Launcher 2/Modules/Base/ModSetup.cs
Move config initialization at startup to ModSetup.ApplyAll and remove the global ModSetup instance.
  • Remove ModBase.Setup static field and its instantiation, as ModSetup no longer needs to be held as a global object
  • In FormMain_Loaded, remove manual config reads and direct UiLogo* and HiddenRefresh calls and replace them with a single ModSetup.ApplyAll invocation after ThemeManager.ThemeRefresh
  • In PageSetupUI.Reload, stop calling UiCustomType directly and instead call ModSetup.ApplyAll once after SetByTag updates config so current settings are re-applied in bulk
Plain Craft Launcher 2/Modules/Base/ModBase.cs
Plain Craft Launcher 2/FormMain.xaml.cs
Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出一些高层面的反馈:

  • 在移除了 ModBase.Setup 之后,ModSetup 构造函数看起来不再在任何地方被显式实例化,因此新的 Config.*.Observe(...) 注册可能永远不会被执行;建议将这些注册显式化(例如提供一个从启动代码中调用的静态初始化方法),或者重新引入一个明确会被使用的实例。
  • 现在在 PageSetupUI 中,每次调用 SetByTag 都会调用一次 ModSetup.ApplyAll(),这会为了单个变更重新应用所有由配置驱动的 UI 更新;建议只更新受影响的设置,以避免重复工作以及可能的 UI 闪烁/性能问题。
  • 大多数 ModSetup 方法已经被改为静态,但仍然依赖全局 UI 状态,比如 ModMain.FrmMain/ModMain.FrmSetupUI;更干净、更安全的做法是要么在使用前始终进行空值检查,要么将这部分逻辑从静态/全局状态中解耦,以提升健壮性和可测试性。
AI 代理提示
Please address the comments from this code review:

## Overall Comments
- After removing `ModBase.Setup`, the `ModSetup` constructor is no longer obviously instantiated anywhere, so the new `Config.*.Observe(...)` registrations may never run; consider making the registration explicit (e.g., a static initialization method that is called from startup) or re-introducing a clearly used instance.
- `ModSetup.ApplyAll()` is now called on every `SetByTag` in `PageSetupUI`, which re-applies all configuration-driven UI updates for a single change; consider updating only the affected setting to avoid redundant work and potential UI flicker/performance issues.
- Most `ModSetup` methods have been made static but still depend on global UI state like `ModMain.FrmMain`/`ModMain.FrmSetupUI`; it would be cleaner and safer to either consistently guard against null before use or decouple this logic from static/global state to improve robustness and testability.

Sourcery 对开源项目是免费的——如果你觉得我们的评论有帮助,请考虑分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据这些反馈改进为你提供的评审。
Original comment in English

Hey - I've left some high level feedback:

  • After removing ModBase.Setup, the ModSetup constructor is no longer obviously instantiated anywhere, so the new Config.*.Observe(...) registrations may never run; consider making the registration explicit (e.g., a static initialization method that is called from startup) or re-introducing a clearly used instance.
  • ModSetup.ApplyAll() is now called on every SetByTag in PageSetupUI, which re-applies all configuration-driven UI updates for a single change; consider updating only the affected setting to avoid redundant work and potential UI flicker/performance issues.
  • Most ModSetup methods have been made static but still depend on global UI state like ModMain.FrmMain/ModMain.FrmSetupUI; it would be cleaner and safer to either consistently guard against null before use or decouple this logic from static/global state to improve robustness and testability.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- After removing `ModBase.Setup`, the `ModSetup` constructor is no longer obviously instantiated anywhere, so the new `Config.*.Observe(...)` registrations may never run; consider making the registration explicit (e.g., a static initialization method that is called from startup) or re-introducing a clearly used instance.
- `ModSetup.ApplyAll()` is now called on every `SetByTag` in `PageSetupUI`, which re-applies all configuration-driven UI updates for a single change; consider updating only the affected setting to avoid redundant work and potential UI flicker/performance issues.
- Most `ModSetup` methods have been made static but still depend on global UI state like `ModMain.FrmMain`/`ModMain.FrmSetupUI`; it would be cleaner and safer to either consistently guard against null before use or decouple this logic from static/global state to improve robustness and testability.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@LuLu-ling LuLu-ling requested a review from a team May 23, 2026 06:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L PR 大小评估:大型 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant