Skip to content

Contributing

Bubbleshum edited this page May 22, 2026 · 2 revisions

Contributing

Thanks for the interest. WPR is an alpha preservation project — there's a lot of low-hanging fruit (missing shims, untested games, broken patcher entries) and contributions of all sizes are welcome.


Things that help

  • Test games and report results (commit hash + first [wpr-ex] line from the per-game log goes a long way).
  • Add missing shims — usually a few lines of Microsoft.* / System.* API surface that a game needs.
  • Fix patcher table misses — type/method references the game's IL uses that don't map to a shim yet.
  • Implement Silverlight controlsLongListSelector, WrapPanel, PhoneTextBox, PerformanceProgressBar, GestureService / GestureListener are notable absences.
  • Improve Android — currently launches to a white screen on this fork.
  • Documentation — wiki edits / FAQ entries / Compat List updates.

Setting up

  1. Clone:
    git clone https://github.com/Bubbleshum/WPR.git
    cd WPR
  2. Open Src/WPR.sln in Rider (recommended) or VS 2022 17.8+.
  3. Set startup project to WPR.UI.Desktop and run.

Full detail and CLI build flags: Building WPR.


Read these first

  • CLAUDE.md in the repo root — the canonical project conventions: build-flag pitfalls, reinstall-vs-rebuild rule, shim file layout, end-of-session cleanup.
  • Architecture on the wiki — how install / patch / launch / shims fit together.

The reinstall-vs-rebuild rule

Burns everyone at least once. Internalise this:

Change Action
Shim implementation change
(any .cs under WPR.*Compability, Microsoft.*, System.*, FNA, GamerServices)
Rebuild only. Installed games pick up the new behaviour on next launch.
Patcher table change
(new entries in ApplicationPatcher.cs's Patches / MemberPatches)
Rebuild and reinstall the affected games. The IL was rewritten at install time; new redirects don't apply retroactively.
Achievement extractor change
(XnaAchievementCodeExtractor.cs)
Install-time — affected games need reinstalling.

When your PR description mentions a fix for a specific game and lists a patcher / extractor change, call out that a reinstall is needed so reviewers know what to test.


Shim file layout convention

WPR.SilverlightCompability mirrors the upstream Silverlight / WP namespace hierarchy on disk:

Upstream type File path
System.Windows.Shapes.Rectangle System/Windows/Shapes/Rectangle.cs
System.Windows.Controls.Primitives.Popup System/Windows/Controls/Primitives/Popup.cs
Microsoft.Phone.Shell.PhoneApplicationService Microsoft/Phone/Shell/PhoneApplicationService.cs

The C# namespace declaration in every file is WPR.SilverlightCompability — the directory structure is pure organisation, the assembly is one flat DLL. When adding a new shim type, look up the upstream namespace, mirror it as directories, drop the class file in. The filename matches the type name.

Keep the doc comment /// Shim for <c>System.X.Y.TypeName</c>. on each shim — it's the canonical record of which upstream type the file shadows.

WPR.WindowsCompability and WPR.XnaCompability are still flat. Don't make a separate pass just to reorganise them; apply the mirror-tree convention the next time you touch them.


CLI build for edit-verify

dotnet build <project>.csproj -c Debug `
    -f net8.0-windows10.0.17763.0 `
    -maxcpucount:1 -nodeReuse:false --nologo

Build a leaf project for fastest feedback (e.g. the project containing the file you just edited). Full-chain builds via the CLI sometimes fail with spurious "namespace not found" cascades — defer those to Rider.

The Android leg often fails on this dev box with NU1202 (workload mismatch) — that's why we explicitly pass -f net8.0-windows10.0.17763.0.

See Building WPR for the full list of flags and what each one does.


Cleanup at end of a session

Before opening a PR (or wrapping a task), clean up anything you created just for diagnosis:

  • Log files you wrote to the repo root or under Src/ (e.g. build_*.log, restore_*.log, install_*.log). Leave pre-existing files alone.
  • Stray global.json / scratch csprojs created just to probe SDK behaviour.
  • Orphan dotnet / MSBuild / VBCSCompiler processes you spawned (Get-Process + match the command line). Do NOT kill processes belonging to Rider (ReSharperHost, JetBrains.*) or VS (devenv).

Don't clean obj/ or bin/ — those are normal incremental build artifacts.


Coding guidelines

Style

  • Follow existing project conventions (look at neighbouring files).
  • Meaningful names over short ones.
  • Prefer clarity over cleverness.
  • Avoid unnecessary abstractions — shims should be thin.
  • Keep platform-specific code isolated where possible.

Diagnostic logging

Use WprDebugTrace.WriteLine($"[wpr-trace] ...") for trace output. The wrapper is #if DEBUG-gated, so Release builds elide the formatting and file writes entirely (no per-frame cost). The convention for prefixes:

Prefix When
[wpr-trace] Informational milestones
[wpr-ex] Swallowed exceptions
[wpr-heartbeat] Periodic state snapshots (e.g. FFWD loader gates)
[wpr-content] ContentManager.Load failures
[wpr-resolve-user] / [wpr-resolve-default] Assembly resolver probes

Commits & PRs

  • Keep PRs focused on a single change. "Fix PvZ achievements" + "Make SpriteBatch tolerant" + "Add keyboard accelerometer" should be three PRs, not one.
  • Mention any reinstall requirement in the PR description.
  • For compat fixes, name the game(s) in the PR title and add an entry to the wiki's Update History once merged.

Compatibility reports

If you test a game and the result changed, file an issue with:

Info Example
Game name Hydro Thunder GO
WPR commit hash c5e988d9
Platform Windows 11 22H2
Status Playable / Partial / Broken
First [wpr-ex] line (paste — include the stack, not just the message)

The log lives at %LocalAppData%\WPR\Apps\<ProductId>\wpr_game_debug.log — see Troubleshooting.


What not to submit

  • Copyrighted game assets / XAPs / decompiled commercial code.
  • Proprietary SDK files (the WP7 SDK reference assemblies).
  • Anything that would put the preservation project at legal risk.

Related pages

Clone this wiki locally