godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Add support for multiple .NET languages to have "built-in"-like support. F#, Visual Basic, Etc. #191

Open willnationsdev opened 4 years ago

willnationsdev commented 4 years ago

Describe the project you are working on: Plugins and a mobile app that uses .NET.

Describe the problem or limitation you are having in your project: Using non-C# .NET languages in Godot is cumbersome since you have to create C# scripts anyway and then have C# classes inherit a third-party class's features. This is what the Godot F# Tools plugin I wrote assists with. However, I would prefer it if it were easier to add support for arbitrary .NET languages that build on the features in the current CSharpScript implementation.

For example, maybe have a MonoScript that acts as another layer on top of Script and then have more specific CSharpScript, and potentially FSharpScript or TypeScript, implementations in submodules. This would allow other languages to take advantage of some of the GDMonoObject work that has already been done. Even if support for other languages had to be downloaded via the AssetLibrary, I'd still think it could work very well. Though, I must admit, I know very little about the ramifications of dynamically loading in additional languages, but it sounds a lot like what the NativeScript submodule already kinda does.

Describe how this feature / enhancement will help you overcome this problem or limitation:

People who want to use their preferred .NET language to create Godot games would be able to do so much more easily, without having to hack support in through C#.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:

I would propose re-organizing the codebase to make CSharpScript files be in a dedicated submodule folder within the mono folder (at mono/csharpscript) and instead replace them with a set of MonoScript-like files. Then provide avenues for plugging in other arbitrary MonoScripts, operating similarly to PluginScript for the GDNative C bindings.

Inheritance hierarchy would look something like this:

- Script
    - MonoScript
        - CSharpScript (built-in)
        - FSharpScript (via addon), can reference .fs files, interops with same MonoScript API.
        - Etc. (via addon), can reference .xx files, interops with same MonoScript API.

Describe implementation detail for your proposal (in code), if possible:

This would involve refactoring a lot of the C# Mono code to remove direct dependencies of C# code and syntax.

Projects would need to be generated and managed from the dotnet cli, more than likely, rather than manually creating the files in Godot's Mono-related C++ code. It would make it easier to operate with an arbitrary language.

If this enhancement will not be used often, can it be worked around with a few lines of script?:

Involves direct changes to the mono module. Unrelated to scriptable changes.

Is there a reason why this should be core and not an add-on in the asset library?:

Involves direct changes to the mono module. Unrelated to scriptable changes.

zetashift commented 4 years ago

Does TypeScript support the .NET CLR as a target? Anyhow I'm all for this as I have a profound love for F# and using it as a scripting language; related issue here: https://github.com/godotengine/godot/issues/12337 where neikeq mentioned:

The plan is to rename CSharp ScriptLanguage/Script/ScriptInstance implementations to Mono and make them abstract classes. Language-specific implementations should derive from these (we would still only support C# officially).

However I'm not sure where the Godot team will find the time for refactoring as I think people really only care for C#.

willnationsdev commented 4 years ago

@zetashift Enabling people to use Godot with their preferred language has been a growing concern ever since 3.0 where GDNative and C# were first introduced. Until then it had just been GDScript and C++ (I don't even think 2.1 had VisualScript, but I could be wrong - never used it). The point being that now there are roughly a dozen+ languages that one could choose to use for Godot and the trend has been to continue making it possible for people to use the languages they want. The MonoScript concept (and #119 honestly) would go a long way towards that, so I think there is incentive there. But the real shame is that neikeq is the one who is most familiar with the C# codebase. Like, I think he does around 90% of the CSharpScript-related PRs. There aren't many people that can contribute and/or help with the refactor, so it's basically a bandwidth problem.

zetashift commented 4 years ago

@willnationsdev I wholeheartedly agree, neikeq is doing awesome work but does also almost all the Mono work alone. A MonoScript concept would be great, but I fear that a big refactor of the C# code or GDNative code will be postponed or delegated to the community, because the current solutions are ""just enough"" and other stuff might take priority.

So might this refactor be better for the 4.0 release?

willnationsdev commented 4 years ago

Oh, for sure. There's no refactoring happening in 3.2 (already in feature freeze, just bug fixes). But I also kinda doubt it would even get done for 4.0. The priority right now is probably going to be getting exports working for mobile/web if possible. And only when there is no more work to be done on those fronts might things get refactored.

willnationsdev commented 4 years ago

@ShalokShalom

You would appear to be writing off this community as one that does not respect the power and versatility of functional, declarative languages (correct me if I'm wrong). And I do not believe this to be an accurate assessment.

Godot has more or less been spearheading the effort of being a highly cross-language API for building content. This is evidenced by its GDNative C API and its inclusion of not just a domain-specific text language, but also C# .NET and a domain-specific visual language. There are even C bindings available for Haskell as a scripting language. So, if anything, the history of this project is evidence that the people here care about making Godot as flexible as possible. I think there's something like a dozen languages you can already use.

And it's not that you can't use F# either. Lars Kokemohr wrote a guide to using F# in Godot and I built on top of that to create F# tools to make it easier to generate the script boilerplate for the language. This Issue is just about making it easier to use F# since it is a functional language that could conceivably get out-of-the-box support.

What's more, neikeq, the lead .NET developer for Godot, has already mentioned that he has plans to refactor things to enable other .NET languages (as this Issue describes), but he just hasn't done it yet. Which makes sense since the priority should be getting exports working on as many platforms as possible first. I mainly created this proposal only to document and track the community's desire for the feature.

Calinou commented 4 years ago

@ShalokShalom @willnationsdev Please keep the discussion on-topic about the proposal :slightly_smiling_face:

aaronfranke commented 4 years ago

F#, TypeScript, Etc.

Note that if we ever migrate to .NET 5+ (aka .NET Core), the list of supported languages is more limited. AFAIK currently only 5 are supported: C#, F#, VB, PS Core, and raw IL.

panesofglass commented 4 years ago

Would it be possible to also have MonoScript support static classes and static members? @neikeq noted this in https://github.com/godotengine/godot/issues/12337, and I've noticed a lot of newer C# codebases and frameworks supporting this style.

zetashift commented 4 years ago

This proposal being open, does that mean it's accepted?

Calinou commented 4 years ago

@zetashift No, as we don't really have a formal proposal acceptance process.

Chaosus commented 3 years ago

The only problem I see to implement this feature is the level of support for these languages - For C# I feel only @neikeq and @aaronfranke are busy with it on a regular basis. Even if we add to support for these languages - who will fix bugs, adds new functionality, and update them to recent versions? I think we need new contributors to solve this proposal.

neikeq commented 3 years ago

The idea, at least for me, is not to support them officially but to provide the APIs to allow third-parties to make them work with close if not the same functionality as C#. Depending how much functionality they want, this can go from as easy as specifying different file extensions to more complex tasks. From our end it requires just a little initial work to provide the extensibility.

ShalokShalom commented 3 years ago

I highly welcome this initial step and contribute everything I can, in order to see 1A FSharp support.

So far as I can see, is also nothing in the way of in-editor support, other than the integration itself.

Llamato commented 2 years ago

I for one would really like to see vb.net in godot. Especially because for many people vb.net is still their frist language. By making Vb.net an option in Godot we would enable all those new developers to start game dev right away. What is more fun then that?

Additionally them starting out with Godot would mean that they will grow their Godot specific skills alongside their general programming skills. I see real potential to make godot more competitive with other engines by just allowing the userbase to expand. I am all for vb.net in godot. As of now I do not feel famillier enough with the engine to just try to develop the needed components myself but If others are interested in unoffical vb.net support, please let me know. I will be happy to help.

TheWitheredStriker commented 2 years ago

Seconded. I'm down for including F#, VB.NET and the rest of the CLI family in Godot.

Llamato commented 2 years ago

For anyone interested in my progress, I spent the last 2 hours setting gdot with mono support up and testing vb support though a dll. That approch works just fine. So to that extend we got VB.Net compatibility already.

I am however not satisfied with that as it is in my opinion more of a workaround then a solution. I think to say that Godot is truely vb.net / CLI compatible we need to at least be able to attach CLI script directy to nodes. As I said I am unfamillier with the engine but I am currently trying to figure out how to integrate Vb.net without having to resort to a dll. if anyone here knows more about how godot handles C# then I will happly accept any help I can get.

zetashift commented 2 years ago

Does Godot 4.0 and the migration to dotnet 6 change anything concerning this proposal?

KoB-Kirito commented 1 year ago

+1 for VB.Net support, it's a very readable language and easy to learn

For anyone interested in my progress, I spent the last 2 hours setting gdot with mono support up and testing vb support though a dll. That approch works just fine. So to that extend we got VB.Net compatibility already.

Did you make any progress since then? Could you explain how to set it up in more detail?

ShalokShalom commented 1 year ago

The F# Discord has a thread about the ongoing effort to get this running

https://discord.com/channels/196693847965696000/1021127955579150427

TheWitheredStriker commented 1 year ago

Awesome to see that there's a concerted effort for F# as we speak. =)

I would like to vouch for VB.NET as well, thus I am in agreement with @KoB-Kirito. @Llamato Indeed, can you elaborate?

lenscas commented 1 year ago

Awesome to see that there's a concerted effort for F# as we speak. =)

I would like to vouch for VB.NET as well, thus I am in agreement with @KoB-Kirito. @Llamato Indeed, can you elaborate?

For F# we decided to make our own glue through Myriad. I think that every .NET language will have to basically make their own glue or get C#'s source generators working natively with said language.

Alternatively, the source generator approach gets replaced by some kind of code generation that works regardless of language, however while this would make things easier for other languages I am actually not convinced it would make things better.

As things stand, yes it means that every language will have to spend time creating their own glue generation but on the flip side it also means that every language is able to tailor this generation step as well as the glue that gets generated based on what fits their language the best. For example, for F# we are focusing on a module first approach rather than class based. Once that is done we will also experiment with special glue for Discriminated unions and Records, something that never worked with the old methods and probably would also never work if we kept piggybanking on Godots .NET glue.

Once that is done, and assuming everything goes somewhat to plan this should allow F# devs to write F# code that is much closer to what is idiomatic F# rather than C# with F# syntax like how it was in the 3.X days of Godot.

So, all in all I see the change to source generators as a step in the right direction for overall .NET support despite it making it harder for languages to piggybank on existing infrastructure.

One thing that annoys/worries me still is the hard need for .cs files (and a csproj file?). It would be lovely if there was a nice way for .NET language glue code to expand the file extensions list or similar so the hard dependency on .cs files and the csproj file stops being a thing.

However I don't have a good way to improve that.

Pac-Dessert1436 commented 2 months ago

It's such a long story when I have been trying to work on Visual Basic .NET in Godot 3.5. Take my previous game project Avoid the Monsters as an example, the following async method just won't run on my Android phone, even though I've already equipped the project with "Microsoft.VisualBasic.Core.dll"!

Public Async Sub ShowGameOver()
    ShowMessage("End of Game")
    Dim messageTimer = GetNode(Of Timer)("MessageTimer")
    Await ToSignal(messageTimer, "timeout")
    Dim message = GetNode(Of Label)("Message")
    message.Text = "Avoid the
Monsters!"
    message.Show()
    Await Tosignal(GetTree().CreateTimer(1), "timeout")
    GetNode(Of Button)("StartButton").Show()
End Sub

For this reason, I would have to make the above subroutine a MustOverride Sub, and then re-implement the subroutine in the corresponding C# script:

using Godot;
using VBLibrary.AvoidTheMonsters;

public class HUD : HeadUpDisplayVB
{
    public override async void ShowGameOver()
    {
        ShowMessage("End of Game");
        var messageTimer = GetNode<Timer>("MessageTimer");
        await ToSignal(messageTimer, "timeout");
        var message = GetNode<Label>("Message");
        message.Text = "Avoid the\nMonsters!";
        message.Show();
        await ToSignal(GetTree().CreateTimer(1), "timeout");
        GetNode<Button>("StartButton").Show();
    }
}

It's not until last night that I could download the source code of Godot 3.5, but I've only learned a little C++ for the time being, so there's no doubt that I have difficulty modifying the C++ code in order to directly integrate "Microsoft.VisualBasic.Core.dll" into the entire engine. I could basically understand that the C++ code for the C# support aims at extracting C# keywords, calling the methods from C# , and so forth, but integrating this runtime library into Godot 3.5 is totally out of the question for my part, owing to my limited capability. So the current $64000 question is: Will anyone find an efficient way to integrate Visual Basic .NET into Godot 3.5 for mobile game development?

KoB-Kirito commented 2 months ago

Or in 4.3? It's so much better than 3.5 nowadays..

Pac-Dessert1436 commented 2 months ago

Or in 4.3? It's so much better than 3.5 nowadays..

Yes. I can't agree more with you when it comes to adding VB support to Godot 4.3, but speaking of mobile game development in Godot Engine, some of my opinions are slightly different from yours. Mobile exports using C# in Godot 4.2 are considered experimental nowadays, since the language version for scripting is C# 10. Godot 3.5 uses C# 7.3 for scripting, so it looks more stable for Android platform exports, but I'm not 100% sure whether it's really as stable as it seems...

Pac-Dessert1436 commented 3 weeks ago

Hello everyone. I've noticed that Godot 4.3 is available for the moment, and that I don't have to manually include the "Microsoft.VisualBasic.Core.dll" library on Godot 4.2 before exporting the VB.NET project to my Android phone. Therefore I can't wait to share with you what I have recently been working on, and I sincerely hope VB.NET bindings for Godot would come true, together with F# bindings.

I have aleady realized that there ought to be a Return ... statement as a modern way to return function values in VB.NET, but I insist that the "stone-age approach" should be made use of, just to make this part of code a little consise.

One more thing, I'm good at writing F# scripts as well, since I can easily define variables by means of let mutable statements, and simple F# functions like let squaredSum (a: float) (b: float) = pown a 2 + pown b 2.

Option Strict On
Imports Godot
Imports Godot.Collections

Public Module WorkingOnJsonFiles
    Public Function LoadJsonData(Of T)(jsonPath As String) As Dictionary(Of String, T)
        LoadJsonData = New Dictionary(Of String, T)
        ' The resulting dictionary is automatically returned after loading the JSON data.
        ' When the conversion is failed, an empty dictionary is returned instead.
        Using jsonFileObj = FileAccess.Open(jsonPath, FileAccess.ModeFlags.Read)
            If jsonFileObj IsNot Nothing Then
                Dim parseObj As [Variant] = Json.ParseString(jsonFileObj.GetAsText())
                Try
                    For Each entry In CType(parseObj, Dictionary(Of String, T))
                        LoadJsonData.Add(entry.Key, entry.Value)
                    Next entry
                Catch
                End Try
            End If
        End Using
    End Function

    Public Sub UpdateJsonData(Of T)(jsonPath As String, jsonData As Dictionary(Of String, T))
        Using jsonFileObj = FileAccess.Open(jsonPath, FileAccess.ModeFlags.Write)
            jsonFileObj?.StoreString(Json.Stringify(jsonData, vbTab))
        End Using
    End Sub
End Module
willnationsdev commented 2 weeks ago

Since there's been questions/comments on this, I will mention (to the best of my very limited knowledge): (Note: I stopped pursuing this myself since I eventually became disillusioned with F# and grew to prefer C#)

In Godot 3 (I assume this is still the case), Godot proactively scanned the .cs files from the C# project and loaded them using Mono. The relationship was one of Godot determining for itself what information from the Mono runtime is relevant (which put the burden of implementation for class querying more heavily on Godot).

In Godot 4, it uses the more recent, cross-platform .NET runtime(s) instead (dotnet) and instead delegates the information-gathering task to the CLR in order to know which defined classes, if any, extend Godot types. The relationship is one of Godot querying the CLR while dotnet informs Godot of what is relevant (the burden of implementation for class querying is mostly shifted to dotnet).

Thus, in theory, Godot 4 should already be able to have you define F# or VB classes recognizable to Godot Engine so long as they extend the established Godot classes and the classes are publicly visible from the assemblies in the same way (as in, the F#/VB assemblies are project references for the main C# project). If true, this ticket is largely resolved as you no longer need a C# class extending the custom class.

Beyond that, the only 2 things that could be done would be...

  1. Adding the ability for the "main" .NET project to be something other than a .csproj file.
    • Difficult? idk. Worth the maintenance effort? Probably not.
  2. Adding the ability for Godot binding features to work on classes defined by other languages. This would refer to anything that the C# source generators are used to supplement the code in order to make things work with Godot. You'd have to implement these same features in the other languages in order to "support" them fully.
    • This seems largely impractical to me since it would be a HUGE maintenance burden on the Godot team. I also do not know to what degree it would even be possible (maybe with F# type providers supplementing whatever the C# source generators provide; idk if VB has something similar).
Pac-Dessert1436 commented 1 week ago

Since there's been questions/comments on this, I will mention (to the best of my very limited knowledge): (Note: I stopped pursuing this myself since I eventually became disillusioned with F# and grew to prefer C#)

In Godot 3 (I assume this is still the case), Godot proactively scanned the .cs files from the C# project and loaded them using Mono. The relationship was one of Godot determining for itself what information from the Mono runtime is relevant (which put the burden of implementation for class querying more heavily on Godot).

In Godot 4, it uses the more recent, cross-platform .NET runtime(s) instead (dotnet) and instead delegates the information-gathering task to the CLR in order to know which defined classes, if any, extend Godot types. The relationship is one of Godot querying the CLR while dotnet informs Godot of what is relevant (the burden of implementation for class querying is mostly shifted to dotnet).

Thus, in theory, Godot 4 should already be able to have you define F# or VB classes recognizable to Godot Engine so long as they extend the established Godot classes and the classes are publicly visible from the assemblies in the same way (as in, the F#/VB assemblies are project references for the main C# project). If true, this ticket is largely resolved as you no longer need a C# class extending the custom class.

Beyond that, the only 2 things that could be done would be...

  1. Adding the ability for the "main" .NET project to be something other than a .csproj file.

    • Difficult? idk. Worth the maintenance effort? Probably not.
  2. Adding the ability for Godot binding features to work on classes defined by other languages. This would refer to anything that the C# source generators are used to supplement the code in order to make things work with Godot. You'd have to implement these same features in the other languages in order to "support" them fully.

    • This seems largely impractical to me since it would be a HUGE maintenance burden on the Godot team. I also do not know to what degree it would even be possible (maybe with F# type providers supplementing whatever the C# source generators provide; idk if VB has something similar).

Thank you so much for providing such detailed information for me. Turning your thoughts to C# isn't a big deal, since C# programming is out of the box in Godot 4, which I'm also good at. Meanwhile I can understand that there will be a tremendous amount of work for the Godot contributors when it comes to adding F# and VB.NET bindings, not to mention the fact that I'm not that capable of writing GDExtensions for these bindings (since I've only learned a little C++ for the time being). For my part, however, the most critical part is that the VB.NET source files should be recognized by Godot script resource, and that these source files can be easily attached to the Godot nodes like C# scripts.

Just now I tried writing "HelloWorld.vb" as follows, based on the VB.NET library that I've created for testing purposes (simply named TestLib). Nevertheless, after adding the project reference TestLib.vbproj into the corresponding .csproj file in a Godot 4 project of mine, the source file "HelloWorld.vb" ::doesn't:: show up in the Godot script resource, even though the C# project has been updated and equipped with the VB.NET project.

Imports Godot

Public Class HelloWorld
    Inherits Node2D

    Public Overrides Sub _Ready()
        GD.PrintRich("[rainbow]Hello world![/rainbow]")
    End Sub
End Class

Therefore, speaking of using VB.NET in Godot 4, I guess the second option for me is to write a large VB.NET module that contains useful variables, functions, algorithms etc. (which are almost everything needed for the specific game I'm making), compile the VB.NET module into a DLL, and then import the module by means of using static syntax when writing C# scripts for the game. As far as I'm concerned, nothing is better than such an "import-export" strategy without available VB.NET bindings, and using F# in Godot 4 might end up with the same approach.