reckfellENGINE

C# scripts: from build to verified result

Runnable example: a dynamic call, signal, formula and UTF-8 file.

On this page

Run a complete example

Use a C# project with Reckfell.NET.Sdk 1.0.0 and net10.0. C# setup covers project creation and building.

  1. Save the four files below in the project with their exact names.
  2. Run dotnet build in the .csproj directory.
  3. Create a level with an Entity root, attach ScriptToolsExample.cs and save as script_tools.rscene.
  4. Run that level. Output should contain SCRIPT_TOOLS count=5; signal=5; damage=25; ok=True.

The example also writes user://script-tools-note.txt containing Reckfell: 25. This is a test note rather than the whole game's state. CounterService is deleted after the check.

NumericExpression.cs
C#
using System;
using Reckfell;

public sealed class NumericExpression : IDisposable
{
    private readonly Expression _expression = new();
    private bool _parsed;
    private int _inputCount;

    public bool TryParse(string formula, string[] names, out string error)
    {
        _parsed = false;
        error = "";
        if (_expression.Parse(formula, names) != Error.Ok)
        {
            error = _expression.GetErrorText();
            return false;
        }
        _inputCount = names.Length;
        _parsed = true;
        return true;
    }

    public bool TryEvaluate(double[] values, out double number, out string error)
    {
        number = 0;
        error = "";
        if (!_parsed || values.Length != _inputCount)
        {
            error = "Parse first and supply one value per input name.";
            return false;
        }
        using var inputs = new Reckfell.Collections.Array();
        foreach (double value in values)
        {
            if (!double.IsFinite(value))
            {
                error = "Inputs must be finite numbers.";
                return false;
            }
            inputs.Add(value);
        }
        using Variant result = _expression.Execute(inputs, null, false, true);
        if (_expression.HasExecuteFailed())
        {
            error = _expression.GetErrorText();
            return false;
        }
        if (result.VariantType is not (Variant.Type.Int or Variant.Type.Float) ||
            !double.IsFinite(result.AsDouble()))
        {
            error = "Expected a finite numeric result.";
            return false;
        }
        number = result.AsDouble();
        return true;
    }

    public void Dispose() => _expression.Dispose();
}
TextNoteStore.cs
C#
using System.Text;
using Reckfell;

public static class TextNoteStore
{
    public const string Path = "user://script-tools-note.txt";
    public const int MaximumBytes = 4096;

    public static bool TryWrite(string text, out Error error)
    {
        error = Error.InvalidParameter;
        if (Encoding.UTF8.GetByteCount(text) > MaximumBytes) return false;
        using var file = FileAccess.Open(Path, FileAccess.ModeFlags.Write);
        if (file is null)
        {
            error = FileAccess.GetOpenError();
            return false;
        }
        if (!file.StoreString(text))
        {
            error = file.GetError();
            return false;
        }
        file.Flush();
        error = file.GetError();
        return error == Error.Ok;
    }

    public static bool TryRead(out string text, out Error error)
    {
        text = "";
        using var file = FileAccess.Open(Path, FileAccess.ModeFlags.Read);
        if (file is null)
        {
            error = FileAccess.GetOpenError();
            return false;
        }
        if (file.GetLength() > MaximumBytes)
        {
            error = Error.InvalidData;
            return false;
        }
        string candidate = file.GetAsText();
        error = file.GetError();
        if (error != Error.Ok && error != Error.FileEof) return false;
        text = candidate;
        error = Error.Ok;
        return true;
    }
}
CounterService.cs
C#
using Reckfell;

public partial class CounterService : Entity
{
    [Signal] public delegate void CountChangedEventHandler(int count);
    private int _count;
    public int Count => _count;

    public bool TryAdd(int amount)
    {
        if (amount <= 0 || amount > 1000 - _count) return false;
        _count += amount;
        EmitSignal(SignalName.CountChanged, _count);
        return true;
    }
}
ScriptToolsExample.cs
C#
using Reckfell;

public partial class ScriptToolsExample : Entity
{
    public bool Succeeded { get; private set; }

    public override void _Ready()
    {
        var counter = new CounterService();
        AddChild(counter);
        int observed = 0;
        counter.CountChanged += value => observed = value;
        bool added = counter.Call(CounterService.MethodName.TryAdd, 5).AsBool();
        using var expression = new NumericExpression();
        bool parsed = expression.TryParse("base_damage * multiplier",
            new[] { "base_damage", "multiplier" }, out string error);
        double damage = 0;
        bool evaluated = parsed && expression.TryEvaluate(new[] { 20.0, 1.25 }, out damage, out error);
        bool saved = TextNoteStore.TryWrite("Reckfell: 25", out Error writeError);
        bool read = TextNoteStore.TryRead(out string text, out Error readError);
        Succeeded = added && counter.Count == 5 && observed == 5 && evaluated &&
            damage == 25 && saved && read && text == "Reckfell: 25";
        ReckfellApi.Print($"SCRIPT_TOOLS count={counter.Count}; signal={observed}; damage={damage}; ok={Succeeded}");
        if (!Succeeded) ReckfellApi.PrintErr($"SCRIPT_TOOLS failed: {error}; write={writeError}; read={readError}");
        counter.Free();
    }
}

Inspect each part

C# and Variant · Formulas · Files · Logging · Reading the API · Templates

If ok=False, inspect the reported stages: dynamic call, parsing/evaluation and opening/writing/reading the file. Do not keep processing a result that already reported failure.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.