Scripting Guide

C# Scripting

Write powerful scripts using C# with full .NET support, strong typing, LINQ, and access to the entire .NET ecosystem.

Overview

C# is a powerful, statically-typed language that provides excellent IDE support, robust error handling, and access to the full .NET framework. It's ideal for complex scripts that benefit from strong typing and advanced features.

Strong Typing

Catch errors at compile time with static type checking.

LINQ Support

Query and transform data with elegant LINQ expressions.

.NET Libraries

Access System.*, JSON parsing, HTTP, and more.

IDE Support

Full IntelliSense and debugging in external editors.

When to Use C#

  • Complex data processing and transformations
  • Integration with .NET libraries
  • Scripts that benefit from strong typing
  • Large scripts with multiple helper classes
  • When you need advanced async/await patterns

Setup

C# scripting requires the Mono runtime, which is included with FaustBot. No additional setup is required.

1

Create a C# Script

In your action, add a Run Script effect and select C# as the language.

2

Write Your Code

The script must contain a CPHInline class with an Execute() method.

3

External Editing (Optional)

For complex scripts, save the file externally and use Visual Studio or VS Code for full IntelliSense support.

Script Structure

C# scripts follow a specific structure with a class containing the entry point method.

Basic C# script structure
using System;

public class CPHInline
{
    public bool Execute()
    {
        // Your code here
        CPH.SendMessage("Hello from C#!");
        return true;
    }
}

Available Objects

These objects are automatically available in your scripts:

ObjectDescription
CPHMain API object for all FaustBot functionality
argsDictionary containing trigger event data

Type Safety

C# provides strong typing for variables, giving you compile-time error checking and better IDE support.

Type-safe variable access
public bool Execute()
{
    // Strongly typed variable access
    string username = args["user"].ToString();
    int points = CPH.GetUserVar<int>(username, "points", 0);
    DateTime lastSeen = CPH.GetUserVar<DateTime>(username, "lastSeen");

    // Type-safe global variables
    int totalFollowers = CPH.GetGlobalVar<int>("totalFollowers", 0);
    List<string> recentUsers = CPH.GetGlobalVar<List<string>>("recentUsers");

    // Set with proper types
    CPH.SetUserVar(username, "points", points + 100);
    CPH.SetGlobalVar("lastActivity", DateTime.Now, true);

    return true;
}

Common Types

TypeUse Case
stringText, usernames, messages
intWhole numbers, points, counts
doubleDecimal numbers, percentages
boolTrue/false flags
DateTimeTimestamps, dates
List<T>Collections of items
Dictionary<K,V>Key-value mappings

.NET Features

LINQ Queries

Use LINQ for powerful data querying and transformation.

LINQ example
using System.Linq;
using System.Collections.Generic;

public class CPHInline
{
    public bool Execute()
    {
        // Get all users with more than 1000 points
        var topUsers = GetAllUsers()
            .Where(u => u.Points > 1000)
            .OrderByDescending(u => u.Points)
            .Take(10)
            .ToList();

        // Format leaderboard
        var leaderboard = topUsers
            .Select((u, i) => $"{i + 1}. {u.Name}: {u.Points} pts")
            .Aggregate((a, b) => $"{a} | {b}");

        CPH.SendMessage($"Top 10: {leaderboard}");
        return true;
    }

    private List<UserData> GetAllUsers()
    {
        // Implementation here
        return new List<UserData>();
    }
}

Async/Await

Handle asynchronous operations cleanly with async/await patterns.

Async operations
using System;
using System.Threading.Tasks;

public class CPHInline
{
    public bool Execute()
    {
        // Run async operation synchronously
        var result = FetchDataAsync().GetAwaiter().GetResult();
        CPH.SendMessage($"Got result: {result}");
        return true;
    }

    private async Task<string> FetchDataAsync()
    {
        // Simulate async work
        await Task.Delay(100);

        // Make HTTP request
        var response = await CPH.HttpGetAsync("https://api.example.com/data");
        return response;
    }
}

JSON Handling

Parse and create JSON using System.Text.Json or Newtonsoft.Json.

JSON serialization
using System;
using System.Text.Json;

public class CPHInline
{
    private class ApiResponse
    {
        public string Status { get; set; }
        public DataPayload Data { get; set; }
    }

    private class DataPayload
    {
        public string Name { get; set; }
        public int Value { get; set; }
    }

    public bool Execute()
    {
        // Parse JSON response
        string json = CPH.HttpGet("https://api.example.com/data");
        var response = JsonSerializer.Deserialize<ApiResponse>(json);

        if (response?.Status == "success")
        {
            CPH.SendMessage($"Got: {response.Data.Name} = {response.Data.Value}");
        }

        // Create JSON
        var outData = new { user = args["user"], timestamp = DateTime.UtcNow };
        string outJson = JsonSerializer.Serialize(outData);
        CPH.SetArgument("jsonOutput", outJson);

        return true;
    }
}

Advanced Patterns

Helper Classes

Define helper classes within your script for better organization.

Using helper classes
using System;
using System.Collections.Generic;

public class CPHInline
{
    // Helper class for structured data
    private class UserStats
    {
        public string Username { get; set; }
        public int Points { get; set; }
        public int WatchTime { get; set; }
        public DateTime FirstSeen { get; set; }

        public string GetRank()
        {
            if (Points >= 10000) return "Legend";
            if (Points >= 5000) return "Elite";
            if (Points >= 1000) return "Veteran";
            return "Newcomer";
        }
    }

    public bool Execute()
    {
        string user = args["user"].ToString();

        var stats = new UserStats
        {
            Username = user,
            Points = CPH.GetUserVar<int>(user, "points", 0),
            WatchTime = CPH.GetUserVar<int>(user, "watchTime", 0),
            FirstSeen = CPH.GetUserVar<DateTime>(user, "firstSeen")
        };

        CPH.SendMessage($"{stats.Username} is a {stats.GetRank()} with {stats.Points} points!");
        return true;
    }
}

Error Handling

Use try-catch blocks for robust error handling with specific exception types.

Comprehensive error handling
using System;

public class CPHInline
{
    public bool Execute()
    {
        try
        {
            // Main logic
            string user = args["user"]?.ToString()
                ?? throw new ArgumentNullException("user");

            int amount = ParseAmount(args["message"]?.ToString());
            ProcessReward(user, amount);

            return true;
        }
        catch (ArgumentNullException ex)
        {
            CPH.LogError($"Missing required argument: {ex.ParamName}");
            return false;
        }
        catch (FormatException ex)
        {
            CPH.SendMessage("Invalid number format. Usage: !reward <amount>");
            return false;
        }
        catch (Exception ex)
        {
            CPH.LogError($"Unexpected error: {ex.Message}");
            CPH.LogError(ex.StackTrace);
            return false;
        }
    }

    private int ParseAmount(string input)
    {
        if (string.IsNullOrWhiteSpace(input))
            throw new FormatException("Amount is required");
        return int.Parse(input.Trim());
    }

    private void ProcessReward(string user, int amount)
    {
        int current = CPH.GetUserVar<int>(user, "points", 0);
        CPH.SetUserVar(user, "points", current + amount);
        CPH.SendMessage($"Gave {amount} points to {user}!");
    }
}

External Libraries

You can reference external .NET assemblies in your scripts.

Using external libraries
// Reference external assemblies at the top
// #r "path/to/MyLibrary.dll"

using System;
using MyLibrary;

public class CPHInline
{
    public bool Execute()
    {
        // Use external library
        var helper = new MyHelper();
        var result = helper.ProcessData(args["message"].ToString());

        CPH.SendMessage(result);
        return true;
    }
}

Library Tips

  • Place DLLs in the FaustBot plugins directory
  • Use NuGet packages by downloading the DLL
  • Ensure library targets .NET Standard or compatible framework
  • Test library compatibility before using in production