protonscr

Project Torque

protonopen appid 1112400Game compatibility - Unofficial.NET
ValveSoftware/Proton#3359 · opened 2019-12-25 by Newbytee · updated 2026-02-07 · 15 comments · github · game page · search this game
2 matching comments, n / p to jump
NNewbytee 2019-12-25 github

Compatibility Report

  • Name of the game with compatibility issues: Project Torque - Free 2 Play MMO Racing Game
  • Steam AppID of the game: 1112400

System Information

I confirm:

  • [X] that I haven't found an existing compatibility report for this game.
  • [X] that I have checked whether there are updates for my system available.

steam-1112400.log

Symptoms

The game does not launch and instead crashes before anything else happens.

Reproduction

  1. Start the game
  2. Observe that the game crashes instantly upon launch
Mmadewokherd 2019-12-31 github

With wine-mono from the master branch I get this:
[00000028:] EXCEPTION handling: System.InvalidProgramException: Invalid IL code in ^].^Z:^A (): IL_0019: callvirt 0x0a000fda

Looks like obfuscated code, that'll be a pain to track down.

Mmadewokherd 2019-12-31 github

The failing code looks like this

				IL_0000: br.s IL_0012

				IL_0002: ldnull
				IL_0003: ldftn class [mscorlib]System.Reflection.Assembly '\u001d.\u001a'::'\u0001'(object, class [mscorlib]System.ResolveEventArgs)
				IL_0009: newobj instance void [mscorlib]System.ResolveEventHandler::.ctor(object, native int)
				IL_000e: br.s IL_0019

				IL_0010: leave.s IL_0023

				IL_0012: call class [mscorlib]System.AppDomain [mscorlib]System.AppDomain::get_CurrentDomain()
				IL_0017: br.s IL_0002

				IL_0019: callvirt instance void [mscorlib]System.AppDomain::add_AssemblyResolve(class [mscorlib]System.ResolveEventHandler)

My guess: Mono processes the code sequentially to figure out the stack types, but in fact the objects aren't pushed in the order they're written. It fails because the call signature doesn't match what it thinks is supposed to be in the stack.

JJackster 2022-10-04 github

I am running the game without obfuscation on my SteamDeck.
Here is the full error log.
steam-17677587930077462528.log

My issue is this.
Unhandled exception: unimplemented function d3dx9_36.dll.D3DXGatherFragments called in 32-bit code (0x7b011197).

D3DX fragment linker was removed in later builds of DX9 releases. Will look into it. If anyone has any suggestions, please let me know.

The game uses the November 2007 SDK which is D3DX9_35

JJackster 2022-10-04 github

I should note, I did get this working when I first got my Deck.
https://community.projecttorque.racing/threads/steam-deck-support-it-works.1618/#post-9316

I used ProtonTricks to install the following

  • d3dx9_36 - Microsoft Directx 9.0c
  • dotnet35sp1 - .Net 3.5 Service Pack 1
  • mfc90 - Visual C++ 2008 Redistributable

This stopped working a couple of weeks after I posted that topic on our forum.

JJackster 2022-10-23 github

Opening the dump files from the Steam Deck and it looks to be an issue with Fragment Linker.
image
If one force installs d3dx9_36 via ProtonTricks, it no longer crashes when loading.
But that game does not fully load up.
gamescope_2022-10-23_16-44-41
It is getting stuck on loading the game.
image
At this point, I would guess this is a .NET 3.5 issue stopping the game fully loading.

JJackster 2022-12-21 github

More Proton debugs from the game.
Fresh install of the latest OS and running Proton 7.0-5

Stock Proton settings other than "DXVK_LOG_LEVEL": "full",
DXVK.log

"PROTON_USE_WINED3D": "1",
WINED3D.log

JJackster 2022-12-22 github

Looks to be a Wine level issue. Will report back.

JJackster 2022-12-24 github

So I tested an old .exe today and it worked when I included the d3dx9_36.dll and d3dx9_31.dll files in the game directory.
When running without these files, I got the "unimplemented function d3dx9_36.dll.D3DXGatherFragments" error.

I have not been able to get the current build to load the .DLLs before today so did not upload them to the deck and we don't include them with the release (as advised) as Steam handles the DX9 install.

Here is the Proton log from the old version that runs.
steam-16801495106560458752.log

I have just tried 2 new builds and both worked when the DLLs were included in the game directory.
Even managed to get the March 2010 SDK working and that I believe is the last SDK we can run before stuff got properly removed.
gamescope_2022-12-24_04-13-10

As for how the obfuscated version use to run, IDK. We have made some changes and updates to the obfuscation so I will roll back and check to see what might be causing us issues.

JJackster 2022-12-25 github

Rolled back to an earlier version and it does not run.

Looks like users will need to force install .NET 3.5 to get it working as Mono does not run the obfuscated code.

Is anyone able to advise on how to force .NET 3.5 over mono or a way to install it that is easy for the end user?
ProtonTricks does not want to install 3.5 (at least since May 2022) as it comes up with the "2.0 is not installed" error.

SSecularSteve 2024-12-15 github

This is what I got in the error log after trying to install .NET 3.5 through protontricks using the latest GE:

[12/15/24,15:59:41] WapUI: [2] DepCheck indicates XPSEPSC x64 Installer is not installed.
[12/15/24,19:57:14] WapUI: [2] DepCheck indicates XPSEPSC x64 Installer is not installed.
[12/15/24,23:44:53] WapUI: [2] DepCheck indicates XPSEPSC x64 Installer is not installed.

I think I need to run it in Compatibility mode.

JJackster 2026-02-07 github

The game does work if you install Proton GE
Image

Currently adding Steam SDK support along with controller and Deck detection for better useability on the Deck and other handhelds. So hopefully we can work out a native fix and get this game running without tinkering.
It actually plays really well even at low TDP settings.

AI Slop from Claude, reading the latest logs from the game running on Proton 10.0-4, none obfuscation build.

Proton Issue: Project Torque (1112400) - Mono SGEN GC Crash

Game: Project Torque
Steam AppID: 1112400
Proton Version: 10.0-4 (build 1769167055)
Issue: Game crashes after 12-15 seconds with Mono SGEN garbage collector assertion

Proton log: steam-1112400.log
Custom game scripts: user_settings.py ProjectTorque.exe.config.txt

Issue Description

Project Torque crashes shortly after launch with a Mono SGEN garbage collector assertion failure. The game is built for .NET Framework 3.5 but Proton's Wine-Mono attempts to run it under .NET 4.8, causing a critical stack validation failure in the stop-the-world GC.

Status

  • [ ] Playable
  • [ ] Runs, but has issues
  • [x] Doesn't run (crashes on startup)

Console Output

Fatal Crash:

* Assertion at /builds/mono/wine-mono/wine-mono-10.4.1/mono/mono/metadata/sgen-stw.c:73,
  condition `info->client_info.stack_start >= info->client_info.info.stack_start_limit &&
  info->client_info.stack_start < info->client_info.info.stack_end' not met

.NET Version Mismatch:

fixme:mscoree:parse_supported_runtime sku=L".NETFramework,Version=v4.8" not implemented

Note: Game targets .NET 3.5, but Wine-Mono defaults to 4.8 regardless of ProjectTorque.exe.config settings.

Steps to Reproduce

  1. Install Project Torque via Steam
  2. Launch using Proton 10.0
  3. Game runs for ~12-15 seconds, then crashes with Mono GC assertion

System Information

Steam Deck Hardware:

  • CPU: AMD Custom APU 0405 (Zen 2)
  • GPU: AMD Radeon VANGOGH (RDNA 2)
  • RAM: 16GB
  • OS: SteamOS 3.0 (Holo)
  • Kernel: Linux 6.11.11-valve27-1-neptune-611-g60ef8556a811

Workarounds Attempted

None successful. Tested:

  • PROTON_NO_FSYNC=1
  • PROTON_NO_ESYNC=1
  • PROTON_USE_WINED3D=1
  • WINEDLLOVERRIDES=mf=n;mfplat=n;mfplay=n
  • ProjectTorque.exe.config with <supportedRuntime version="v2.0.50727"/>
  • MONO_GC_PARAMS=gc=boehm (not supported - Wine-Mono is SGEN-only)

Logs

Full Proton log attached as steam-1112400.log.

Key excerpts:

======================
Proton: 1769167055 proton-10.0-4
SteamGameId: 1112400
Command: ['/home/deck/.local/share/Steam/steamapps/common/Project Torque/ProjectTorque.exe']
Options: {'noesync', 'wined3d', 'forcelgadd', 'nofsync'}
depot: 3.0.20251216.191774
pressure-vessel: 0.20251210.0 scout
scripts: 0.20251210.0
sniper: 3.0.20251216.191774
Kernel: Linux 6.11.11-valve27-1-neptune-611-g60ef8556a811 #1 SMP PREEMPT_DYNAMIC Thu, 08 Jan 2026 10:09:09 +0000 x86_64

Additional Notes

Game Information:

  • Build: 5036 (Feb 6 2026)
  • Free-to-play MMO racing game
  • No anti-cheat that would prevent Wine/Proton usage
  • Uses .NET Framework 3.5 (not 4.8)

Root Cause:
The Mono SGEN garbage collector's stop-the-world phase (sgen-stw.c) fails stack bounds validation during garbage collection. This appears to be triggered by the game's threading pattern combined with the .NET version mismatch.

The game runs successfully for multiple GC cycles (12-15 seconds) before hitting the assert, suggesting specific threading conditions trigger the bug.

Potential Solutions

  1. Fix Wine-Mono to respect .NET version requests - Should honor <supportedRuntime version="v2.0.50727"/> for .NET 3.5 applications

  2. Backport SGEN stack validation fixes - If upstream Wine has addressed this, consider backporting

  3. Consider alternative for .NET 3.5 games - Allow using native .NET via winetricks more seamlessly

ProtonDB Link

https://protondb.com/app/1112400

--

Tagging: @wine-mono maintainers

Mmadewokherd 2026-02-07 github

From the log, with lines trimmed that I don't think are relevant:

10383.990:0128:012c:fixme:mscoree:corruntimehost_SwitchOutLogicalThreadState stub 00B7A370
10383.990:0128:012c:fixme:mscoree:corruntimehost_CreateLogicalThreadState stub 00B7A370
* Assertion at /builds/mono/wine-mono/wine-mono-10.4.1/mono/mono/metadata/sgen-stw.c:73, condition `info->client_info.stack_start >= info->client_info.info.stack_start_limit && info->client_info.stack_start < info->client_info.info.stack_end' not met

Looking up CreateLogicalThreadState, it seems this has to do with fibers. I don't know a lot about those, but it makes sense to me that switching to a fiber would put the thread stack pointer out of the range where the GC expects to find it. I would guess that we need to implement those methods, but I don't know the proper way to forward that information to Mono, if there even is one.

I'm surprised stopping the world is still necessary with SGEN. I'd thought the point of cooperative GC was to remove the need for such things.

Mmadewokherd 2026-02-07 github

A cursory search suggests that Mono is not currently able to handle fibers.

Mmadewokherd 2026-02-07 github

OK, looking a little bit more carefully, SGEN and cooperative suspend removes the need for stopping threads in random places. Instead, threads are only stopped in managed code and some parts of the runtime. But it seems that SGEN still examines stack pointers and wants to know about stack ranges. So what's likely happening here is that Project Torque is calling into the runtime from a fiber, the runtime sees while attempting GC things that its current stack pointer is not in the expected range, and it asserts.

MSDN doesn't really explain those unimplemented methods at all, but I'm guessing what's expected is:

  • SwitchOutLogicalThreadState - Informs the runtime that control is about to leave the current fiber. The runtime should note this and save any information (particularly about the stack) that it needs from the current state. The GC needs to remember to account for any references on the current stack, even though there shortly will not be any thread with that stack.
  • CreateLogicalThreadState - Informs the runtime that control has entered a new fiber. The runtime should create a new thread state object for it.
  • SwitchInLogicalThreadState - Informs the runtime that control is about to return to a fiber it knows about (via the "cookie" value returned from SwitchOutLogicalThreadState)
  • DeleteLogicalThreadState - Deletes a thread state object, also based on a cookie value.
  • LocksHeldByLogicalThread - OK, I don't really get this one. I guess it's to tell the caller whether any managed locks are held so that it can avoid switching fibers at a bad time???

I guess that a "logical thread state" roughly corresponds to Mono's SgenThreadInfo structure. And, because of cooperative suspend, we don't have to worry as much about stopping threads at weird times. So this may not be as hard as I initially thought. But there are still a lot of unknowns as I'm not very familiar with fibers or SGEN internals, and it'll have to be done in two steps (adding an API for this to Framework Mono that works on Windows, then using it to implement the logical thread state APIs in Wine).

This might be a good starter project for someone who wants to learn about the Mono GC. But since it only affects this one game, to my knowledge, and is moderately difficult, I don't see myself working on it in the near future.

JJackster 2026-02-07 github

Replying to https://github.com/ValveSoftware/Proton/issues/3359#issuecomment-3865046597

There was a commented out "#ifndef USE_THREAD_INSTEADOF_FIBER"
Looks to have fixed it on a fresh install on my Steam Deck.

Thank you @madewokherd !

Testing obfuscation build next.

Proton versions

Launch options

DLLs