#Godot and FSharp
1 messages ยท Page 2 of 1
What does reflection, that makes it disadvantaged here?
and isn't allowed on some targets (consoles, iphones, android(?))
generators can't even make use of it
you don't have a System.Type of the types you are working with
it also breaks AOT builds, so that isn't great either...
actually....
yeah?
you can ask the F# compiler to check an file and then you get typed AST back
and then you get a lot more information
Yeah, I saw that, but what Myriad has is simpler, and for what I do it works good enough
๐คท
I found the typed thing to be easier to work with
I did not really understand it at all, and did not want to bother too much
The examples posted here also seemed outdated
yea, the examples are not great ๐
But, unless you want to spit out code that uses reflection you kinda need to use it due to the "Needing to get a Variant.Type" thing
Hmm, oh yeah, my current approach won't work for complex types, so I have to check that later again
I started a bit at translating the C# code that does this check but didn't manage to complete that yet. I can push it if you want, should maybe also make it a bit easier to work with the TAST as there is then some (untested) code that compiles
If you want. I look at that after I got the complete output working for simple types first, though.
Thanks so much guys, for doing all this โ๐ป
I wish I could help more but Ive not even installed godot :-p
ast/tast/quotations/reflection is second nature though
The benefit to tast is its reflection friendly, quotations rely on reflection
You can get round that though with some judicious hacking ๐
reflection can be cached too, so generally fine for a generator, you dont want much reflection at runtime or repetedly called without any caching.
You can reconstruct the System.Type from the tast by using various methods depending on what type of type it is
You dont need to install it, it's an executable binary ๐
Well I havent even downloaded it then ๐
If i get some time I'll have a look at godot, its just tricky finding any time lately
Ah, I think I tried with the newest version of FSharp.Compiler.Service... but as long as it works
Hmm, for some reason the compiler can't find the FSharp.Compiler.Service assembly when trying to use the project as a nuget
oh joy >_<
It is listed as a dependency, but somehow it seems to at least not be available when Myriad runs.
well, at least it isn't a segfault
If that is still current, it seems the dependencies have to be copied into the package for Myriad? https://github.com/MoiraeSoftware/myriad/issues/39
Okay, copying the files manually works, but we need to find how to do that automatically at some point
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> ?
Tried, did nothing differently
just put it in every .fsproj and .csproj file
then sooner or later you have the correct one :P
I only have one fsproj for the nuget ^^
alternately you could likely add a function to AssemblyLoadContext.Default.add_Resolving to supply the FSharp.Compiler.Service assembly
Unless it is to copy in the referencing project, not the generating one
yea, but maybe the fsproj/csproj file that loads this need that set? ๐คท
assuming FCS exists somewhere
One project in that issue above seems to use a build system (FAKE?) and instructions to copy dependencies, but we'd have to look into that... unless someone already has experience with that
/// Renames necessary files in the buildDir so they are ready to run
let renameInBuildDir buildDir publishDir =
let nativeDll = FileInfo.ofPath (Path.combine buildDir "SharpCells.XLLNE.dll")
// This path must match what is set in XllControl.fs
let xllFile = Path.combine publishDir "SharpCells.XLL.xll"
nativeDll.MoveTo(xllFile, true)
// SharpCells.Ribbon.comhost.dll expects a runtimeconfig.json of the same name
let runtimeConfig =
FileInfo.ofPath (Path.combine publishDir "SharpCells.XLL.runtimeconfig.json")
let runtimeRibbonPath =
Path.combine publishDir "SharpCells.Ribbon.runtimeconfig.json"
let _ = runtimeConfig.CopyTo(runtimeRibbonPath, true)
()
moving and copying files as part of a FAKE script
Nope, also no change. Well, for now it works copying manually, so I can at least test more
it's almost equivalent to using the System.IO classes
Well, I guess it is a good thing to look into FAKE at one point.
(afk for a while, just fyi)
FAKE is pretty easy but I found it best to keep it in a project rather than fsx files as they seem to recommend
would introducing FAKE in the project leak through to people that just want to use this library?
nah FAKE is purely build time
sure, I get that it is at build time
but that doesn't say much when talking about a library as it doesn't say which build time ๐
lots of F# projects use FAKE and it doesn't end up in their nugets
hmm maybe different as you are relying on Myriad at client build time
the other way would be to put a post-build task with MSBuild
post-build your lib or pre-build their lib
CopyLocalLockFileAssemblies works for me
Maybe the newer dotnet have broken it
Im on 6.0.202
In building and distributing Myraid I merge two nugets together due to tools assemblies having issues
Also makign sure you have the correct props file and import it when testing and local building helps with tests etc
Hows it going @mossy whale / @open dagger are you making much progress?
I had no time to work on it since my last message
@balmy bison Idk, I have checked, but the file still does not seem to be available when Myriad is running the generator.
I can manually specify to copy the files for a package... but I also would need to do that for each dependency
What version of dotnet? I can only think they broke something again
For runtime, or msbuild?
The project uses 6.0, though the output says that it uses the 7.0 binary to build
Use build tool: C:\Program Files\dotnet\sdk\7.0.202\MSBuild.dll
https://github.com/dotnet/fsharp/issues/14289 you might be running into this issue
Where it references System.Runtime 7 based on the SDK even though the project is 6
Hmm... when I try to specify a 6.0 msbuild using the ide, msbuild complains about not being able to find fsc.exe
Yeah only thing I found that works was uninstalling net 7 completely and keeping 6 or making the project 7. The latest comment suggests another workaround though
Yeah, I tried that last one. Did not fix it.
I'll see about using (or removing, it's not like I need it ) net 7
Anyway, here is the log from the build, maybe it helps finding another solution:
- 'd:\Users\Beliar\.nuget\packages\godot.fsharp.sourcegenerators\0.0.1\lib\net6.0\Godot.FSharp.SourceGenerators.dll'
OTHER: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
Could not load file or assembly 'FSharp.Compiler.Service, Version=41.0.7.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the specified file .
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.Assembly.GetTypes()
at Myriad.Implementation.findPlugins(String path) in D:\a\myriad\myriad\src\Myriad\Program.fs:line 22
at [email protected](String path)
at Myriad.Main.main(String[] argv) in D:\a\myriad\myriad\src\Myriad\Program.fs:line 136```
Uninstalling net 7 did not fix it
Do we think it is sensible, to share one common denominator container?
what?
^
dev container
So the development could be more fluid, future contributors would just download that, and not run into a ton of issues
Reproducible environments
There are containers with all SDKs, libraries and stuff, ready to develop
ah, you want a docker container.
Ideally that won't be needed and I kind of dislike developing it in a "pristine, carefully crafted" environment compared to the messy setups that people will actually use it in as it will have to run in those same environments as well (something that now seems to give problems)
I see the F# Discord now since quite a while, and "my environment doesn't work" is clearly the most common issue
And also for me, its hell of a pain to setup a new environment
For me containers are more for building the final binary or package
In combination with Godot, I think it's fine to combine both in one container, maybe with a presetup VSCode
Containers are for many things ๐
yea.... no...
we need to get this working on people's PC's without containers
Well, when considering development, not deployment
I could try to assemble something, it's maybe one of the few things I can see myself doing for this
the dev environment?
no one will want to use this if they suddenly need to grab docker or something
I mean for us, to work together
of course. I didn't mean that
that would be crazy
I think the current problems are related to using the thing correctly
Honestly, I think F# and specifically Ionide is far away from just working on everybody's computer
Particularly out of the box
๐คท
You guys are all using Linux?
No
Yes, sadly
ok
I have WSL
Also, Roslyn Source Generators/Analyzers have a similar problem when using nuget packages. One has to specify that files from there should be included so they can be found when running those. It is even mentioned in the official documentation.
The inline Roslyn msbuild code gen is a pain like that
I use that in myriad too for some msbuild gymnastics
Ionide has only intermittently worked when building myriad so I just use Rider
I re-opend the issue in Myriad anyway, if anyone wants to add an assembly resolver then I'll merge a PR.
I think unless it is possible to call nuget restore, or something then the only way is to have these files in the package
Though, these build plugins are not something I know anything about, so feel free to ignore my message
I guess dotnet would benefit from having something like build packages, similar to cargos (rust) build dependencies
I have some code I could contribute that tries to find dlls in the NuGet cache based on a deps.json if that would help?
I thought this was just a fails to build thing rather than runtime bllop
i.e. transient reference fails to copy to build directory
Thais was also an issue in F#4 years back, I rember addign a fix to build script generation for #r generation
Its annoying there are lots of various facets that make things just fiddly to do when it should be simple
Do you have the private attribute set?
<ProjectReference Include="../../src/Myriad.Plugins/Myriad.Plugins.fsproj" PrivateAssets="All" />
<ProjectReference Include="../Myriad.Plugins.Example1/Myriad.Plugins.Example1.fsproj" PrivateAssets="All" />
In the project that builds the nuget, or that uses it?
I have it in the generator project:
<PackageReference Include="FSharp.Compiler.Service" Version="41.0.7" PrivateAssets="all" />
I only have the one project
<ItemGroup>
<PackageReference Include="Myriad.Sdk" Version="0.5.1" />
<PackageReference Include="Myriad.Core" Version="0.5.1" />
<PackageReference Include="Myriad.Plugins" Version="0.5.1" />
</ItemGroup>
Consumer ^
I have 2 projects, one for the myriad generator plugin, which creates the nuget, and one that consumes that. The error is in the consumer project.
I dont think Myriad has a hard reference to FSharp.Compler.Service that comes in via Fantomas
Can Fantomas be used to get the same result as ?
[Go to message!](#1021127955579150427 message)
I mean, technically it should be possible as you have the AST which presumably is used to generate the TAST and stuff ๐
Ah, I see, Fantomas is just a formatter, or at the very least can't be used in the same way
Do I need something special for the attributes list of an Entity to be actually populated with attributes set on that type?
?
According to the results from the checker the types have no attributes, which is incorrect
Or I am just using it wrong, probably more likely
sorry, been a while since I worked on this. Not entirely sure what you are referring to ๐
It might be that I made a mistake somewhere though
when working on that commit I basically did no testing
I tried answer.ImplementationFile and the Declarations in it, which I can extract a list of FSharpEntity from, which match with the entities in the file, but none have the attribute that is set on them. Then I saw that answer.PartialAssemblySignature.Entities also is a list of FSharpEntity but same results.
Fantomas.Core new version 6 has a simplified AST called Oak
weird, not sure what is going on there then
The information from Myriad had these... but it would be suboptimal to have to use different parsers just because both have incomplete information
yea....
Well... it must be available somehow. I wonder what we are missing
๐คท
Hmm... I just tested by adding Serializable (because it is available from the framework) and the log actually writes that attribute from the list, just not the one defined by me... so the problem is something else
So, basically the code I wrote to get attributes work, just not for the custom attribute. I guess the checker needs information about that one...
maybe if we split the attributes into their own library?
just throwing random things at this wall ๐
Well, it is defined in another file. Maybe getting the project options from a single source file is not the best way... still looking for what is, though
I think GetProjectOptionsFromScript is really just for fsx files
There is this https://fsharp.github.io/fsharp-compiler-docs/fcs/project.html but not sure if there is not a better way to just read the fsproj
I am checking https://github.com/ionide/proj-info , maybe that helps
I seem to remember there was a project to read fsproj but it was discontinued as the possible contents of fsproj is too varied due to msbuild
Yeah, that is one I also found, but that was some years old, but this seems recent
Well, it works using the ionide proj-info package to read the project and get the options
parsing project info has always been an utter car crash.
Well, we get better results when having good project project options, and getting them from the actual project seems like the best way.
yep, thats the only way, its how tooling works.
yep, the easiest source of errors and breaks ionide every few sdk/f# versions
I start to think that reading the .dll and generating code based on that after the compile step is more sane ๐
Well, I almost get the same result as just with Myriad now, but with way less code.
Just convertManagedTypeToVariantType does not seem to work correctly yet. But that is for another time.
The tast and its quirks can be overwhelming, it took a few years of use before the null references were plastered over with options ๐
Ah, the problem was that I passed an abbreviated type definition
Yeah, they can be recursive too
Okay, union as godot resource is working (with simple types, others are untested) , at least the f# file, though the c# file just needs to be a skeleton calling the methods.
Hmm... if we want our generators to create the c# classes, we need to keep in mind that godot only supports one class per file, which also needs to be the same name as the file.
Though, we can use the name of the file passed through Myriad to infer which type the user wants to generate, if there are multiple possibilities.
Hmm... no, actually if it is in a nested module/namespace that still won't work
If it is a nested module then you can make a folder to represent that though, right?
Yeah, that is probably the only way
Okay, the way I would currently implement creating the c# files would be by just outputting them to a (customizable) folder (with subfolders for modules/namespaces) while/after creating the specific f# files, without having the user to specify where to put each file. Since the name of the file has to match the class anyway and c# does not care about order, I don't think this is a problem, and/or better anyway.
my personal preference for the time being would be to put them next to the F# file they belong to (put into a folder if the F# file does a module inside module thing) because for the time being the user still needs the C# file to hook everything up to Godot and the like.
Ah, I took the fact into consideration that it is not possible to have one project have f# and c# files (for building), but I can change the default folder to be just the project root
you can put the F# and C# project files next to each other without problems
True, but one still needs to add the C# files to a separate project for building, but the way godot projects are set up by default it should work anyway
why can't the files live in the C# project that gets directly linked to Godot?
They can, I just wrote it in a confusing manner again
Anyway, I'll just do it the way you described, with the user having the possibility to change the folder
๐
there is an issue open about needing C# files so maybe in the future we can remove this stuff.
I am not 100% sure about putting the c# files besides the f# file. There could be potential conflicts if, for whatever reason, there are types with the same name in the toplevel module/namespace in two different f# files (or 2 namespaces inside one file). With the godot constraints on the name of the c# file this can't be solved with just encoding the top level namespace in the file.
The easiest solution would to create folders for even the top level namespaces/modules of a file. The other might be to detect conflicts... but I am not even sure if that is possible given that the Myriad generators work on a per-file basis.
Or we encode the namespace in the c# class name using "_" (and name the c# file accordingly)
Which leads to bad file names, though
hmm... but shoving the C# files in some random file structure is also not exactly nice because that is how you interact with the engine
What if we adopt the same "1 exposed thing to Godot per file" thing? Would that help reduce conflicts?
Hmm... if we also have a "(exported) type name must match file name" constraint then it would work. We don't even need a namespace structure then.
So basically "If you want a type to be usable in godot you have to make separate file for it (until the godot dotnet loader is changed to allow multiple types)"
yep
Having to only handle one type would also have been easier...
Eh, I'll keep it as handling lists, but checking for it only being a single item.
Hmm... how can I tell Myriad that a certain file has nothing for a given Generator?
Or rather, how does one work with multiple Generators in Myriad generally?
๐คท
normally they look for attributes
but that happens in the generator itself
not sure if there is some nicer way of doing this
Yeah, but in the project one just says that a file is generated, but multiple generators could find attributes, or one could find none... and we can't error that one since that stops building completely
hmmm.... no idea
Hmm... okay that might not be a problem. For multiple all sources are added... so if none generate something that means the input file is wrong anyway
So, unless they generate something that conflicts that would not be a problem, I think?
sounds like it? ๐
I mean, that could only be if they use the same namespace/module as their first statement
And a namespace/module has to be the first statement in a file, and the generators have to work as if they generate for an empty file
I mean, we also could write a single generator for everything (with the different parts in separate files), and differentiate by what attribute is given (and error when there are multiple that would lead to a c# file being generated)
Actually, that might not be a bad idea - given how dotnet works in godot. I have to think a bit more about that.
So, what I am thinking is the following:
The generator has a list of sub generators (like one for Scripts and one (or two?) for Unions/Records as resources) that have to implement an interface that we specify.
That interface has two methods, one "Verify" that returns the number of Godot types that would be generated, and one "Generate" that does the generating (and returns the same Output that a Myriad generator does)
The generator will first run "Verify" on each generator and if there are more than one Godot types being generated it will error.
If that checks it it will run "Generate" on the single generator has a type to be generated.
I am unsure whether we want to pass the GeneratorContext from Myriad or the Tast (probably either the FSharpCheckFileResults or the FSharpImplementationFileContents) to the Generators.
Yea, sounds reasonable
And what do you think the generators should work with, the GeneratorContext (from Myriad), the FSharpCheckFileResults , the FSharpImplementationFileContents, or something else?
I don't know what is best
We need to be able to walk up the inheritance tree though
Well, with the GeneratorContext you can choose what to use to parse the file (AST, TAST, something else) but need to do more manually, the FSharpImplementationFileContents has information about the specific file and FSharpCheckFileResults also has related information about the checked file. FSharpImplementationFileContents and FSharpCheckFileResults are TAST.
FSharpImplementationFileContents can be obtained through FSharpCheckFileResults, but I am not sure if we need the other fields.
Not sure if it is the same version we use, but basically this:
FSharpCheckFileResults: https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-codeanalysis-fsharpcheckfileresults.html
FSharpImplementationFileContents: https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-symbols-fsharpimplementationfilecontents.html
So, I think for now I use GeneratorContext and write functions to get FSharpCheckFileResults and FSharpImplementationFileContents from it and we see later what is needed
Okay, I pushed the changes for the main Generator and interface to main in my repo
Okay, the generator to create resources from unions and records is now finished and merged
Hurray : ๐ฅณ
Hello guys, how is the state of the interop? How can I test in a project? What are the next steps and what can I do to help?
I am learning Godot and have some knowledge of F#, it isn't much but I want to help in what I can ๐
@solemn plover I dont know how much works, or how to set it up, this just seems to be the most up to date repo:
There is also a fork from lenscas, with one commit ahead, and six commits behind.
I.. haven't touched the project in too long ๐ Sorry about that.
IIRC I was working on making it work so actual classes could be generated for your nodes while Beliar worked on doing some resource stuff.
If anyone wants to take a stab on making the classes generate that would be huge
I am currently working on other godot related things, but after that I might look at it, if no one else did at that point.
Thanks ๐๐ป
Great!
This project should be used with the one that you create for your game? Or are you planning to put it with the ones made inside the engine?
I am not quite sure I understand what you mean
To use the Godot.FSharp.SourceGenerator, should I use the project as a project reference (or a NuGet package in the future), or it will be proposed to be added inside the engine itself, in Godot.Sdk (or some other .Net project inside the engine)?
F# isn't supported by Godot
so, though some changes to Godot might be merged to make this project nicer to work with I highly doubt that this project as a whole would get accepted to be included into Godot
Understood
so, I should reference the project in my own game?
would I still need to create the "C# glue" classes?
sadly, for the time being, yes
Until that is solved a stop gap is to generate those C# classes automatically like how one can do for Godot 3.X
Okay, I have rewritten the generator for nodes so that it generates the F# code for nodes based on the input.
The problem with SaveGodotObjectData and RestoreGodotObjectData remains, and I doubt that the PR will be merged, so idk what to do there
yea, no way it will be merged for 4.1, so, at best 4.2 I guess....
We can put a forked version of those generators on NuGet that isn't turned off the same way as the ones from Godot itself and then just ask people to turn the Godot source generators off and to use our version.
And maybe poke the devs a bit after 4.1 got released
I just found a problem with that approach. For the IDE using a different SDK from nuget will work, but the editor and templates will be using the bundled assemblies, which don't have that attribute. So, we either need to provide the whole editor and templates (for dotnet builds) or remove generating these functions - I don't really know where they are even used, they are never hit in a debugger.
Technically it is only needed for the generators, but I am not sure if it is possible to only include it in the generator/analyzer stage of Roslyn.
The only other way that might work is to have intermediate classes, that are in a separate package/project, for the c# classes to inherit from that only contain code for these special methods. This is technically not difficult but there needs to be one for every class that inherits from GodotObject.
you... don't have to replace the entire SDK though? Just turn the source generators off from the SDK in Godot (which can be done in the csproj file) and then import the forked version which just contains the forked source generators?
I mean, that is possible too if the code to disable the source generators is removed from the forked version.
Or this works too: https://stackoverflow.com/a/75858779
We then just need to name the fork different... which is easy
Okay, that seems to work. I just need to find where to move the definition of the attribute to, as it currently would be in the GodotSharp project. Luckily the source generator only needs to match the name, not the actual type.
https://www.nuget.org/packages/Godot.FSharp.SourceGenerators.CSharp/4.0.3
Not sure about the name, but this makes it easier to disable the default generator by name.

In the csharp project file one would then need to add the following:
<ItemGroup>
<Analyzer Remove="@(Analyzer)" Condition="'%(Filename)' == 'Godot.SourceGenerators'" />
</ItemGroup>
</Target>```
I think for 4.1 they added the other PR to disable generators for the whole project, so then that also should work.
What is missing for the object generator is creation of the C# files, and more testing.
Okay, C# files for the nodes are now also generated
Okay, after a bit of testing, there are some things that are not working correctly. One is that the generated code for some inputs is not correct and the variant type for objects (like Texture) is not correctly determined.
Okay, fixed the errors I found and the type for Objects is correctly determined with specialization for Nodes and Resources
Is there maybe some repo, I can point to, when mentioning the new implementation on here:
https://github.com/Beliar83/Godot.FSharp should be it
Thanks
hmm... what should be used as the hint path in the fsproj file so it can see godotsharp?
I'm an idiot, can just reference the nuget package nowadays 
In case someone is interested
GDQuest discontinues their lifetime plan
It's still available until the 15.Juli
Seems like nuget does not display the readme the same way that github does
Free and open-source new features demos: https://github.com/gdquest-demos/godot-4-new-features
Join our discord community: https://discord.gg/87NNb3Z
The Godot.FSharp.SourceGenerators.CSharp package has been updated for 4.1
Also while rewriting an old godot fsharp project I have found some bugs in the fsharp generators, which I am going to check out
Okay, fixed the bugs and uploaded a new package (pending validation).
The generated code should work for 4.0 and 4.1 as nothing 4.1 specific is generated at this point
Hmm, I think there was a problem with updating the package. I have found another bug anyway, so I first fix that.
Oh, there is still bug in the generated GetGodotMethodList() when there are no methods to add to the list. Though at worst godot prints an error
Folks, how tenable is the method described here? https://hamy.xyz/labs/2023-04-godot-4-script-fsharp
the thing that Beliar_83 worked on basically brings the godot 3 workflow back and ideally better than ever
so while the methods described there do work, you should probably check out the thing Beliar worked on :)
Sounds good
I think we basically do the same, but automatically generate the code that does the C# <-> F# stuff
Ah. makes sense.
And is this repo https://github.com/willnationsdev/godot-fsharp-tools outdated now?
It is only for Godot 3
The author said he is interested in contributing, once Godot 4 is settled on how it implements C#
And I know he is constantly busy
Ok. Yes he seems quite active and also very interested in integrating F# into Godot.
Yeah. I posted him the repo on his Discord
He works at the university and has a very tight schedule, but yeah, he is quite involved in Godot for a couple of years. ๐
Welcome @gilded geode by the way ๐
๐๐ป
Thank you and hello! I am still testing the waters here.
Lifeguards are here, watching the beach ๐๏ธ ๐
Anyone having a problem with this signature (inside a NodeSript) ?:
(state, 1) // 1 = Example for return value```
Interesting. StringName.op_Equality("methodname", &method) works in HasGodotClassMethod but not in InvokeGodotClassMethod
I think the Godot generators has the property and method names as static fields for a reason
Ah, I think that was rather because these two methods were not correctly called
I have pushed the fixes to the repo and uploaded 0.0.4 to nuget
I have looked at GlobalClass in 4.1 and while it generally would work if we add that attribute to the C# Class - adding it to F# type does not - it cannot be used for the "Any class inheriting from" constraint in godot hint strings, as the F# types do not (and can't) inherit from the generated C# class.
The main handling of the GlobalClass also seems to be done in C++ code. There is nothing generated in C# when adding that attribute.
oh, welp
GlobalClass was like, the only reason I wanted to update from 3.5 to 4.1
so... fun
I mean, you can still use it when you want it to appear in the "Create Node" list, but inheritance won't work correctly
I need it for resources 
Yeah, that is where I want it too
You can, for example, put a hint string of "Component" and it will allow only that specific global class but not any that inherits from the generated F# node, only from the generated C# node.
It would also be possible to create another F# and C# project for the base type and inherit from that... but that is suboptimal
Why don't you stay on 3.5 then?
considering that heavily to be honest
3.5 got a lot nice things backported and your project seems to fare the easiest this way
You are doing something entirely 2D related, so OpenGL and the old graphic stack generally will be enough
navigation didn't fully get backported though 
did they say why?
because doing it fully would break everything IIRC
so... this also means that if someone is say, using a nuget package that uses GlobalClass that it won't work, right?
@mossy whale Sorry, I explained incorrectly.
If you have a GlobalClass class, for example "Component", that inherits from Resource and another class that exports a field with that type in C#, the editor would only allow setting that field to an instance of "Component" or any GlobalClass class that inherits from Component.
For F# that is not working correctly as godot can only see the GlobalClass if that attribute is set on the C# node, and the generated F# types inherit from the base F# type, not the C# node, so they don't inherit from the C# node.
And it actually might work if we change how the types are generated, though I have to think a bit about that
Actually, it more likely might not work, but I'll have to try out things to be sure.
I don't really think there is a good way to do this
Sure. But it doesn't work because Godot does a bit of magic when it sees a file with that attribute, right?
So, if someone makes a C# library for Godot and pushes it onto nuget then Godot also doesn't see any global class attributes for that library, right?
I am off to work, will reply later
Ok
@mossy whale From what I got the CSharpScriptLanguage class in C++ calls a method in GodotPlugin to gather information about a script. GodotPlugin checks, through reflection, if the class has a non inherited GodotClass attribute and sets the "global_class" variable to true or false. When the engine calls "get_class_name" on CSharpScriptLanguage it returns the name of the C# class if it is a global class.
This should also work if the GlobalClass was defined in another assembly/package.
hmmm... so.... if the C# part depends on the F# project as a .DLL, that would work then?
I think so, though it might depend on what you actually mean
I have, for example, made a C# Project (did not want to go through F# for a class that is basically empty) with a single global class called "Component" which the F# project references and uses to inherit from.
Suboptimal, but it works
I wonder if we can write the whole dotnet side of GodotSharp in F# and use that as a replacement. We would not have to touch C++, but are bound the interface that is there. And it is still native interop, just only the dotnet side
considering I got a segfault when trying to use that inside Myriad, I.. fear we won't be able to 
didn't even really need it for anything Godot related. Just for some logic of what a type is...
Yeah, probably not, I don't really know too much about native interop
It also is not an easy thing to do, even if we just "copy" what is done in GodotSharp
I do find it weird that it going through .dll's is fine but through project references is not really?
Because even .dll's that are C# can't really register their classes, can they? As there are no files any more?
So, I find it weird that then works but our F# classes do not?
What happens if you compile the F# to a .dll first and depend on that instead of the fsproj file?
Sorry if I am missing something, just woke up 
Ah, the project also uses the Godot.NET sdk which generates the entry point for that assembly, and I guess godot looks looks for that for in every assembly... not quite sure.
Hmm, there is no iterator in gd_mono.cpp
so... we also need to somehow create an entry point?
It is something like this in the generated C#:
{
[UnmanagedCallersOnly(EntryPoint = "godotsharp_game_main_init")]
private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks,
IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
{
try
{
DllImportResolver dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
var coreApiAssembly = typeof(global::Godot.GodotObject).Assembly;
NativeLibrary.SetDllImportResolver(coreApiAssembly, dllImportResolver);
NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
ManagedCallbacks.Create(outManagedCallbacks);
ScriptManagerBridge.LookupScriptsInAssembly(typeof(global::GodotPlugins.Game.Main).Assembly);
return godot_bool.True;
}
catch (Exception e)
{
global::System.Console.Error.WriteLine(e);
return false.ToGodotBool();
}
}
}```
I think UnmanagedCallersOnly does not even work in F#
does that matter?
Not quite sure
it sounds like it is just there to prevent C# from calling it?
and in our case we probably have to have this file be the last in the fsproj list...
so.... kinda solved that way 
I think the compiler uses that to generated different ILASM, or something?
oh...
Or something do to with how the function is found from hostfxr
It might work without, but not sure
and... .NET has no way to patch DLL's after compiling, right?
Otherwise we could've just made a .DLL with just this piece of code and patch it into the .DLL that F# code got compiled to 
"Any method marked with System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute can be directly called from native code." but "This attribute is currently unsupported by the F# compiler. Applying it will not achieve its intended effect."
I don't think so, but not like I'd know
https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/#unmanagedcallersonly
I only partly understand that, though
Okay, I just did a quick test. If you have a Resource Type in another assembly you can't create an instance of that with the editor, but you can have a property that has that class as a Type and create instances of inherited classes defined in the main project.
ah, so basically libraries can only create abstract classes? (technically they aren't abstract but kinda act like those in the editor)
I think so
You also probably could create an instance through code too
This would work for the use case I have in mind, but not sure about others
yea, you should be able to. So it is a bit more powerful than an abstract class.
There is a 4.1 branch if you want to check it out, but I have not yet added generating the correct hint strings to the generators, but you can change the generated f# code to add that, for now.
Something like this properties.Add( Bridge.PropertyInfo( Variant.Type.Object, "Component", // Property name PropertyHint.ResourceType, "Component", // Global class name (LanguagePrimitives.EnumOfValue<_, _> 4102L), true ) )
hmm... worst case, would it be possible to emit our custom version of this file in the C# assembly that also sets it up for our F# code?
So, it does 2 assemblies instead of one?
Yeah, that may work.
A C# project that puts Avalonia in Godot https://github.com/MrJul/Estragonia
After having rewrote my old project I noticed some things with Myriad (or is it how we use it?):
- Editing a single file seems to cause every file to be regenerated
- Files are generated sequentially which increases the build time greatly on large projects
@balmy bison Can you help us?
Files are generated sequentially which increases the build time greatly on large projects
Doesn't totally surprise me and I don't think it would be a problem if
Editing a single file seems to cause every file to be regenerated
is fixed
Yeah
Oh, btw, I have found out that the entry point is only needed for the main project, for others they don't seem to be called.
oh
So, I am not entirely sure how the class in another project is found, though maybe the Bridge still can find it because the main project references the project?
Also, I wonder if FSharp.CompilerService can be used inside the Bridge to get information about FSharp types
That might be easier than rewriting the NativeInterop in F#... but it needs testing for viability
Hmm... it is also possible that the regeneration is done because of a change in the project structure
Hmmm that still doesn't sound great...
Can we store cache files somewhere?
Would that be faster?
maybe hash the input and include the hash as a comment in the output F#, then when regenerating check if the output has the hash in it
Hmm, I guess we can do, probably in some "." folder
That would also work but requires parsing those files at least a bit
I mean, nothing is stopping us to load files
In before it ends up being slower 
So, I'd say store the hashes in a key/value file
I'll create an issue and look into that, unless someone else wants ^^
Hmm, if I, through an AutoLoad, call ScriptManagerBridge.LookupScriptsInAssembly manually for the assembly of other projects the Classes are correctly registered
Well, except F#, but I think this is (also) because there is no loader for .fs files.
so... we need to make a loader for our F# files?
well, that is going to be fun /s
on the plus side, that should allow us to then drop C# file generation as a whole, right?
Yeah, IF it works
yea... and that is a big if
One thing is, that the Bridge looks for an AssemblyHasScripts attribute, with a list of the types, on the assembly, but this should be doable, I think
Hmm, the C# loader does not really do anything other than call something on the Bridge (which does things with the already registered Type, or create an empty), set the source text and return the script.
Hmm, doing some tests with just allowing "fs" for CSharpScripts and then using the Bridge to add a Node defined in F# it seems to be added correctly, displays properties, but they can't be edited. It could be just something how Godot finds methods.
I mean, outside of F# specific things the Types should be compatible, anyway.
are you working with a forked version of Godot?
I have it checkout out locally
ah, nice
And, Yes I know C++, but No, I'd like to stay away from it, unless necessary.
like any sane person :P
If it works we may just need a single LoadFSharpTypes() in an autoloaded C# script, so I am looking more into that.
nice
(and we also need to convince the Godot guys to accept your changes to the engine...)
Or write an FSharp loader (that inherits from the CSharp one) in dotnet, or as an extension (in rust ^^)
oh, that is also possible? Nice
It should be, I am just changing it in the Engine directly as just changing these lines is faster ^^
yea, I can imagine 
Ah, i forgot [<Tool>]
Well, first, we actually can't have a ResourceLoader for fs files, unless we kinda duplicate much of what the dotnet module does... but I have found out that godot does not care what actually is in the file - though it needs to exist for the class to be recognized. What is important is the type that has the ScriptPath attribute with the file.
If, for example an F# type has the attribute [<ScriptPath("res://MyNode.cs")>], and there exists a file - even an empty one - at that path godot will register the F# type as that script. The editor would show the wrong file contents, though, so it could not be edited in there.
So, kinda tricking godot into thinking it loaded a CSharpScript, even though it is not. It works because of how dotnet works.
That seems to be the only way to be able to use F# with Godot without having to write proxy classes in C#, that does not need us to pretty much reinvent what the current dotnet binding does.
so... if Godot doesn't care about the stuff inside of the file
would it then be possible to edit the kinds of files it looks for for C#?
to also include .fs files?
there are open issues about .NET support as a whole, so if we can demonstrate that we have a way to get F# working with only that one check being in the way of things then I think we have a pretty decent case on why that check should be editable in some way?
with editable I mean either in a setting somewhere or perhaps even better, have it be editable by code itself. Then projects that aim to add more language support through the .NET interface (like the F# thing you worked on) can just add their file extension to the check
Well, as Godot does not actually parse or compile the dotnet files, yes, the loaders are kinda only for the editor to show the source.
Now, for full support you want to have actually classes that inherit ScriptLanguage/ScriptLanguageExtension for the types, as otherwise the editor would try to reformat F# files like C# ones, and that does not go well.
Of course the base loading would be the same, so only specific formatting and syntax would have to be in these.
Of course, outside of modules, which need to be compiled into the engine, we can't inherit from CSharpScriptLanguage, as that class is not visible to extensions or GodotSharp.
Anyway, would it be okay for you if the F# generators are rewritten to take advantange of that?
sounds good to me
you have a lot more knowledge about how everything works, so I am just going to trust you :)
The other advantage is, that we don't have to care what the C# Generators would do, so it works with the default SDK as is.
we don't have to care
until someone wants to use both C# and F#, no?
Because then we run back into the fact that protected methods aren't a thing in F#?
ideally with some way for Godot's generators not being dumb 
or.. F# just biting the bullet and adding protected
actually, why doesn't F# have protected?
Can't remember
IIRC F# doesn't have protected because it encourages bad, OO-focused designs
Well, F# did other things just because it needs to be compatible with C# too
Although it is compatible, just not with the Godot generators
yeah, it can work with protected but not in a C#-F#-C# sandwich
any source generator that decides to emit protected and extends your types 
https://github.com/fsharp/fslang-suggestions/issues/157 This is "approved-in-principle", so maybe?
But that probably is still way off in the future
I also still don't know when SaveGodotObjectData and RestoreGodotObjectData are being called, they don't seem to be during normal operation
So, not sure if they are even absolutely needed
I think you can save some things to disk
Like resources
So.... I'd assume that that is when that happens?
Ah, that could make sense
Not sure when nodes are though
Might be related to the hot reload thing from godot
Or... Packed scรจnes?
Well, those are resources
if it's just a [<Protected>] attribute, maybe the code gen isn't too bad? I assume protected is an IL intrinsic to maybe the compiler change wouldn't be too onerous
Even if someone wants to use F# and C#, that can still be done by simply using dedicated nodes, I guess?
I mean you can mix and match this way, pretty much as you like?
the languages can't just directly interact with each other
which will still be a pretty big hurdle
good so ๐
I want to use Godot with FSharp
Okay, yeah, the functions are called when the assembly is reloaded in the editor.
There seems to be another problem with the assembly reloading. The type seems to not be registered after that, and I have yet to find out how fix that.
This would only be a problem in the editor, but still is not good
I think for this to fully work, godot would have to fully support having godot classes in different projects/assemblies
Though, if you don't mind having to remember to close the editor before rebuilding the solution, it would still work
And the only reason that it works now is because the autoload script is being called before godot is doing things with the registered types
So, the current solution is able to support fsharp in the build in editor?
You mean the on where it creates actual c# files? then, yes.
I mean, it supports reloading the assemblies
What also might work is just having the fsharp project as the assembly, with the things I tried today
Yeah, editing the code is another things
Do you think this will be possible?
I slightly remember how that would have to be implemented
Maybe I am capable doing that
But this was in Godot 3, no idea if they changed something about it
Technically yes but I am not sure about the details
Though the editor is pretty bad for anything that is not gdscript, or just small fixes, anyway
I usually hook VSCode to Godot in the settings, so that it opens, when I click on a script
Then I hover the VSCode window exactly over where the Godot inbuild editor is, usually
I just like, to edit the files within the context of Godot, it feels just right to me
Okay, if I change the project assembly in the godot project to the FSharp assembly it works even after rebuilding and reloading. So, outside of the protected thing, there is no general problem with loading Scripts from F#
So, I think what we need is a way to tell godot to also look in other assembly for Scripts, and then whoever wants to use godot with their dotnet language just has to set up the the things that godot is looking for.
Also, maybe be able to extend from a base "DotnetScriptLanguage" with a bare minimum of just having to override "getRecognizedExtensions"
Because the basic stuff for dotnet languages should be the same
Ah, there is already a bug for scripts from another project: https://github.com/godotengine/godot/issues/75352
Sorry I just noticed this, I imagine you have sorted it.
๐ ๐
Actually I havent, but good to know.
I was only joking, its just I havent looked at it, or F# in a good while
I just saw, that Rider has specific Godot support, like for Unreal and Unity.
Might be possible to simply use that, once fsharp does comply with Godot itself.
use that for what?
Developing? If it ever comes to that
sorry to off topic a bit here, but any reason why to go with Godot as opposed to something like MonoGame? ๐ค
curious as I've used Unity before, and was considering either trying to get Godot or Unity to work wwith F# but now I'm just veering towards learning MonoGame
monogame is just a framework rather than a fully fledged engine so it has less stuff builtin
True, I'm kind of oblivious to how much stuff is missing from MonoGame vs something like Unity, guess I'll just take the time and explore a bit ๐
I thought maybe of using something like Garnet and trying to make it work with Godot / Unity, since you'd just need to have a layer to interface between the C# / F# code, but not even sure where I'd start ๐ค
working properly with unity is going to be hard as the csproj file is full with hardcoded paths (a few hundred of them IIRC) and you are not supposed to put it nor the sln file in git.
you can get it to work but I doubt it will work with multiple people/multiple machines
oof, that sucks, MonoGame it is then wish me luck I guess
if you can split the fsproj into 2 or more files
One of which containing all the paths to unity's stuff
and the other everything else then it could work
@frank apex I did look at the available engines for FSharp, and found Godot personally to be the most balanced
Unreal 4 has a pretty good implementation, but it broke on the way to Unreal 5, and the engine seems to be suited for entire teams, and not single individuals anyway due to it's complexity
One thing, that could be interesting to you us FNA.
This is an accurate open source implementation of XNA 4.
MonoGame is it's successor, and some people say it's changes to the architecture are for the better and the worse.
FNA is a reimplementation of the Microsoft XNA Game Studio 4.0 Refresh libraries.
For me it is mostly that Godot has an editor that also can be extended by plugins.
So, I just got F# to work with Unity pretty flawlessly following a modified version of @balmy bison's tutorial
problem is no hot reload (https://hotreload.net/) ๐ข
what does the fsproj file look like?
Or rather, how are you referencing the unity stuff?
With an .fsx script you can create a References.props file with all unity references, then reference it in your .fsproj, then just copy the dlls over to Unity. I have to manually refresh the project folder by right clicking unfortunately for it to detect it, and it is a lot slower vs having hot reload with C#, but at least its F# ๐
using dotnet watch build and having vscode save when editor loses focus makes it a lot better as well
I'll put it in a repo, give me a sec
ah, so basically splitting the fsproj file
neat :)
Yup!
Here it is
https://github.com/vmenge/fsharp-in-unity/
What did you modify? Stuff changes from time to time in unity, unfortunatly making a new video takes a lot of time!
Nothing much really, just the path to copy the FSharp.Core.dll from, plus the script to generate all unity references.
What do you think about adding F# Script (fsx) Support to Godot instead/in addition to F#? I did some basic testing and it should work. It would need to be written as an extension, in C++ (which can be ported to Rust gdext, once at least one issue there is resolved), with probably most of the actual code in dotnet (to make calls to the F# compiler service/FSI). It would allow the issues we ran into to be resolved by it being an actual separate language, though we also need to implement the classes needed for that, but we have the F# compiler service/FSI to help with that. It would still use the dotnet version of Godot and the GodotSharp package, so we don't need to reimplement the base setup for dotnet.
yea, originally I was hoping that we could just piggybank off C#'s implementation and safe time on our end
but it sounds more and more that that isn't going to work out properly
Yeah, but since there is already an interpreter for fsx we can use, which can be called from code, it should not be too difficult. I just have only tested whether it could work at all.
@open dagger i'd be interested to follow you on this / lend a hand where i can. i'm not actively using godot right now but i've wanted to try and integrate FSI with godot after playing with the FCS APIs. i've done a bit of research on the new extensions system for v4 but wasn't sure how to make that work other than generating some C/C++ bindings on the fly maybe. i was hoping it might be possible to generate C# files from FSX scripts or f# projects and use the FCS API there but i haven't been following the .NET attempts you've already done closely
@wicked flare What I am currently trying to do is to implement FSX as an actual script language, which means implementing a ScriptLanguage, Script, ResourceSaver and ResourceLoader for it using FCS and FSI. As there does not seem to be really much in Documentation for those I am trying to figure it out by looking at the implementatiosn for GDScript and CSharpScript.
It has 2 parts: A gdextension written in C++ and a plugin written in C#/F#.
oh nice! i forgot about those layers/integration, i scanned some of the C# integration code a while ago to get an idea of what was going on under the hood and stumbled into some of that. i'm going to follow what you post and i'll share anything i find (tho currently i'm preoccupied with some webrtc stuff, working on some bindings + a little chat app for my resume while i'm between jobs)
what time zone are you if you don't mind me asking? i'm gmt -6/CDT
GMT + 2 / CEST
I was hoping I could use the already existing GodotSharp package inside the scripts, but it seems that, probably because of some other others things that I had to do to work around an issue due to how Godot loads assemblies, the calls from dotnet to native are not setup in the context of the script and fail.
I will try to see how difficult it actually is to write something similar (though it can probably be simpler for fsx) in C++, or maybe better in rust (with gdextension).
Hey! Not sure if interest died down here, but after the Unity debacle I ended up giving Godot another go. I tried Beliar's lib, but had a few issues and ended up just creating a generic script using reflection on _Ready. to load an F# script from an imported assembly that's referenced on the Godot's .csproj.
using System;
using System.Reflection;
using Godot;
static class Utils
{
public static fs.IActor? GetIActor(string? typeName, Node node)
{
try
{
if (typeName is null)
{
GD.PrintErr("FsFile must be set!");
return null;
}
var assembly = Assembly.Load("fs");
var type = assembly?.GetType(typeName);
if (type is null)
{
GD.PrintErr($"Failed loading type {typeName}");
return null;
}
object[] args = { node };
var actor = Activator.CreateInstance(type, args) as fs.IActor;
if (actor is null)
{
GD.PrintErr($"Failed creating instance for type {typeName}");
}
return actor;
}
catch (Exception e)
{
GD.PrintErr($"Error instantiating type {typeName}: {e.Message}");
return null;
}
}
}
using System;
using System.Reflection;
using Godot;
public partial class FChar2D : CharacterBody2D
{
[Export]
public string? FsFile { get; set; }
fs.IActor? actor;
public override void _Ready()
{
actor = Utils.GetIActor(FsFile, this);
}
public override void _Process(double delta)
{
actor?.Proc(delta);
}
}
With this I can just re-use FNodeName classes everywhere, setting the FsFile to the fully qualified class name.
F# classes simply implement the IActor interface, and take the corresponding node as single constructor arg. Been working without issues for me.
Not sure if I'll encounter any performance penalty later on unless I'm spawning a lot of things at once, but let's see I guess ๐
biggest downside is needing a separate class for each base node type (FNode for Node, FNode2D for Node2D, etc), but after that there is no need to touch C# code at all.
type IActor =
abstract member Proc: delta: float -> unit
type Player(node: CharacterBody2D) =
let speed = 200f
let getMoveVector () =
let x = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left")
let y = Input.GetActionStrength("move_down") - Input.GetActionStrength("move_up")
let vec = Vector2(x, y)
if vec.Length() > 0f then vec.Normalized() * speed else vec
interface IActor with
member _.Proc _ =
node.Velocity <- getMoveVector ()
node.MoveAndSlide() |> ignore
Hmm, interesting. I don't think you can make global classes using that, though?
I wonder if this would also make F# Support easier, but it probably is unlikely to be implemented for a quite some time:
https://github.com/godotengine/godot-proposals/issues/7895
wdym?
one thing I've been considering is just trying the render server directly with Garnet ECS (f# ECS)
One of the additions of 4.1 was that you can define "global classes", that is, classes that you can, for example, use to constraint lists in the editor to specific types, with the [GlobalClass] attribute.
And garnet is nice, yeah.
Which is also something I wanted to use together with global classes to just define components in the editor, but that did not work with how the fsharp generator was written.
oh wasn't aware of that, sounds neat! will take a look into how they work
Think a <@&457404552136622090> could pin the original message? Discord has made it a struggle to get to it without scrolling several eons.
Excellent! Thank you @pallid fossil ๐ฅณ
https://www.youtube.com/watch?v=kJK_lBk4qOk Is this video a good up-to-date / recommended source for using F# in Godot?
I almost got this working, tried today for about an hour. C# intellisense wasn't picking up on my F# stuff though, but my F# did build/compile, and did have access to Godot stuff, despite C# saying it wouldn't work
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Ello", "Ello\Ello\Ello.fsproj", "{61F61CA2-F869-4E8D-8779-94F05E0E1C3C}" EndProject
I noticed that some people's solution files have something along the lines of this
But mine doesn't. I have no clue how to get that long alphanumerical string
Are you using vscode? Unless things changed omnisharp pretends that F# doesn't exist
Oh crap... yes, I am using VSCode
And, am using Omnisharp
Is there a fix, besides switching IDEs?
Also, I fixed this by going into Visual Studio, and editing the .sln file there.
https://github.com/dotnet/vscode-csharp/issues/1623 ah crap, seems like it's been a longstanding issue. I wonder if it works with the C# devkit extension, but I wouldn't be surprised if it doesn't
If you tell omnisharp to decompile dependencies then it somewhat works (for me at least)
You have to reload the editor (or maybe just omnisharp if there is such an option) for it to pick up changes in your F# code. And going to a type brings you to the decompiled version rather than your F# code but.... At least it is something....
Reload the editor anytime I want to go access new F# code from C#? Yeah that's messed up. If it's that bad, that's reason enough to switch to Jetbrains IDe or VS
I mean..... there is a command to do it, you don't have to close and reopen the editor
but yes, it is not nice... >_<
Anyone know of a way to make these error messages not show in Godot? They are mildly annoying
Also, my experience with VS was bad too. Not as bad; I could at least get the C# to recognize the F# code whenever I built/compiled it. But, it was still bad because whenever I used f2 to rename my F# code, it doesn't update the C# code correspondingly it seems. Furthermore, if I open the C# code and try to update the names with f2 there, it didn't seem to work. So, I had to have both VS and VSCode open whenever I do refactorings...
A thread this long should be its own channel, or several different threads i think
I'd participate in a gamedev channel
I don't do gamedev but I find it interesting and would lurk in such a channel.
bump/necro, "worked for me"
though this is all it returns
going to be honest, don't look at that stuff. Look at the repo from Beliar_83
I'll do that too, I've been just scrambling these past few days for something usable ๐
so I was kinda hoping that it can be solved with just a simple resourceformatloader/resourceloader
yea, sadly that is a no.
Godot is too dependent on source generators for that and source generators are very much a C# only feature.
The repo from Beliar_83 gets as close as a "drop in" you are going to get but it requires fiddling a bit with the existing source generators to get them to play nice with the stuff Myriad generates.
There is a PR open IIRC to make them work out of the box but I don't think there was any progress there for a long time
Oh shoot there was a PR? Godot repo right?
(Also quick question after a lot of Ctrl+F-ing, signals are still iffy even with Beliar_83's generator, right?)
a PR to make the source generators behave with the Myriad stuff Beliar_83 implemented, yes
no idea. Have not used Godot in a long time
damn, I'll have to look even deeper into their PR list then ๐
aw shucks
thanks for the help though, much appreciated ๐
I think there is a .NET bug regarding signals in Godot right now though that prevents them from being properly cleaned up. Not sure about the details though
sounds even better
also tried the myriad generator quickly, not against the package in any way but I guess I'll stick to some simple libs at the moment
maybe a C# (for resources) -> F# -> C# (nodes+calling fs lib) sandwich will be okayish lmao
gotta see if Godot can handle multiple projects in any way
d a m n
and somehow I still think that Godot has better .NET integration than Unity.
Really shows how low that bar has gotten >_>
holy sh*t it works
i mean
it's 100% "hand-written" public partial whatev in the sub-project, so that's a pain point
at this point
"we" have Fable->Rust
and godot-rust
wink-wink (jk that would be extra-painful)
okay, got a "[importedTypePath] conflicts with imported type [importedTypePath]" warning but no issues
so uhh "update", that can be used for extra glue
eh, janky enough to set up but it works
so
C# project for resources
F# lib that has a node that inherits from said resource
C# lib that has a node that inherits from the F# resource
both the C# and F# lib refer to the Resource project
only cons: in this A<B<C inheritance, if I have a "top-level" export reference to type A
and give it a type C
I just get the following error:
E 0:00:00:0454 :0 @ System.Object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void* , System.Object ): System.InvalidCastException: Unable to cast object of type 'SandwichParent' to type 'ResourcesProject.ResourceAttempt'.
<C++ Error> System.InvalidCastException
<C++ Source> :0 @ System.Object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void* , System.Object )
<Stack Trace> :0 @ System.Object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void* , System.Object )
VariantUtils.generic.cs:385 @ T Godot.NativeInterop.VariantUtils.ConvertTo<T >(Godot.NativeInterop.godot_variant& )
OtherProjectCaller_ScriptProperties.generated.cs:13 @ Boolean OtherProjectCaller.SetGodotClassPropertyValue(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.godot_variant& )
CSharpInstanceBridge.cs:57 @ Godot.NativeInterop.godot_bool Godot.Bridge.CSharpInstanceBridge.Set(IntPtr , Godot.NativeInterop.godot_string_name* , Godot.NativeInterop.godot_variant* )
sorry for spamming this channel tho ^^"
don't worry about it
also this err's not for "plz troubleshoot", just some quick logging
I'm happy to see Godot + F# get some more attention
making an rts, gotta use whatever tools I can
and F#'s Array/List/any modules are imo a bit better than resorting to linq in "heavier" areas
even if I stopped using both the combination has potential to be good
It just will be too much effort and time for me to do anything with it 
or just accessing RenderingServer parts
yeah, it's mostly on godot-side .net contributions to actually make it work
but the error above is a huge bummer
the signals and their listeners worked perfectly
but any attempt to call method from the parent-parent-... type is no bueno
maybe I'll just have to limit the F# usage to not inheriting gd types or doing some sandwich inheritance thing
(why am I "wasting" time on this with a 2 week deadline for uni)
nope, that was C#'s bs, it auto-included the sub-projects folder
solved by a <Compile Remove..../> in the csproj
yep, that also solved this issue
guess it was just double-compiled so it tried to cast from A.NodeType to C.NodeType
love C#'s "implicitly include everything" style
@rain bough I don't know how much effort you are considering to put in experimenting F# -> Rust -> Godot, but any project which highlights how to write a crate in F# or a binding to a rust crate in F# and or rust is of great value to F# community
I'm interested in fable to rust for reaper extensibility myself (and due to lack of lua target, as this would be easier for me, than the native C api and the current rust crates for it)
Uhhhh I could only consider even attempting one (no prior rust knowledge) after the holiday season, but I guess I can try and see what works and how, both in F#->rust and just rust itself
But it would be definitely a different kind of funny to idk
Rewrite the dotnet/mono bindings of godot (not like I could do it) in rust
Coming from F#
So essentially a dotnet<->native binding written in dotnet
(Thinking about that, is it even possible to do something similar at least with NativeAOT? f# or c# doesn't matter)
there is no pressure to deliver a nuget that covers all of F# to Rust to Godot (which seems to be huge), just more "F# wrappers to Rust crate" code samples out there
with fable, it would be F# specific, no C# support for such nuget
as for doing AOT stuff that binds to C++, well supported for both C# and F#, if I understand you
I know, I just got a bit sidetracked by myself with "can Bob build it"
Yep, that one
It would be a few layers of either weird, cool or painful to (using godot as an example) write .NET<->native bindings in pure .NET
Practical? Doesn't sound like that
Technically possible? God I'd throw money at some mythbusters-level projects of these sorts
unless we are talking CPPProvider<"""#include "<godot/godot.hpp>" """> if you are aiming for dotnet community support, C# is probably better, but isn't there already this existing? and what is missing for AOT?
Naah, not a type provider but the other way around
Like "hey here's my nativeAOT module that tells you how to just call my stuff xoxo gossip girl"
So nothing missing in particular (afaik), just joking about what if "c/cpp glue to call dotnet code" could be written in dotnet
To see if there are multiple ways to do this stuff:
- good ol cpp like they do
- fable->rust+godot-rust (stability is another question)
- maybe some nativeaot thing?
Honestly wish I had the expertise+time to actually work on stuff like that
fable->rust if the godot rust story is stable, I think would be stable, assuming you do basic F#, the rust fable target seems to be well behaved, just needs more examples of bindings to crates IMO
and no managed stuff in the end result, which other AOT path, you still deal with GC and dotnet runtime bloat
didn't I see some figure of benchmark comparing F# AOT via rust vs dotnet recently?
keep in mind that some stuff that would be perfectly fine to do in F# <-> Godot will actually be UB once Rust gets involved.
This is because in Rust only a single &mut T can exist to any given T at any given time. This will include Godot's Node's
But what if (sorry for these)
Instead of a "we'll target godot through gd-rust" path
There'd be a way to only implement just the loaders/other gdextension stuff
So yeah it'd still need godot-rust
But instead of going with compiling all of our gd-related F# code to work through godot-rust
There would be just the "gd-mono-like" loader that runs through that module
If you need native callable exports from F# you can use https://github.com/AaronRobinsonMSFT/DNNE
so just a dotnet bootstrapper(? if that's a name that makes sense) instead of "every bit of game-specific logic"
that might work depending on how you do things and what the exact rules are that Rust has when it comes to objects from outside sources (in this case, Godot)
Yep, it generates C at compile time that bootstraps the .net runtime and native exports based on annotated F# functions
it'd essentially be a clone/rewrite of their current C# implementation though
yes, but Rust has other rules than C/C++
yep, their memory management is the one thing that always stopped me from learning it
(not bc i don't like it but bc it kicked me 100 times for good reason)
and I do not know what the rules exactly are when you start to mix those languages.
Like, I get that 2 &mut T's to the same object are a no go.
But what counts as "same object" if the object lives in C/C++?
Are 2 nodes that are gotten from a get_node() different objects? Even if they both go to the same node?
I, simply put just don't know
or there's the even worse nonexistent workaround for that: "just run it through a for a rust->cpp transpiler lmfao"
that actually won't work
breaking the rules means UB (or just not compiling, depending if we are talking pure safe code or unsafe code).
UB is both a problem at runtime and compile time
the rust fable target works well for this also, with repl c and cbindgen, and the right attributes in F# code
wondering: does unsafe helps enough with the rust rules not getting in the way of "I like UB and know what I'm doing"?
"I like ub and I know what I am doing" is not a thing that exists. Not even in C/C++ land.
People may think it exists but it doesn't
At best it means you are hard stuck with an exact version of the compiler with some exact settings and some prayers that your code will not break when you recompile it
Just add a unit test that the UB is still doing what you expect with each new compiler
Not just compiler changes but also every code change and even hardware change.
And technically, even the existence of that unit test may change the behaviour of the ub
Also, UB infects the callstack. As the compiler is allowed to assume that UB never happens it means that any path that would lead to UB also never happens
So, measuring the UB in one place doesn't mean that the UB will behave the exact same everywhere
It all depends on what the compiler exactly managed to do and how good it was able to analyse your code at any given point
Like I said, UB is not just a runtime thing like normal bugs
It also exists at compile time
Wait wait. Godot cant have C# nodes that use F# libs?
If so aw shit.. i was doing really well in a DDD approach i was doing
It can, just Nodes in F# are a Problem
Yea, that part i was aware of. But using C# as glue between godot and f# should be fine right?
Aye
Would it? I thought that the F# exports and stuff won't show up then?
Also, Update: After what felt like a year, but apparently was only 4 months, I came to the conclusion that I still don't know enough about Native Interop to do what I wanted - add F#/FSX as a script language to Godot, and I want to do something different for now.
I hope that the Godot devs do know that (and their Engine) better and the teased - not sure if work ever started on it - Dotnet (C#) Support through a GDExtension will make that possible.
Yea, the issue is that anything-F# (exports and stuff) are not recognized by godot
So if you want godot-visible types that are used from fs libs, you have to go with a C#-F#-C# project sandwich
Extra pros with some C#-side boilerplate is the ability to send signals from FS, since C# delegates are a bit funky on the F# side if you want to use nameof or something
Though it's weird that exports from an F# base are not visible even if it's on a C# child (class Cs : Fs case)
Also if you want to pass around F# types in signals, a good workaround is using https://github.com/pocketberserker/MessagePack.FSharpExtensions to just serialize those DUs and stuff, pass them to a signal and handle deserialization in signal handlers (I usually just slap an active recognizer on the paramlist of the handler if it's written in F# lol)
MessagePack Extensions for F#. / msgpack.org[F#] . Contribute to pocketberserker/MessagePack.FSharpExtensions development by creating an account on GitHub.
source generators don't run on F# code and they don't look at what is inherited, instead the generated methods just call the base.WhateverMethod() to get that information
Yeah, the current lack of source generator-F# "interop" is a bit of a bummer
Beliar_83 made an attempt with Myriad, I think it makes some stuff work but not everything (no global class for one)
Yeah, that is when I started trying to add F# as a script language, but the main Problem is not having a Library that I can use to call into godot. The one for C# requires special initialization from the engine (that is why it is a separate Download) and trying to use GDExtension it seems using Function Pointers through multiple DLLs (from Dotnet to a Shared Library to Godot) does not really work, or at least I don't know how that can work.
It might also work if someone knows how to get swig to work with classes that have several circular dependencies.
Because that was the closest I had it to working, I think.
https://github.com/godotengine/godot-proposals/issues/7895
I've been playing with GDExtension's C API a tiny bit and I think this route might be the right way to get better F# support for Godot. As far as I understand the proposal would be to create something akin to rust-godot or swift-godot by writing a C/C++ GDExtension to host dotnet and call into a .net DLL. It's a decent amount of work but I think with that route there wouldn't need to be any awkward C# code generation/C# only entry points for F# to deal with
Alternatively I was poking around the .NET integration code w/ Godot and it seems like right now Godot .NET works by using reflection on a DLL (who's path is specified in the project settings) to call an initialization method that does all of the classdb bindings/setup. From what I could tell there wasn't any reason you couldn't drop in a F# dll, but godot's project builds might get in the way of that. If C# is trying to move to a GDExtension based route anyways though probably better to go with the former option
I think whatever route gets used there's a need for a F# => ClassDB registration code generator like the existing C# source generator
No reason that wouldn't work. There are tools to generate C# from C headers to get all the struct definitions (I can't remember the names now but they are in this discord). C# is probably better at the lowest level anyway for a few language features like fixed buffers in structs and function pointers. As well as just reading more like the original C source.
You can use DNNE https://github.com/AaronRobinsonMSFT/DNNE to generate the C exports that Godot would call and the necessary code to host .NET. That works from F# or C#.
After that you'd want a wrapper to take the unmanaged structs to something more like idiomatic F#.
Yeah, basically I am waiting if and when that C# GDExtension is being implemented, though if someone with more knowledge of native interop wants to look at it, I won't stop them ^^
i was able to load + call GD.Print successfully by using the netcorehost API last night
i'm looking to see what i need to do to register a new class type
i'll post a link to a demo repo soon, gotta fix the hard coded paths first
i used Godot 4.2.1 (non-dotnet version), the dotnet version seemed to have issues with me loading another runtime
C# entry point that rust is calling
https://github.com/weebs/Godot.FSharp.Extension/blob/main/Godot.Extension/Class1.cs#L8
Oh yeah, they initialize the hostfxr "wrong", as in, they don't check for the "already inizialized" value.
@rain viper sorry for ping but I am guessing you might be interested in this thread :)
Yep, I had already found it ๐
ah, oops. Sorry 
Hello, I'm a mantainer of the Godot .NET integration and would like F# to be added to the list of community-maintained languages. Would you be interested in that? If so, I'd like to help you port your existing packages to the new GDExtension-based bindings. Feel free to ask any questions, and let me know of any issues that may come up during the process.
I have a sample project entirely in F# that you can see here: https://github.com/raulsntos/summator-fsharp
I'm not an F# developer so this is likely not idiomatic. I imagine you'll want to build F#-specific packages on top of the .NET bindings to add convenience, like Myriad generators or other fancy F# features.
I know I'd love to see easier integration with Godot ๐ I've been keeping an eye on the GDExtension w/ .NET stuff so it's good to hear you expressing interest in f#
i'll try to play around with the sample when i have some time, i know one thing i'd really like to see is a way to integrate the f# interactive repl for hot reloading (although that might not be necessary with the new gdextension setup?)
Just a heads up, since we don't have a module yet to load the .NET runtime with hostfxr, you'll need to build a native library with the [UnmanagedCallersOnly] attribute, but as far as I know F# doesn't support this. Maybe there's some other way to build a native library with F# and expose a C compatible method.
Regarding hot-reloading, I haven't implemented that yet in the new bindings and I'm not sure how it works, but I know there's an API for it.
just tried it out with a C# entry point and it all works for me, really exiting stuff. thanks for reaching out to us ๐
i had a hostfxr project handy and the Summator example works with that, i was also able to verify the F# repl api works with the hostfxr version
@frank apex gave @tidal mauve +1 reputation.
What's the current best way to use F# in Godot right now?
There seems to be a lot of conflicting information right now
depends on how you actually want to use it.
If you want to use F# as the only language, then Godot 3.X with that extension to automate the boilerplate is probably the "best"
if you just want to write some F# in combination with most of it being C#: then just make an F# library as normal and keep the amount of Godot code in F# minimal
With Godot 4.2.x, are there any tools for using F# with boilerplate?
sorry, I don't know of any
looking through the thread, is there any update on Godot supporting F# nativly like it does with C#?
Does this mean we get F# support in Godot 4.3?
@strong cipher No, this means that when the new .NET integration is out (which will definitely not be in 4.3), the F# community will likely have an easier path to provide support, and I'd be happy to help in that effort.
I just tried that, and it does actually seem to work, even with F#. Maybe only for AOT, though, but that is the main point here
I should add that the F# Compiler/IDE still produces the warning, but it seems that for AOT it can be ignored/disabled.
so [UnmanagedCallersOnly] is working in F# w/ AOT for you? really cool to know if that's true
it might be that UnmanagedCallersOnly "just works" provided the arguments were all already unmanaged
I am not sure how it works. I was looking into the possibility of adjusting the IL code to get the same result as in C#, when I noticed that it actually is the same. It probably is best to look more into and/or at least have it verified as working by someone else.
I'm using that attribute and ignoring the warnings in F# for a different project and it works. But I'm also generating the C API that gets called from native code using the DNNE library
Regarding the new .NET support, do you guys have any plans to extend the Signal attribute's support in some way? With something like an optional typeof(ClassName) param or usability on Event types/some way to create a custom attribute or something
Since all the [Signal] attribute does is just be a marker for the source generators, you should be able to create your own attributes and source generators that generate the appropriate registration code, or even write the registration code manually. The registration code with the new GodotBridge is very simple, so writing source generators should be much easier than before.
Hi, I am looking at godot for ui. I already F# code and want to hook that api to events for the ui. Did this by creating a F# lib and create base F# node types/classes there. The signals are define in the original partials root class (C#).
I couldn't find much info online besides reading this channel. I would like to know if there is a better way atm also should I create my own attribute for F# signals and will those be compatible with records?
For records and unions you should serialize them to a byte array, since Godot can't deal with those by default (using MessagePack.FSharp for that) and then deserialize on the receiving end
Either this, a dictionary or a wrapper class for these records which is more work than its worth
And also looking for a better way, I'm currently defining a base interface for everything I'd use in F#, and use my "API" with those (and native godot types) and implementing them on the C# side
Aaand the signals are exposed as observables in those interfaces since I've ran onto some inconsistent issues with implementing interface events, which results in a ton of boilerplate (not sure if it's a "right way" atm)
Thanks for the info.I might pause the F# godot since it seems like there is a lot of extra glue. But I will have a try later this weekend.
Eh, there's a lot of glue but it could be manageable, I'm also thinking of pausing the F# part tho
It's essentially a waiting game of "who'll write the codegen for it" atm to skip the boilerplate, but then there should be a generally agreed-upon path to pick for it
Since some people would like to possibly go with records and fp-heavy godot code, others would like an "it just works" way even if it results in imperative/oop F# code so uhhhhh
Yeah
Personally I'm waiting for the new GodotBridge which has been mentioned above, and some motivation to look into codegen-related topics
I had a look at Godot recently and it seems to suffer from:
- deeply wedded to OO techniques. For example creating a door, attach a script to it that has some behaviour in response to an event. How do I replicate that behavior in a function so that I can share it between other doors.
- deeply wedded to its own editor. I want my source code an assets to be seperate. I want my game logic to be separate from the game engine.
For the first one: something like "let openDoor<'T&#Node&#IDoor> (door:'T)" or something similar (plus whatever other params you need) could work in a module, then you'd only have to call the method from your godot C# code, at least that's what I'm doing right now to share common code between some Nodes
Is there a post about how would a preferred api look for f# script?
i dunno tbh im too clueless on godot to have a proper opinion
i just cooked an api i like, but its definitely not performant, at least the way its implemented
namespace fs
open Godot
module Systems =
let setup (world: World) =
world.on <|
fun (Process deltaTime) (area: Area2D) (sprite: Sprite2D) ->
area.GlobalScale |> string |> sprintf "hello! area 2d with scale %s" |> GD.Print
sprite.Texture.ResourcePath |> sprintf "texture is %s" |> GD.Print
i made it so
- user registers functions before anything runs
- this regsitration creates a function that takes in a custom node type and registers its lifecycle methods if that node has all the required nodes from the function (
Area2DandSprite2D) in this example - this created function is called by any nodes of the
Entitytype on_EnterTree(its an empty custom node that gathers all functions it should call and just calls them)
the Godot Node looks like the following:
using Godot;
using fs;
public partial class Entity : Node
{
FNode fnode;
public override void _EnterTree()
{
fnode = fs.FNode.Create(this);
fs.World.Singleton().registerNode(fnode);
}
public override void _Ready()
{
fnode.On(new fs.Ready());
}
public override void _Process(double delta){
var x = fs.Process.NewProcess(delta);
fnode.On(x);
}
}
theoretically once its expanded enough there would be 0 need to touch any c# code and everything could be done from f# ๐ค
i guess maybe some databags or something like that would be done in c#, but literally just using variables to [Export]
I would love to see a full example of this, it looks very interesting
sorry for the delay, i dont open discord that often
its pretty cursed but here you go:
https://gist.github.com/vmenge/3061964f113b07ed6930ccd0ef6ed9a4
im probably going to try something with codegen in a bit
i got something converting
[<Gfs>]
type Converted() =
inherit Node2D()
member val Speed = 5.0f with get, set
override _._Ready() = ()
override _._Process(delta: double) = ()
to
using Godot;
public partial class Converted : Godot.Node2D
{
fs.Converted converted = new();
[Export]
public float Speed
{
get => converted.Speed;
set => converted.Speed = value;
}
public override void _Ready()
{
converted._Ready();
}
public override void _Process(Double delta)
{
converted._Process(delta);
}
}
trivially, but there are two main issues:
- you cant reference other generated godot classes from the f# project due to circular dependencies
- every converted class now has a heap allocation
using structs could solve this but property ergonomics on structs would be pretty bad
this also works pretty well:
[<Gfs(typeof<Node2D>); Struct>]
type Converted =
val mutable Speed: float
member _._Ready() = ()
member _._Process(delta: double) = ()
drawback remains:
- you can't reference other generated godot classes from the f# project
new drawback:
- no type checking on method override -- its being done by convention by the generator on every method starting with
_
but, removes the drawback of every f#-converted godot class resulting in a new heap allocation
