Skip to content

RimWorld 1.7 (Waylith) support, refactor, CI - #7

Merged
zzzz465 merged 11 commits into
masterfrom
feature/1.7-waylith
Oct 13, 2026
Merged

zzzz465 merged 11 commits into
masterfrom
feature/1.7-waylith

Conversation

@zzzz465

@zzzz465 zzzz465 commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

RimWorld 1.7 moves the game from Unity to Ludeon's Waylith engine (unstable branch, 2026-10-12). This PR adds a native 1.7 build, rewrites the 2019-era code, and adds CI.

1.7 / Waylith

  • Waylith runs a modified .NET 10 CLR and redirects UnityEngine* to UnityStubs.dll, which implements IMGUI on the new backend. Every game API this mod uses (and the bodies of the patched methods) is unchanged from 1.6.
  • New net10.0 target compiled against the 1.7 Assembly-CSharp.dll + UnityStubs.dll and Harmony 3.0 → 1.7/Assemblies; net472 target for 1.6 → 1.6/Assemblies.
  • Fix: LoadFolders.xml had no v1.6 entry, so RimWorld 1.6 loaded the 1.5 DLL; added v1.6 and v1.7.

Refactor

  • SDK-style multi-target project, nullable, warnings as errors; Core (engine-independent) / Patches / UI split; dead code removed.
  • Mod versions are now written by the scribe while the meta header is written (transpiler) and read from the already-parsed header. Previously every save was re-loaded and re-written with XDocument, and opening the mismatch window re-wrote the selected save. XML layout unchanged, old saves still work.
  • Versions also read from About.xml <modVersion> (workshop request).

Alignment and window

  • LCS alignment by package id (was a greedy pass by display name); reordered mods shown as "load order changed" instead of removed + added.
  • Summary/legend, search, toggles for unchanged mods and order changes (workshop requests), font-based row heights (the old fixed 34px threw and blanked the window), tooltips, "Save mod list" button, confirmation before restarting with the save's mod list. New strings translated (en/ko/ja/zh-CN).

CI / releases

  • Assemblies are built locally (the 1.7 target needs game files) and committed; CI never downloads the game.
  • release.yml, on a v* tag: checks the tag against About/Manifest.xml and the csproj version, checks the committed 1.6/1.7 assemblies, validates XML, runs the tests, zips the mod files, creates a GitHub release, then updates Steam Workshop item 1872244972 with steamcmd (workshop_build_item, content + change note only) using the cached login in STEAM_USERNAME / STEAM_CONFIG_VDF. Suffixed tags become GitHub pre-releases and skip the Workshop.
  • Running the workflow manually only checks that the Steam login still works.
  • AssemblyInformationalVersion no longer embeds the commit hash, so rebuilding does not change the committed DLLs.

Test plan

  • dotnet build for net472 (1.6) and net10.0 (1.7) with warnings as errors
  • 20 unit tests: LCS optimality vs. a textbook LCS on 6000 random lists, never fewer matches than the old algorithm, greedy fallback equal to the old code, Harmony 3.0 transpiler insertion inside a finally block on CoreCLR
  • In-game on 1.7.4976 (automated, temporary test mod, log-verified): saving writes <meta><modMetaDatas> (Harmony 3.0.0.0, this mod 1.2.0; unknown versions omitted), reading the header back returns the same versions, a 1.6 save with 219 mods opens the window without loading it (221 rows: 212 removed, 7 unchanged, 2 added), filters work, no exceptions while drawing
  • Visual check on 1.7 with computer use: layout, legend, search, both toggles, scrolling, hover tooltip, Esc, "Load anyway" (loads the save and closes the window), version-changed row. Synthetic clicks only register when held, and the window's X and the main-menu buttons did not respond to them at all (vanilla buttons too), so those were driven by a test-only helper.
  • Run on 1.6
  • After merge: manual run of release (Steam login check)
  • First tagged release (v1.2.0): GitHub release + Workshop update

🤖 Generated with Claude Code

zzzz465 and others added 11 commits October 13, 2026 11:19
LoadFolders.xml only defined v1.1-v1.5, so RimWorld fell back to the
highest defined version (1.5) and the assembly in 1.6/Assemblies was
never loaded. Add the v1.6 entry and list 1.7 in supportedVersions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace the 2019 VS project (hard-coded Steam paths, Harmony 2.0) with
  an SDK-style multi-target project:
  - net472  -> RimWorld 1.6 (Unity/Mono), references Krafs.Rimworld.Ref
    1.6.4871 and Lib.Harmony.Ref 2.4.3, output 1.6/Assemblies
  - net10.0 -> RimWorld 1.7 (Waylith/CoreCLR), references the game's
    Assembly-CSharp.dll and UnityStubs.dll plus Lib.Harmony.Ref
    3.0.0-rc.2, output 1.7/Assemblies
- The 1.7 target needs a local game copy (RimWorld17Dir, auto-detected
  from the Steam install or set in Source/Local.props) because no 1.7
  reference package exists yet.
- Add LoadFolders entry for 1.7.
- Add a GitHub Actions workflow that validates mod XML and builds the
  1.6 target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Structure
- Core/: engine-independent ModEntry, AlignedRow/RowState and
  ModListAligner, testable without the game.
- Patches/: attribute-based Harmony patches applied with PatchAll.
- UI/: ModMismatchWindow drawn with Verse Widgets/Text instead of
  hand-made Unity GUIStyles; one scroll view for both columns, only
  visible rows drawn.
- Remove dead code (UITester, NotImplemented helpers, single-impl
  interfaces, SimpleLog) and enable nullable + warnings-as-errors.

Alignment
- ModListAligner reproduces the old greedy algorithm exactly (still
  matching by mod name). Tests compare it with a verbatim copy of the
  old code on the real sample lists and 6000 random lists. Unlike the
  old code it no longer throws when one list is empty.

Mod versions in the save (behavior change)
- Before: after every save the whole save file was loaded with
  XDocument and written again to add <meta><modMetaDatas>, and opening
  the mismatch window loaded and re-wrote the selected save as well.
- Now the versions are written by the scribe while the meta header is
  being written (transpiler before Scribe.ExitNode in WriteMetaHeader)
  and read from the meta header the loader already parsed. Same XML
  layout, so old saves still work; unknown versions are omitted instead
  of written as "Unknown".
- Running versions come from About/Manifest.xml as before, falling back
  to <modVersion> in About.xml; results are cached.

Dialog (behavior change)
- "Load mod list from save" now asks for confirmation and reports
  missing mods, like the vanilla dialog. "Load anyway" closes the window.
- Rows show the package id in a tooltip; long names are truncated.

Tests and CI
- Add an xunit v3 test project (Microsoft Testing Platform) including a
  Harmony 3.0 test of the call insertion used by the transpiler, and run
  it in CI.
- Bump mod version to 1.2.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Alignment
- Align with a longest-common-subsequence pass keyed by package id
  (case-insensitive; folder name for pre-1.1 saves) instead of the
  greedy pass keyed by display name. Common prefix/suffix are trimmed
  first; lists whose differing middle would need more than 4M table
  cells fall back to the old greedy pass.
- Mods present on both sides but in a different place are reported as
  MovedFrom/MovedTo instead of removed + added.
- A version change needs both versions known, so saves without version
  data no longer open the window for every mod with a version.
- Tests check the result against a textbook LCS on 6000 random lists,
  that it never matches fewer mods than the old algorithm, and that the
  greedy fallback still equals the old algorithm.

Window
- Summary line with colored counts (added / removed / load order
  changed / version changed) that doubles as the legend.
- Search box (vanilla QuickSearchWidget) over names and package ids.
- Toggles to hide unchanged mods and load order changes, remembered in
  the settings (requested in workshop comments).
- Row heights follow the current font instead of a fixed 34px; the old
  window threw "Root rect's height is smaller than minimum size" and
  drew nothing when text was taller.
- Zebra rows, hover highlight, per-row tooltip with package id, version
  and what the state means; "old -> new" version on changed rows.
- "Save mod list" button like the vanilla dialog.
- Translations for the new strings in English, Korean, Japanese and
  Simplified Chinese.

Settings
- Writing mod versions into saves is now on for fresh installs; it no
  longer rewrites the save file, and comparisons need the data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a Windows job that downloads the RimWorld unstable branch with
steamcmd (STEAM_USERNAME + STEAM_CONFIG_VDF secrets), compiles the 1.7
target against its Assembly-CSharp.dll and UnityStubs.dll, and uploads
the resulting DLL. Without the secrets the job is skipped with a
warning. Game files are deleted after the build and never cached, since
fork pull requests can restore caches of a public repository; fork
pull requests do not run the job at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Downloading RimWorld 1.7 with steamcmd on every run was too slow, so
assemblies are built locally only. Remove build.yml (and its steamcmd
job) and add release.yml: on a v* tag it checks the tag against
About/Manifest.xml and the csproj version, checks the committed 1.6/1.7
assemblies, validates XML, runs the tests, zips the mod files and
creates a GitHub release (suffixed tags become pre-releases).

Also stop embedding the git commit hash in AssemblyInformationalVersion:
the DLLs are committed, so the hash made every rebuild after a commit
differ from the committed file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a v* tag without a suffix, a Windows job downloads the packaged mod
and updates Workshop item About/PublishedFileId.txt with steamcmd
(workshop_build_item, content and change note only), logging in with
the cached login in the STEAM_USERNAME / STEAM_CONFIG_VDF secrets.
Running the workflow manually only checks that this login still works.
Both jobs time out after 15 minutes in case steamcmd waits for input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing the window in RimWorld 1.7:
- Saves without version data showed "ver : Unknown" on every row; the
  version line is now left empty when the version is unknown.
- Gray version text on the bright amber version-changed row was hard
  to read. The amber is now as dark as the other state colors and
  secondary text on colored cells is near-white.
- Drop the untranslated "Checking mismatch... please wait" message
  that flashed above the window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compared side by side in RimWorld 1.7 against the 1.1.3 window, rows
had grown from 34px to 38px and two toolbar lines were added on top,
so fewer mods fit than before.

- Each row is one line again: the version is drawn small and
  right-aligned on the same line ("1.2.0 -> 1.2.1" when it changed),
  and the name is truncated to make room for it. Row stride is now
  about 23px, so roughly 24 rows fit instead of 14 (1.1.3: 15).
- The summary/legend shares the title line and only wraps below it
  when it does not fit; spacing between sections is 6px instead of 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zzzz465
zzzz465 merged commit d54c321 into master Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant