> For the complete documentation index, see [llms.txt](https://stoneforgeteam.gitbook.io/stoneforgeteam-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://stoneforgeteam.gitbook.io/stoneforgeteam-docs/gml-and-c-code/gml-bindings.md).

# Your own GML

{% hint style="warning" %}
**GML works only on the VM modbranch.** On the game's native branch its GML is compiled into the exe, and nothing can be added: a mod with a `GML` folder isn't loaded there, and its page in the Mods window says why. See [Native and VM branches](/stoneforgeteam-docs/getting-started/game-branches.md).
{% endhint %}

Put GML functions in a mod's `GML` folder (the mod itself: see [Writing a mod](/stoneforgeteam-docs/getting-started/writing-a-mod.md)). StoneForge compiles them into `data.win` when the game starts, and a Roslyn source generator gives the mod's C# a class to call them with. The same generator works in Visual Studio. GML changes need a full game restart; the mod's C# still hot-reloads.

## Calling your GML from C# code

The bindings are named after the mod's folder. A mod in `mods\ExampleMod` with `GML\Add.gml`:

```gml
/// @stoneforge return double
/// @stoneforge param left double
/// @stoneforge param right double
function Add(left, right)
{
    return left + right;
}
```

gets a generated class `ExampleMod.Gml`:

```csharp
namespace ExampleMod;

public class ExampleMod : IStoneMod
{
    public void Load(ModContext context)
    {
        // Inside Load, Tick or another game-thread callback:
        context.Log("20 + 22 = " + Gml.Add(20, 22));
    }
    ...
}
```

Inside the mod's own namespace that's just `Gml.Add(...)`; from another namespace, `ExampleMod.Gml.Add(...)`. A folder name that isn't a C# name is turned into one: `mods\my-cool mod` gives `MyCoolMod.Gml`. `Gml` is a `public static partial class`, generated as one file per GML file (`GML\Add.gml` gives `Add.g.cs`) plus a shared `Gml.g.cs`. To add members of your own to it, declare it the same way:

```csharp
namespace ExampleMod;

public static partial class Gml
{
    public static double AddTwice(double left, double right) => Twice(Add(left, right));
}
```

A non-partial class of your own named `Gml` in that namespace clashes with the bindings, and the generator reports it.

There's nothing else to set up: no manifest, no IDs or versions. A mod's GML can only be called from that mod.

## Supported GML

* One named function per `.gml` file, anywhere under `GML\` (subfolders are fine; don't name one `GML`). No top-level code before or after it.
* Plain named parameters, each with a type annotation; a return annotation is required. No optional/default or variadic parameters.
* Types: `int`, `double`, `bool`, `string`, `GmValue`; the return type may also be `void`. The annotations define the C# signature; GML itself is dynamically typed, so return values must match. Conversions follow `GmValue`.
* Function and parameter names must be valid plain C# identifiers. Duplicate function names are rejected.
* Ordinary quoted strings and comments are supported. Verbatim/interpolated strings are rejected.
* Parameters are compiled as `argument0`, `argument1`... This compatibility rewrite is retained with UndertaleModLib 0.9.2.0; write parameters by name as usual and don't also declare a local with a parameter's name. Simplifying the rewrite for the new compiler has not been validated.
* Functions in the same mod can call each other by name, in any file order: StoneForge compiles each after the ones it calls. A function may call itself, but functions that call each other in a loop (`A` calls `B` calls `A`) are rejected. Names are rewritten to a stable internal name derived from the mod folder's name; strings and member access (`obj.Add`) are left alone, so don't look your functions up by name with `asset_get_index`.
* Calls from C# run with global self. Pass positions, IDs and values in explicitly. A function can loop over instances itself to do a batch of work in one call.
* C# calls GML; GML can't call back into C#.

## Visual Studio / editor setup

For a mod at `<game>\mods\<mod>`, its `.csproj`:

Target `net10.0` in the project's `PropertyGroup` and install the .NET 10 SDK for editor builds. The source generator DLL remains `netstandard2.0` for compiler-host compatibility.

```xml
<ItemGroup>
  <Reference Include="StoneForge.API">
    <HintPath>..\..\dotnet\StoneForge.API.dll</HintPath>
    <Private>false</Private>
  </Reference>
  <Analyzer Include="..\..\dotnet\StoneForge.GmlGenerator.dll" />
  <AdditionalFiles Include="GML\**\*.gml" />
</ItemGroup>
```

The generator finds the mod folder from the GML files' paths (the folder holding `GML`), so the IDE and the game name the bindings the same way.

## Warning and switching off

The Mods page shows, in yellow:

{% hint style="warning" %}
This mod uses GML bindings and can bypass StoneForge's security. Its GML can't be hot-reloaded: changes need a restart of the game. Use at your own discretion.
{% endhint %}

The GML runs directly inside GameMaker, outside StoneForge's C# restrictions. Preparation and loading log the same warning. GML can affect game state and files; the C# source-policy check does not sandbox it.

Switching a mod off makes its `Gml` calls refuse. Its compiled GML stays in the current `data.win` until the next start: switching off is not a security boundary, and can't undo what its GML did. On restart the patcher rebuilds the game data whenever any mod's GML changes. Invalid GML leaves the previous data file in place, and bindings that don't match the GML the game was prepared with refuse to run.

What was prepared is read once when the loader starts. Editing GML (or its annotations) while the game runs needs a restart: a C# reload can't call an old GML body through a new signature.

Renaming a mod folder renames its bindings (and its GML's internal names) at the next start.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://stoneforgeteam.gitbook.io/stoneforgeteam-docs/gml-and-c-code/gml-bindings.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
