vmenge.Godot.Garnet 0.0.5

dotnet add package vmenge.Godot.Garnet --version 0.0.5
                    
NuGet\Install-Package vmenge.Godot.Garnet -Version 0.0.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="vmenge.Godot.Garnet" Version="0.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="vmenge.Godot.Garnet" Version="0.0.5" />
                    
Directory.Packages.props
<PackageReference Include="vmenge.Godot.Garnet" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add vmenge.Godot.Garnet --version 0.0.5
                    
#r "nuget: vmenge.Godot.Garnet, 0.0.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package vmenge.Godot.Garnet@0.0.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=vmenge.Godot.Garnet&version=0.0.5
                    
Install as a Cake Addin
#tool nuget:?package=vmenge.Godot.Garnet&version=0.0.5
                    
Install as a Cake Tool

Godot.Garnet

Very exprimental library meant to help write Godot games with almost all code driven completely from the F# side outside of a single glue C# script.

Main feature right now is importing scenes into a Container from the Garnet ECS with minimal boilerplate and zero per‑frame allocations, but as I work more with Godot and F# I will most likely add any generic relevant helpers here if deemed necessary.

Installation

dotnet add package vmenge.Godot.Garnet

How It Works

Godot's groups are used to tag nodes that should be converted into entities or Marker or Link components. When you bring Godot.Garnet into scope, an ImportScene extension method is added to Garnet.Composition.Container. Container.ImportScene(this, sceneRoot) walks the subtree rooted at sceneRoot and:

  • Creates an ECS entity for every node in the entity group.
  • Adds all children Nodes directly as components to that entity.

Additionally, there are two Attributes added to make one's life easier:

  • [<Marker("markergroupname")>] will create components for an entity if the Node in the "entity" group or any of its children belongs to markergroupname.

    // Marker attribute structs should **always** be empty.
    [<Marker("spawnPoint")>]
    type SpawnPoint = struct end
    
  • [<Link("linkgroupname")>] will add the component tagged with the Link attribute to its parent entity instead of the raw node.

    // Link attribute structs should **always** have a single
    // field for the `Node` it is linking to.
    [<Struct;Link("player")>]
    type Player = {
        Node: CharacterBody2D
    }
    

Both Link and Marker groups can be assigned both to the parent "entity" node, or any of its children.

So the following Godot node structure

World (Node2D)
├─ Player (CharacterBody2D)   [groups: entity, player]
│  └─ CollisionShape2D        [no groups]
└─ SpawnPoint (Marker2D)      [groups: entity, spawnPoint]

Using the Marker and Link attributes like so

  [<Marker("spawnPoint")>]
  type SpawnPoint = struct end

  [<Struct;Link("player")>]
  type Player = {
      Node: CharacterBody2D
  }

Upon importing the World node with Container.ImportScene, would result in the following entities with components:

ECS World
├─ Entity #1
│  ├─ Player                ← link component (holds CharacterBody2D node)
│  └─ CollisionShape2D      ← node component
└─ Entity #2
   ├─ SpawnPoint            ← marker component
   └─ Marker2D              ← node component

One big difference between Marker and Link, is that Marker components are added alongside the normal component import chain. Link components will always be added instead of the component it is linked to.

With the above structure, one could query the components through Garnet

let mySystem (c: Container) =
  c.On<Ready> 
    <| fun e ->
        for r in c.Query<SpawnPoint, Marker2D>() do 
          let marker = r.Value2
          // do something

        for r in c.Query<Player, CollisionShape2D>() do
          let characterBody2d, collisionShape2d = r.Value1.Node, r.Value2
          // do something

Quickstart example

Full project examples will be in the /examples folder on the repo soon, but one should be able to get started with something as simple as the following:

On the F# project:

// Main.fs
module Main

open Godot
open Godot.Garnet

[<Struct>]
type Ready = { Root: Node }

[<Struct>]
type Process = { Root: Node; Dt: float }

type FWorld =
    { Container: Container
      Disposable: IDisposable }

    static member Make node =
        let c = Container()
        c.ImportScene node

        {
            Container = c
            Disposable =
                Disposable.Create [
                    c.On<Ready> 
                    <| fun e -> GD.Print "root scene is ready!"

                    c.On<Process>
                    <| fun e ->
                        GD.Print $"hello from process! deltatime: {e.Dt}"
                ]
        }

On the Godot C# project, a single World.cs or equivalent is all that is needed, attached to the root node of a scene:

using Godot;
using static Main;

public partial class World : Node2D
{
    FWorld world = null!;

    public override void _Ready()
    {
        world = FWorld.Make(this);
        world.Container.Run(new Ready(this));
    }

    public override void _Process(double delta)
    {
        world.Container.Run(new Process(this, delta));
    }
}

From there, using the Marker and Link attributes to define structs that correspond to Nodes that belong to or are children of a "entity" group Node and their equivalent groups should be more than enough to run Garnet queries as per its documentation.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.5 490 7/22/2025
0.0.4 496 7/22/2025
0.0.3 485 7/22/2025
0.0.2 489 7/22/2025
0.0.1 492 7/22/2025