Skip to content

Readd support for web platform exports when using the C# (.NET) version of the engine #70796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Kezzo opened this issue Jan 1, 2023 · 92 comments · May be fixed by #99508 or #106125
Open

Readd support for web platform exports when using the C# (.NET) version of the engine #70796

Kezzo opened this issue Jan 1, 2023 · 92 comments · May be fixed by #99508 or #106125

Comments

@Kezzo
Copy link

Kezzo commented Jan 1, 2023

Godot version

v4.0.beta10.mono.official [d0398f6]

System information

macOS Monterey 12.5.1 (21G83)

Issue description

In a fresh project created with v4.0beta10 and export templates downloaded and installed, the web export templates files are missing at the expected path. This makes it impossible to create web builds afaik.

image
image
image

Steps to reproduce

  1. Create new godot project with v4.0beta10
  2. Create web export preset
  3. Download export templates
  4. Click on open folder in the export template download window
  5. Observe that the required files for web exports are missing

Minimal reproduction project

N/A

@Calinou
Copy link
Member

Calinou commented Jan 1, 2023

There are no C# export templates for HTML5 yet due to missing upstream support in .NET 6 (.NET 7 didn't address this).

That said, there are significant issues with the HTML5 export in 4.0, such as #68647 and #70691. I would recommend using 3.x if targeting HTML5 for now, regardless of whether you're using C# or not.

@Calinou Calinou closed this as not planned Won't fix, can't repro, duplicate, stale Jan 1, 2023
@Calinou Calinou reopened this Jan 1, 2023
@Calinou Calinou changed the title Web export templates not downloaded/missing Document missing C# web export templates due to lack of upstream support Jan 1, 2023
@Calinou Calinou added this to the 4.0 milestone Jan 1, 2023
@Delpire
Copy link

Delpire commented Jan 15, 2023

What is the missing upstream support from .NET we're waiting on to get HTML5 support? Can we link that item here and then in whatever documentation gets created?

Not having HTML5 support for Godot 4 is preventing me from using Godot 4 when participating in game jams as I prefer uploading web builds.

@yanniboi

This comment was marked as off-topic.

@poke1024
Copy link
Contributor

Since several people now independently wrote this same bug report, and the situation is as it is with Godot 4 stable, maybe it might make sense to mention Web export for Godot 4/Mono as "unsupported for now" somewhere central in the Godot mono docs.

@yingshaoxo

This comment was marked as off-topic.

@ArikRahman

This comment was marked as off-topic.

@Sythelux
Copy link

There are no C# export templates for HTML5 yet due to missing upstream support in .NET 6 (.NET 7 didn't address this).

That said, there are significant issues with the HTML5 export in 4.0, such as #68647 and #70691. I would recommend using 3.x if targeting HTML5 for now, regardless of whether you're using C# or not.

I propose we make a Tracker ticket to collect things: why C# Support is missing, what can be done about it (split in: what can we do about it. What can dotnet devs do about it) and what can be done to make it verbose to the user. I also recently stumbled upon it just missing and I also consider it an important feature.

I saw here, on other tickets and on the release notes of 4.0 that there was supposedly a communication between core godot-devs about it, but there isn't really a transparent Ticket for us.

@ashelleyPurdue
Copy link

There are no C# export templates for HTML5 yet due to missing upstream support in .NET 6 (.NET 7 didn't address this).

What upstream support is missing, exactly? Is it something that we could expect in, say, the next year?
I'm trying to gauge whether or not I should use Godot 4 for a new project, in the hopes that web support comes while I'm still working on it.

@Calinou
Copy link
Member

Calinou commented Jun 23, 2023

What upstream support is missing, exactly? Is it something that we could expect in, say, the next year?

We can't give an ETA as we don't know when contributors will be available to do the required work on both the .NET and Godot side. I wouldn't expect it to be ready for this year though, especially if you want to use a stable version and not a pre-release. If you need to use C# to target the Web platform right now, stick to Godot 3.x.

@Sythelux
Copy link

We can't give an ETA as we don't know when contributors will be available to do the required work on both the .NET and Godot side.

Is there a group of participants I could connect to? I'd like to help working on that.

@Zireael07
Copy link
Contributor

@Sythelux Try Godot contributors chat at https://chat.godotengine.org/channel/navigation

@WithinAmnesia
Copy link

WithinAmnesia commented Feb 6, 2025

@raulsntos I want to ask you a larger set questions regarding the future dev cycle of Godot and Godot 5.x dev plans. This is for the wider creative dev community and make it easier to convince people (mainly commercial / senior devs) in the industry to start using Godot more in the near future. I want to be able to give these senior talented people proper up to date answers / quotes from 2025 by talented Godot engine devs like yourself. So I figured it best to just go to the source to ask directly about Godot's future fate.

I am sorry to bug you too but I figured it best to go to the source and get various creative community future Godot dev direction concerns sort of done and taken care of with. So I and others can share it with the rest of the creative community in regards to where Godot dev staff are doing for 2025-2027/2028-2030's+ / into the next console gen come 2027/2028+. (I keep getting bugged and I wish to be able to give proper answers to the creative community devs to properly advocate for Godot's macro leadership. So I figured to just get a proper answer to handout / give / share to the wider creative community devs going forward given the lack of discoverable info on the direction of Godot in the next ~2-5+ years).

Is this C# web export problem a reason to make Godot 5.0 start more development? As in with this case if Godot 4.x cannot realistically add proper C# web support in the future / operate with C# web in a way that is native / without large difficulty / poor ergonomics to the majority of Godot devs?

Would this make a Godot 5.x seem closer to a 2027-2028 kind of target window for the general public release? As in if there are too many deep rooted issues to use Godot 4.x for major future proofing for the 2030's? As in would this require a rebuild for better future proofing to start in the current dev cycle (to better solve issues such as C# web in the future)? If Godot 5.x is on the march sooner or later would a dev cycle sort of follow the same pattern as Godot 3 to Godot 4 public release? Also why is there no Godot 5.0 in the Godot issues milestones https://github.com/godotengine/godot/milestones if it is in the proposals https://github.com/godotengine/godot-proposals/milestones ? I wish I could give people proper answers or add it myself but I'm more a creative community dev / old guard to mmo devs and less of a tool dev / Godot engine dev but I think this Godot 5.0 issues milestone would help people make plans moving forward.

I heard rumors of a C# Godot core rewrite for Godot 5.x to better handle C# / web / massively multiplayer / proper servers networking templates / proper multiplayer documentation / proper industry standard multiplayer support and major future proofing for late 2020's / early to mid 2030's and a better focus on large scale projects / proper steam support / better support for industrial scale projects. Specifically with help / more project donations from big movers of the industry in regards to get Godot more in line to support industrial scale game dev staff already trained with C# from Unity and Unreal etc. This has several reasons such as big studios with already trained senior staff to avoid future royalties / fees and so Godot can better compete in the near future with the big older closed source game engines from the creative community.

As over the past year or so talking to the creative community with and without Godot discord, forums, reddit, twitter, youtube, twitch, GitHub, email / talking and other places where large scale creative community / dev community places are I heard of a large demand from commercial / professional / not-indy / senior old guard game devs to mainly use C# instead of GDscript.

As in many creative community dev conversations had shared common points as it would be common to hear from senior game devs talking like in a chat where they go ~Yeah Godot is great but they wouldn't use it due to the dependency on the limited range GDscript and it has onboarding issues so they stick to Unreal / in house engines for serious large scale projects. Yet if Godot had better not-GDscript parity / full C# and C# web support they would think of serious applications to use Godot for making industrial scale game dev to help their large studios / better fund / donate to Godot's dev cycle. What is the status / current line of thinking regarding these issues with Future Godot dev / Godot 5.x?

@WithinAmnesia
Copy link

WithinAmnesia commented Feb 6, 2025

@iistarion I think you have a point, this could merit it's own issue and the complex nature of the questions could merit their own space for discussion. I should free up this space for this issue and find a more appropriate space for these questions. I think that a separate issue would probably be wise to host these issues and allow for more dialogue too. I took the issue rules advice and found https://github.com/godotengine/godot/blob/master/CONTRIBUTING.md and it has a part about communicating with developers. I think I should pursue this, thank you for the feedback, I would not have known of this / where the proper channels were until given the advice.

@Delsin-Yu
Copy link
Contributor

@danroth27

Any ideas on what might be happening here?

Sorry for the pinning; is there any publicly shareable progress or information on the dotnet wasm side about the issue Godot is currently facing? Being able to export to the web is important to many developers, thank you.

@IndigoP4
Copy link

IndigoP4 commented Apr 15, 2025

It may be a really stupid idea/question... if Godot wasm can 2-way communicate with JS via interop, and .net wasm can do the same, isn't it technically possible to build up a communication layer between the 2 via JS bridge (something like the file-based IPC, or with chained callbacks)?
Or it's not even worth considering because the overhead of serialization/deserialization of... literally everything?
Or is there another reason this isn't considered?
(Sorry if somebody asked this before, I haven't found anything related.)

Edit (I don't want to make another post with another probably stupid question):
I've found mixed info about Godot's usage of LLVM. If a Godot template can be compiled with LLVM, would it be possible to pull the engine, and compile both Godot and the .net code to LLVM, link/connect them on that level (intermediate llvm representation?), and compile them together to a singular wasm?

@collmut
Copy link

collmut commented Apr 29, 2025

@raulsntos I have been reading about the limitations you mention above that arise when linking godot and dotnet assemblies.

Would you say this issue godotengine/godot-proposals#7895 will change alot in how web support is implemented? That is just incase we decide to have web support before actually migrating it into a plugin?
The article linked also states the idea of having to go with csharp for scripting or csharp as a tool to extend the application just as how c++ or any other language bindings are via gdextension. Would you also say both paths are possible to have in the same gdextension?

I will appreciate if you have any other newer source where i can read more on transforming godot csharp into a plugin. I have only seen it mentioned in the priorities here: https://godotengine.org/priorities/#dotnet

@Delsin-Yu
Copy link
Contributor

@collmut

Would you say this issue will change alot in how web support is implemented?

No, We'll have the same issue as GodotSharp since hosting the .NET runtime works the same way. In other words, if we cannot get GodotSharp to work in WASM, we cannot make the new bindings work in WASM either.

@raulsntos raulsntos linked a pull request May 6, 2025 that will close this issue
@raulsntos
Copy link
Member

Hello everyone, I have a quick update regarding web support for C# projects.

As mentioned in my last update, the option of statically linking Mono seemed the most promising so we went ahead with that.

I have opened a draft PR with the latest changes, but keep in mind it's still a work in progress:

As a reminder, this approach still seems very brittle to me and has some limitations. The C# project must match the WASM features supported by the Godot template (this includes things like the threading model, exception handling, SIMD support, etc.). The TargetFramework version of the C# project must also match the one that was used to build the template.

Additionally, since we currently don't load any globalization data, we only support invariant mode. This is not a big problem because most users will likely rely on Godot's localization features, so it's not a blocker.

On the last update the issue we run into was retrieving function pointers. We were able to workaround that by declaring stub C# methods on the project we use to retrieve the Mono runtime. When building the Godot templates, this ensures these methods are included in the generated table which seems to be enough to let us retrieve the function pointer at runtime.

In a regular C# application built for the web platform you'd use dotnet.js which acts as a loader for the WASM file and other required assets. In Godot we have our own way of doing this, and as a result we're currently missing a key part of the process.

The Mono runtime exports some JavaScript functions but at the time of building the templates these are stubs. The dotnet.js loader takes care of replacing these stubs with their real implementation in dotnet.runtime.js. We're currently missing this step so they remain stubs.

This means some .NET APIs that rely on these exported JavaScript functions will not work, resulting in unexpected behavior. This includes things that must be implemented using browser APIs such as cryptography.

Nonetheless, I think this is significant progress and has allowed us to build a demo running on the browser:

Thank you all again for your patience with us. We're excited to provide web support for C# projects even at an experimental state and we'll keep working to fix the remaining issues.

@BenMcLean
Copy link

I hope this isn't an ignorant question but regarding the requirement of the TargetFramework of the C# project needing to match the one that was used to build the Godot template: does this come with additional restrictions about other included projects or libraries which may be from older .NET versions? (example: I tend to include a lot of .NET Standard 2.0 libraries and having access to those is one of the reasons C# is a benefit)

@raulsntos
Copy link
Member

So let's say the templates were built with net9.0, then your game project needs to target net9.0 as well. Your game dependencies (project or package references) can target any TargetFramework compatible with net9.0 (for example net6.0 or netstandard2.0 would be compatible, but not net10.0).

It's common for users to target a newer version of .NET, we see it all the time with users targeting .NET 9.0 today even though the default is 8.0. This is already a problem in Android where users must also match the version we're targeting in the template (which in this case is net8.0).

In Android projects you can workaround this by using Gradle builds, because it allows us to use the Java libraries directly from your C# project instead of the hardcoded one we use in the template and the Mono runtime is dynamically linked.

You should be able to build a custom template targeting a different version of .NET if you need it. But it doesn't seem like you'd need to do that in your case.

That said, whether the library you are using is supported on the web platform or not is a different question. That depends on the specific library, not every C# library is "cross-platform" (for example if it consumes some native Windows library).

@YuriArthas
Copy link

I'm really excited to hear that C# support for the web is on the horizon! I was actually about to give up on Godot, but this news has given me new hope.

Do you have an estimated timeline for when this feature might be integrated into a stable release, such as Godot 4.5?

@Armynator
Copy link

Armynator commented May 7, 2025

While it's awesome to have working C# web exports again, I think this approach is going entirely into the wrong direction. Let's ignore the current prototype problems for a second and assume that things like the stub functions, globalization and other incompatibilities can be worked out soon with more manual hacks or adjustments. Is the base of this approach really viable?

As far as I can see, this is a huge step backwards, as you are loading the entire Mono runtime to JIT compile the managed DLLs inside the browser, very similar to Godot 3. Here are a few problems coming to my mind:

  • huge pck file size, as the mono runtime needs to be included
  • no trimming, increasing pck size even further
  • different runtime versions, hacked together with GetRuntimePack (Mono and .NET core)
  • clearly visible C# source code (reminding me of Provide obfuscators support for C# godot-proposals#1407 again)

Now I just tested the demo you provided. And unsurprisingly, it is over 114mb in size already without containing any actual game assets. ~42mb of it are Godot (the entire engine itself), ~60mb of it are just the C# and Mono part. I've also checked the IL code in the DLLs, noticing that nothing was stripped out/trimmed and the full source code left readable.

To put this into perspective: the C# part of a full Godot standalone game export is ~15mb in size when using .NET 9 and NativeAOT with high trimming settings. No runtime needed, no dependencies - just a small, AOT compiled binary blob, nicely embeddable into the final exe file. And I think this should be the goal for the web version too, minus the embedding part maybe.

(For fairness I've also compiled a small OpenGL standalone game to WebGL using the browser-wasm target (dotnet.js), which resulted in ~30kb for renderer and gameplay code and ~9mb for the .NET runtime + dependencies, indicating that dotnet.js and/or NativeAOT-LLVM might be the better way to go in the future)

Another sidenote why all of this is important: optimizing for download size is absolutely mandatory for web games nowadays, especially the initial download size. Unity for example is well optimized for it already, and even they constantly struggle with this problem, as more and more game sites start enforcing lower size limits.

Are there any ways to further optimize the Mono part for now? Is there a way to get AOT compilation/trimming working with it?

Edit:
To make it clear again, the current approach is better than nothing and I'm glad to see it finally working. I just don't think this should be the final solution, as I see too many downsides.

@Delsin-Yu
Copy link
Contributor

@Armynator

I do agree that a look into size optimization is necessary, however

clearly visible C# source code

Can you elaborate on the "clearly visible C# source code"? Are you suggesting that the plain text C# source code is required for the current solution? If I recall correctly, the mono interprets IL (managed DLL content) instead of C# source code.

@Armynator
Copy link

Can you elaborate on the "clearly visible C# source code"?

Yes, the current approach uses IL code, but that's easily converted back into C# source code files with one click. But that's more of a not so nice side effect which doesn't need that much attention anyways. I just brought it up because NativeAOT solved it completely already by removing all debug symbols and stack trace informations if desired, and with the Mono approach we are back 5 years again to this point.

In short: anyone can download your index.pck in the browser, import it into the Godot editor, reverse the IL code back to C# and has the full source code of your game with all assets right in their editor. NativeAOT prevents that for the source code part at least, but as I already said: it's not its actual purpose and more of a nice side effect. The Mono runtime size is much more concerning to me, and I really hope that there are ways to optimize that.

@Delsin-Yu
Copy link
Contributor

and I really hope that there are ways to optimize that.

(For fairness I've also compiled a small OpenGL standalone game to WebGL using the browser-wasm target (dotnet.js), which resulted in ~30kb for renderer and gameplay code and ~9mb for the .NET runtime + dependencies, indicating that dotnet.js and/or NativeAOT-LLVM might be the better way to go in the future)

Sounds like you have expertise in web development via C#, have you ever achieved calling to an AOT compiled dotnet library via a wasm application? as that's the main blocker that's preventing Godot from supporting NAOT/wasm.

@pavelsavara
Copy link

pavelsavara commented May 7, 2025

match the WASM features supported by the Godot template

Emscripten version match could be also required.

threading model

It seems godot is MT, but you are linking ST dotnet?
I guess you are calling it on single thread only ?

statically linking Mono seemed the most promising

Yes, POC of dotnet runtime (mono) running as emscripten side module would be welcome.

I'm interested to learn how dlopen plays with pthreads
What happens when there are 2 different dlmalloc ?
What is the perf impact overall ?

In a regular C# application built for the web platform you'd use dotnet.js which acts as a loader for the WASM file and other required assets. In Godot we have our own way of doing this, and as a result we're currently missing a key part of the process.

In Net10 we made good progress in making dotnet.js more friendly to JS bundlers.

There is also a way how you can provide pre-downloaded files for dotnet.js
https://github.com/dotnet/runtime/blob/main/src/mono/sample/wasm/browser-minimal-config/main.js

That's not really stable/public API, but you are deep in the weeds already.

@raulsntos please feel free to open questions and ping me there.

~60mb of it are just the C# and Mono part.
and ~9mb for the .NET runtime + dependencies, indicating that dotnet.js
Are there any ways to further optimize the Mono part for now?

There are many things you can do to make the mono/wasm runtime smaller. We keep cheat-sheet here
https://github.com/dotnet/runtime/blob/main/src/mono/wasm/features.md

If you are willing to do hacks beyond what's supported product, you can make it much smaller.

We did demo/hack recently for simple form validation
DamianEdwards/WasmClientSideValidation#3

There is ILLink.Substitutions.xml killing runtime C# classes and _MonoRuntimeComponentDontLink killing mono components, ICU, libz.

We got to 2.5MB uncompressed which is about 810 KB brotli compressed.

Image

Typically the application code is much larger than the runtime and so trying harder on runtime has diminishing returns.

Is there a way to get AOT compilation ?

There is Mono AOT for WASM. It tends to produce larger downloads and faster execution than mono interpreter.
The AOT with NAOT-LLVM is community lab project, they have different set of tradeoffs.

Mono runtime has full reflection etc, while NAOT doesn't. Requirements of C# codebase/libraries which you want to use matter.

@raulsntos
Copy link
Member

@pavelsavara Thanks for reaching out.

It seems godot is MT, but you are linking ST dotnet?
I guess you are calling it on single thread only ?

Godot supports both MT and ST. Right now the PR uses ST because, as far as I know, MT dotnet is experimental. However, I tested both MT and ST and they both seem to work fine, as long as the Godot build matches the dotnet runtime:

  • scons threads=yes and <WasmEnableThreads>true</WasmEnableThreads>
  • scons threads=no and <WasmEnableThreads>false</WasmEnableThreads>

In Net10 we made good progress in making dotnet.js more friendly to JS bundlers.

I'll have to look into that, I've only been using .NET 9. I have tried replicating dotnet.js and load dotnet.runtime.js manually, but there's a lot that we end up duplicating.

In an exported Godot project we end up with an index.js (which is the emscripten module and probably the equivalent to dotnet.native.js) and an index.wasm (which is likely the equivalent to dotnet.native.wasm). The workers are also initialized from index.js so it's probably somewhat equivalent to dotnet.worker.mjs too. The only thing we need to do is load/initialize dotnet.runtime.js.

Is there a chance you could expose an API on dotnet.js that only takes care of dotnet.runtime.js and leaves the rest alone? I'm not sure that providing pre-downloaded files for dotnet.js would work given our special setup, since I think Godot needs to be the one initializing the WASM file with WebAssembly.instantiate{Streaming} but I'm not too familiar with this part of the Godot codebase or emscripten in general.


@Armynator Like others have expressed, I also agree that size is important on web. We're looking at getting something functional first, then we can look into optimization. That said, @adamscott has been working on compressing exported projects which can help a lot.

huge pck file size, as the mono runtime needs to be included

A runtime is always needed to run C# code. NativeAOT also includes the runtime (it's by definition always self-contained).

As mentioned in #70796 (comment), there are a number of ways to reduce the size of the Mono runtime and we could explore them in the future, but we can't make any assumptions about what the user project needs. The best way to reduce the size as much as possible will always be to compile the template yourself, so you can configure the linked Mono runtime to your specific needs and exclude unused modules.

no trimming, increasing pck size even further

Mono does support trimming. However, Godot doesn't fully support it because we have some reflection usage that is incompatible, so we are currently rooting the assemblies to prevent trimming APIs that may be needed in the exported project. We want to improve trimming support, but this is orthogonal to web support.

different runtime versions, hacked together with GetRuntimePack (Mono and .NET core)

I'm not sure what you mean by this. As mentioned in #70796 (comment), the template must match the C# project so there shouldn't be different runtime versions.

While it's true that the GetRuntimePack approach may seem hacky, I don't think there's another way to link Mono statically without it. In #70796 (comment) we explored dynamically linking but it didn't work (in summary, the WASM flags didn't match).

@EvarDion
Copy link

EvarDion commented May 7, 2025

Godot supports both MT and ST. Right now the PR uses ST because, as far as I know, MT dotnet is experimental.

It's still experimental because it has been put on the backburner by Microsoft. The last time I looked at it in the UNO project on .NET 8, it was working okay, but Microsoft disabled it in .NET 9 due to stability issues, as it relies on SharedArrayBuffer, which not all browsers support completely (and in the same way).

https://platform.uno/docs/articles/external/uno.wasm.bootstrap/doc/features-threading.html

I think from memory that you can turn it on, but you will only get one extra thread by default, which is still better than nothing but not ideal when most PCs could use eight threads simultaneously (or more).

I haven't looked at multithreading in .NET 10, but I will once I see some indication that Microsoft has fixed the issues with it.

You can increase the number of P-threads when you compile the code with Emscripten, but the main issue was that if you have too many threads running concurrently, the browser would just randomly freeze and not recover, so you would have to reload the page and lose your entire application state. That is pretty much why almost everyone invloved with .NET WASM has decided to just disable multithreading in WASM by default.

For developers who want to target C# in godot on WASM.

The good news is that you can still write your code using Tasks (async/await) and it will work fine on a single thread, then when multithreading becomes available, the code will scale automatically without having to be modified due to how the TaskScheduler works in .NET. So the lack of true multithreading on day one need not be a show stopper. (The only thing needed is a recompile).

@thygrrr
Copy link
Contributor

thygrrr commented May 13, 2025

I'm also not sure this is the right way to go, but it is ONE way to go, at long last, so I am happy this is being explored.

Where I disagree with @Armynator is that theres zero concern about disassembly of the game, as this will be done one way or another. Yes, it's easier with IL, but added obfuscation wouldn't deter determined attackers from stealing or manipulating client binaries. It's also important that an open source project should not actively invest its time and resources to cater to closed source desires (which are not even valid needs). It's fine that closed source is allowed, of course.

My concerns with the Mono approach are:

  • threading models, multi threading needs to be supported (I followed the whole WASM export discussion and actually disagree with its conclusions, while at the same time acknowledging the reality of the browser landscape - the answer is "both", a legacy singe-threaded model as well as a multi-threaded runtime are needed)
  • 3rd party packages, that also might be using some sort of multithreading
  • maintenance effort to keep this working and up to date with whatever the .NET ecosystem needs are
  • who in the world asked for live compilation in the browser, we want an export to the browser (i.e. the demo does 200% of what the scope should have been - I can imagine that it was deemed 'easy enough' given the technology choice, and there are actually some attractive implications here - but what the community wants is a working Web export, nothing more)

I believe the .NET AoT approach failed because the Godot Engine was being stubborn about entry points. The libgodot project was rather close to a promising solution, that would use .NET's AoT binary as the entry point in WASM. I still think this is the correct way to do it.

That said, I'll give the method presented in here a spin to see if I can make my .NET libraries work with it.

@eldamir
Copy link

eldamir commented May 13, 2025

It recently got a mention here: https://godotengine.org/article/live-from-godotcon-boston-web-dotnet-prototype/

Not really adding any information that isn't already in this thread, but at least it seem relevant to link the two together here.

@pavelsavara
Copy link

pavelsavara commented May 13, 2025

Is there a chance you could expose an API on dotnet.js that only takes care of dotnet.runtime.js and leaves the rest alone?

Probably not. Interfaces between our js modules are internal implementation detail.
Also most of our MSbuild scripts, if you have your own build, we can't cover for you.
We are a small team and there is no direct revenue attached to any of this.

The public JS API is in dotnet.d.ts

If you need specific extension point in the startup process we are happy to collaborate.

MT dotnet is experimental.

UNO project on .NET 8, it was working okay

Not okay to our level of expectations for shipped product.

.NET 10, but I will once I see some indication that Microsoft has fixed the issues with it.

The known MT issues

Dear FOSS community, help appreciated ❤ please ping me if you are willing to troubleshoot some of it.

Emulation of pthreads on the WebWorker is very expensive and complex abstraction. Especially if you want DOM/Canvas interaction and synchronous calls from JavaScript at the same time. Here is a design doc I did 2 years ago.

Most of demand for MT is from users which want to port legacy MT codebases to Blazor without "what color is your function" rewrite.

There is no investment into MT in .NET 10 so far.

So the lack of true multithreading on day one need not be a show stopper.

I agree with that. There is plenty you can do with async/await.
Also, many thread-loops could be re-written as a timer, I did it many times already.

@vonweller
Copy link

Actually, the main focus at this stage should be on being able to use web export in GodotC#! Other optimizations, improvements, or breaks can be done gradually. The current proposal by raulsntos feels very worthwhile to try.

@MattParkerDev
Copy link

Can we compile the Godot WASM with flags that match the dotnet WASM?

That's a great question. It has come up before and I'm sorry for not being more clear about it in my previous post.

As I understand it, to link 2 WASM libraries dynamically we need one of them to be compiled with the -sMAIN_MODULE flag and the other one with the -sSIDE_MODULE flag. We can compile the Godot WASM with either of those, but it doesn't matter because the dotnet WASM is not compiled with either of them so it doesn't support dynamic linking.

Compiling the dotnet WASM with one of those flags is mentioned in the NativeAOT-LLVM section of my previous comment.

Based on this comment, to dynamically link 2 modules, one must be the MAIN_MODULE, and the other the SIDE_MODULE

And from this comment:

It's possible that this could be fixed by compiling the entire .NET runtime instead, but I don't think it'd be a good approach. I've discussed with Microsoft employees, and I've been told that they tried to compile the .NET runtime as a side module a long time ago unsuccessfully, they haven't tried since so it's likely not going to work.

It seems that compiling the .NET runtime as a side module is not feasible.

However, is it possible to compile the .NET runtime as a main module, which could then be linked to Godot as the side module? (Ideally this would be a change to the official wasm .NET runtime, so we wouldn't need to compile a custom build ourselves)

Has this already been tried? I would guess that Godot as the side module is probably related to LibGodot also.

@EvarDion
Copy link

EvarDion commented May 13, 2025

Not okay to our level of expectations for shipped product.

When I said it was ok in .net 8 I meant the multithreading was working to a point. but it was only stable on one extra thread.
having 1 background thread plus the UI thread was still way better than having everything run on the browser's UI thread.

That being said, doing UI updates through jsinterop and the DOM the way UNO Platform does it is still 10 times slower than android and 100 times slower than native windows but for a web app it wasnt too bad compared to other fairly complex web apps.

People need to keep their expectations in check, a browser with multithreading is still a browser, so its still has to go through layers or abstraciton and security to get anything done which means its always going to be much slower and worse user experience than native.

Even when I look at the bevy engine's wasm demos, they are technically very impressive but still way below the performance of a native 3D app, especially on mobile devices (if the demo even runs)

Dear FOSS community, help appreciated ❤ please ping me if you are willing to troubleshoot some of it.

I think the main reason not many people are helping is because it's fundamentally a .NET runtime and browser problem (aka a problem for microsoft and google to fix).

As much as I love the idea of C# multithreading working in the browser, if I can't actually change the code that is broken because it is inside the .net runtime or inside the browser source code then meh. i'll wait.

@BenMcLean
Copy link

BenMcLean commented May 13, 2025

That last comment on multi-threading confused me.

I haven't been actively using Godot in several years now. My recollection of working on a C#-based VR project in Godot 3 a few years ago was that there was no way I could consistently send frames to the headset while a level was having physics objects added because of Godot 3 being single threaded, which made Godot 3's physics effectively unusable for anything that could ever even potentially be accepted in the Quest Store. That was a real roadblock for me.

Are you saying Godot 4 is multithreaded now?

P.S. About making Godot the side module instead: this has been proposed and tried many times. I think the biggest effort towards it was called libgodot. The basic idea is to turn Godot into a .NET library instead of having Godot accept a .NET library. But as I understand it, the actual Godot dev team decided this was emphatically not a direction they wanted the official project to go in.

@Pineappletooth
Copy link

Pineappletooth commented May 13, 2025

Are you saying Godot 4 is multithreaded now?

Godot has multithreading, not the whole engine is thread safe but there has been big efforts to make most of the engine thread safe from both internal use and scripting APIs

P.S. About making Godot the side module instead: this has been proposed and tried many times. I think the biggest effort towards it was called libgodot. The basic idea is to turn Godot into a .NET library instead of having Godot accept a .NET library. But as I understand it, the actual Godot dev team decided this was emphatically not a direction they wanted the official project to go in.

Libgodot is listed as a priority from the dev team https://godotengine.org/priorities/#allow-compiling-godot-as-a-library however there is still a lot of work to do before it can be merged, also I don't know if it will resolve the issue with C# web.

@BenMcLean
Copy link

@Pineappletooth Great information. Much appreciated.

@theBSH
Copy link

theBSH commented May 14, 2025

cant we reverse engineer unity's way of handling the webassembly?
note i dont know nothing about it, just wanted to get a proper answer

@Delsin-Yu
Copy link
Contributor

@theBSH
Please refer to this documentation and this blog post for more technical details on the path Unity (and Tuanjie) took for wasm support. Translators may be required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment