Skip to content
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

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

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

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

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

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

@abbychau
Copy link

abbychau commented Oct 4, 2024

Here was an updated from the MicroSoft side. Gave an idea of making godot-as-module

It seems that Godot is not necessarily unable to output web, even without cpp2il

The current problem with .net is that it cannot output the side module of wasm
But it doesn’t actually affect Godot. It makes itself a module, and then the game itself is used as the main module to sideload Godot.

it is a hard work but at least we don't need to wait for .net 10.0 and there is no promise of wasm side modules from 10.0 anyways.

@abbychau
Copy link

abbychau commented Oct 7, 2024

I wanna know how FlatRedBall does this?

@Fireye04
Copy link

Fireye04 commented Oct 7, 2024

Did a bit of digging on their website and found this: https://docs.flatredball.com/flatredball/glue-reference/multi-platform/web

"FlatRedBall supports web projects using Blazor Web Assembly and WebGL. Web projects use C# just like other FlatRedBall platforms."

Here's the relevant link to blazor: https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor

Not sure if this tool can be applied to Godot as it is applied to FRB, but it's hopefully a good place to start!

Edit: Reading over the issue history, it appears this is not an option yet, being dependent on either a dotnet update coming at some unknown point in the future, or potentially a relevant LibGD PR.

@Delsin-Yu
Copy link
Contributor

If I recall correctly, DotNet Wasm's current limitation is that it can't be compiled into a side module. If the development team found a way to boot the whole Godot System from the DotNet Wasm product (and somehow link the C# Scripting system to the DotNet Wasm product), we could get this working.
However, considering the current architecture of Godot, GodotSharp, and the godot-dotnet, it's a ton of work and likely only happens in a custom fork (it relies too much on DotNet).
I agree that the LibGodot Project merger is the starting point of such, but there is still a long way to go if we actually wish to take this technical decision.

@Zireael07

This comment was marked as off-topic.

@theowiik

This comment was marked as resolved.

@Kezzo Kezzo changed the title Document missing C# web export templates due to lack of upstream support Web platform exports are not supported when using the C# (.NET) version of the engine Oct 8, 2024
@RohanMishra315

This comment was marked as off-topic.

@BenMcLean

This comment was marked as off-topic.

@zapoutix
Copy link

monogame / kni has webexport and c# is fully supported

@abbychau
Copy link

abbychau commented Oct 16, 2024

monogame / kni has webexport and c# is fully supported

it is thanks to XNA 4.
but godot and even monogame are highly unlikely to import XNA to their dev branches.

@jolexxa
Copy link
Contributor

jolexxa commented Oct 22, 2024

Curious to get Godot lead weigh-in on the latest comment on the .NET-related thread (see here: dotnet/runtime#75257 (comment))

I think the Godot-as-library route is probably the best route for that engine, not just for WASM but also for more robust iOS/Android support and likely console support as well.

@akien-mga I remember that Godot-as-a-library was kind of a no-go option when we all discussed this on a call — is that still the case?

@Delsin-Yu
Copy link
Contributor

@jolexxa
What we have for Godot right now is the option to either launch the hostfxr and use that to load the managed C# DLL or directly load the unmanaged DLL produced by NativeAOT.

Both ways are Loading C# modules from the native side; I don't recall if we have hostfxr in WASM or if the NativeAOT supports producing WASM modules. These are the major blockers for Web support.

You may launch a Godot instance through project libgodot with C# web application; after all, project libgodot is just an unmanaged DLL that we can DLLImport or LibraryImport and execute; however, currently, there is no way for the host C# application to serve as the C# part (aka GodotSharp) as the built-in mono module.

Suppose we are really planning to leverage the project libgodot as the C# Web export solution. In that case, we need to punch a hole in the engine to pass the C# entry point function InitializeFromGameProject into the initialization function of libgodot libgodot_create_godot_instance, which the mono module then looks up for as the third alternative to connect to the C# environment. (Sounds like a mess)

@Calinou Calinou changed the title Web platform exports are not supported when using the C# (.NET) version of the engine Readd support for web platform exports when using the C# (.NET) version of the engine Nov 4, 2024
@FlooferLand
Copy link
Contributor

(Sounds like a mess)

While I'm not an engine contributor, I'd argue having an inadequate yet functional web export implementation would be better than having none at all for 1-3 more years.
There's been little to no activity from upstream for the past 2 years other than people complaining and a dotnet org member moving it from being planned in .NET 8, to .NET 9, to then potentially .NET 10 and beyond (future milestone)
Sometimes workarounds are unfortunately required, and it doesn't necessarily mean an unsafe messy implementation.
That past bounty someone made was also raised to $500 so there is also that

@jolexxa
Copy link
Contributor

jolexxa commented Nov 19, 2024

Couldn't agree more with @FlooferLand — added something to the bounty that was started above (now at $650).

mcjill added a commit to mcjill/godot that referenced this issue Nov 21, 2024
Adds initial support for exporting C# Godot projects to WebAssembly:
- Implements WebAssembly runtime integration
- Adds export template system
- Creates build tooling for WASM compilation
- Adds test project for verification

Fixes godotengine#70796
@Spycemyster
Copy link
Contributor

Spycemyster commented Nov 26, 2024

I remember hearing talks about transforming .NET Godot into a GDExtension-style support, where .NET code is compiled and turned into GDExtension libraries that can be loaded and used in-engine and referenced via GDScript. Something to point out is that I noticed that the Godot-Rust project has added experimental web support last year: godot-rust/gdext#493. I've personally written a small game project with it, exported it to web, and it works fine. Wondering if this is a possible avenue worth investigating or if this is already what's being tried with LibGodot support?

Also, I added $50 to the ongoing bounty, as of writing this the entire bounty stands at $970

@Delsin-Yu
Copy link
Contributor

@Spycemyster

Wondering if this is a possible avenue worth investigating or if this is already what's being tried with LibGodot support?

The underlying technique connecting the .Net and the Godot Engine is the same, so what we can't do in GodotSharp (the mono module) also applies to the new GDExtension-based binding.

@raulsntos
Copy link
Member

Hello folks, we wanted to update you on the current state of C# web exports. We know there's a lot of people interested in exporting their C# games to the web platform, and we'd love to add support as soon as possible. Unfortunately, there are a number of challenges that have to be solved first and we haven't been able to find a good way to do it.

We've been exploring multiple ways of getting C# web export support, each of them have their own strengths and weaknesses, I'll try to explain what we've tried and why it didn't work.

dotnet.js

This is the most straight-forward way to get run C# on the web platform today. You can just publish a C# project using the browser-wasm runtime identifier and you'll get a WASM and the dotnet.js file ready to deploy. All you have to do is load dotnet.js from your HTML and initialize the runtime.

import { dotnet, exit } from './_framework/dotnet.js';

try {
    const { getAssemblyExports, getConfig } = await dotnet.create();

    const config = getConfig();
    const exports = await getAssemblyExports(config.mainAssemblyName);

    exports.Greeter.SayHello();
} catch (err) {
    exit(2, err);
}

It's very simple, and since we let dotnet.js initialize the .NET runtime we can rest assured that everything is setup properly. It would require very few changes on our side.

Why this didn't work

Every WASM is executed isolated on its own reserved memory, so loading the Godot WASM and the C# WASM separately means they can't communicate with each other.

The only way for WASMs to interact with each other is to link them, and that requires all the WASM libraries to be compiled with compatible flags. In this case, the WASM file built by .NET and the Godot WASM are built with incompatible flags. But what if we built the .NET WASM ourselves with the right flags? See the NativeAOT-LLVM section below.

NativeAOT-LLVM

There is a promising runtime experiment in the dotnet/runtimelab repo that adds support for building a WASM using NativeAOT.

Godot already supports loading C# using NativeAOT, so the changes required to make this work should be minimal.

The reason why this is a very promising option is that, since NativeAOT means you are using native compilers, you get a chance to set custom flags to use in that native compilation. This would allow us to ensure the WASM built for the C# project matches the flags used to build the Godot WASM, and thus make it compatible.

Why this didn't work

Unfortunately, adding the -sSIDE_MODULE=2 flag to the WASM compilation wasn't enough to make this work. There are other libraries linked that don't seem to have compatible flags, so the compilation fails. Here's an example of one of the errors we get:

wasm-ld : error : $HOME/.nuget/packages/runtime.browser-wasm.microsoft.dotnet.ilcompiler.llvm/10.0.0-alpha.1.24568.1/sdk/libbootstrapperdll.o: relocation R_WASM_TABLE_INDEX_SLEB cannot be used against symbol `__managed__Startup`; recompile with -fPIC

The -fPIC flag is also one of the flags set by -sSIDE_MODULE=2, which means it's required that the linked library is compiled with that flag. Unfortunately, it doesn't seem to be the case.

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.

Statically linking Mono

Since dynamically linking WASMs won't work, we could try statically linking Mono instead. This is the worse approach we tried by far, we ended up duplicating a lot of the setup in the .NET runtime to compile the WASM, it'd be a lot of work to maintain this and keep it in sync with upstream, not to mention supporting multiple .NET versions, since we don't know what TFM the user project targets at the time of building the Godot templates.

Why this didn't work

Godot's C# bindings rely on function pointers to communicate with the engine. However, when we set this up we were unable to get Mono to retrieve function pointers. It seems, Mono has a mechanism to build a table of function pointers at compile time so it can retrieve them later, but we were unable to get this to work.

We also tried MonoAOT, but since GodotSharp doesn't support trimming, it seems this assembly is too big and won't compile.

This approach would be very brittle and hard to maintain, but I was willing to give it a try so we could at least get some experimental support to at least unblock the users that have been patiently waiting. Unfortunately, it didn't pan out.

Conclusion

We are sorry to say that web support is still not available for C# projects. We know this is disappointing to hear, but we are constantly looking at new ideas and would love to get this working as soon as we can.

@Delsin-Yu
Copy link
Contributor

In this case, the WASM file built by .NET and the Godot WASM are built with incompatible flags. But what if we built the .NET WASM ourselves with the right flags? ...

Can we compile the Godot WASM with flags that match the dotnet WASM? I apologize for my lack of knowledge of WASM technology, which might make this question sound silly.

@raulsntos
Copy link
Member

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.

@Delsin-Yu
Copy link
Contributor

Delsin-Yu commented Dec 10, 2024

but it doesn't matter because the dotnet WASM is not compiled with either of them so it doesn't support dynamic linking.

Thanks for the clarification. So, to overly simplify the concept, does that mean the dotnet Wasm itself cannot be linked to or linked to any other Wasm module?
Now I'm curious why this was never an issue for the Blazer Wasm users. Is it true that they never use Wasm side modules?

I'm also curious about how Avalonia achieved its web export, considering that they use SkiaSharp, the Managed wrapper for a native library, for rendering. Or are they?

@iistarion
Copy link

NativeAOT-LLVM

...

Why this didn't work

Unfortunately, adding the -sSIDE_MODULE=2 flag to the WASM compilation wasn't enough to make this work. There are other libraries linked that don't seem to have compatible flags, so the compilation fails. Here's an example of one of the errors we get:

wasm-ld : error : $HOME/.nuget/packages/runtime.browser-wasm.microsoft.dotnet.ilcompiler.llvm/10.0.0-alpha.1.24568.1/sdk/libbootstrapperdll.o: relocation R_WASM_TABLE_INDEX_SLEB cannot be used against symbol `__managed__Startup`; recompile with -fPIC

The -fPIC flag is also one of the flags set by -sSIDE_MODULE=2, which means it's required that the linked library is compiled with that flag. Unfortunately, it doesn't seem to be the case.

@raulsntos, is there a repository available where we can reproduce this scenario?

@raulsntos
Copy link
Member

Now I'm curious why this was never an issue for the Blazer Wasm users. Is it true that they never use Wasm side modules?

Side modules is for dynamic linking, they may be statically linking dependencies. But that also has some requirements, the WASM you're linking needs to be relocatable.

NativeAOT-LLVM

is there a repository available where we can reproduce this scenario?

No, just build a Godot project with NativeAOT-LLVM. See instructions in their documentation.

Here's an example .csproj:

<Project Sdk="Godot.NET.Sdk/4.4.0-dev">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <EnableDynamicLoading>true</EnableDynamicLoading>
  </PropertyGroup>

  <PropertyGroup>
    <PublishTrimmed>true</PublishTrimmed>
    <SelfContained>true</SelfContained>
    <MSBuildEnableWorkloadResolver>false</MSBuildEnableWorkloadResolver>
  </PropertyGroup>

  <ItemGroup Label="NativeAOT-LLVM browser-wasm packages">
    <PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-*" />
    <PackageReference Include="runtime.$(NETCoreSdkPortableRuntimeIdentifier).Microsoft.DotNet.ILCompiler.LLVM" Version="10.0.0-*" />
  </ItemGroup>

  <ItemGroup>
    <TrimmerRootAssembly Include="GodotSharp" />
    <TrimmerRootAssembly Include="$(TargetName)" />
  </ItemGroup>

  <ItemGroup Label="NativeAOT-LLVM browser-wasm linker args">
    <LinkerArg Include="-sSIDE_MODULE=2" />
  </ItemGroup>
</Project>

Then use this command to build:

dotnet publish -r browser-wasm -c ExportRelease

@Delsin-Yu
Copy link
Contributor

the WASM you're linking needs to be relocatable

I guess this implies that the Godot Wasm can't be relocatable and hence cannot be statically linked to the Dotnet user Wasm?

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

Successfully merging a pull request may close this issue.