Skip to Content
ScriptingC# Basics
Open in ChatGPTOpen in Claude

C# Scripting Basics

While Lua and JavaScript are the most common languages for FiveM development, C# (C Sharp) offers strong typing, compiled performance, and access to the rich .NET ecosystem. This guide covers the basics of setting up and writing C# resources.

⚠️

This page targets the Legacy runtime (Mono, .NET Framework 4.5.2 / net452). FiveM for GTA V Enhanced replaces Mono with .NET and only requires a .NET 10 SDK, per the official Legacy vs Enhanced notes . See Legacy vs Enhanced before choosing a target.

Prerequisites

To develop in C#, you need:

  • A .NET SDK to build SDK-style projects, plus an editor such as Visual Studio 2022 or VS Code with the C# Dev Kit extension.
  • The .NET Framework 4.5.2 (net452) target: Legacy FiveM uses a Mono runtime compatible with this version. The reference-assemblies NuGet package below supplies it at compile time.
  • Basic knowledge of C# syntax and Object-Oriented Programming (OOP).

Project Setup

1. Create the projects

The official C# runtime guide  generates a client/server solution from the CitizenFX templates:

dotnet new -i CitizenFX.Templates dotnet new cfx-resource

2. Add References

Alternatively, reference the CitizenFX assemblies from NuGet in an SDK-style project. Use CitizenFX.Core.Client in the client project and CitizenFX.Core.Server in the separate server project (same versions as Your First C# Resource):

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net452</TargetFramework> <AssemblyName>MyResource.Client.net</AssemblyName> <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies> </PropertyGroup> <ItemGroup> <PackageReference Include="CitizenFX.Core.Client" Version="1.0.26803" ExcludeAssets="runtime" /> <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net452" Version="1.0.3" PrivateAssets="all" /> </ItemGroup> </Project>

Do not copy CitizenFX.Core.*.dll into the resource; the platform provides them at runtime.

3. Build Output

Configure your project to output the compiled .dll files to a folder inside your server’s resources directory.

Basic Resource Structure

A C# resource typically has two projects in one solution: one for Client and one for Server.

fxmanifest.lua

You still need an fxmanifest.lua to define the resource and load the assemblies.

fx_version 'cerulean' game 'gta5' -- `files` are downloaded by every client: list client assemblies only. -- Never list server assemblies here. files { 'MyResource.Client.net.dll' } client_script 'MyResource.Client.net.dll' server_script 'MyResource.Server.net.dll'

Writing Code

In C#, scripts inherit from BaseScript.

Client Script Example (Client/Main.cs)

using System; using System.Collections.Generic; using System.Threading.Tasks; using CitizenFX.Core; using static CitizenFX.Core.Native.API; namespace MyResource.Client { public class Main : BaseScript { public Main() { // Event Handlers EventHandlers["onClientResourceStart"] += new Action<string>(OnClientResourceStart); // Register a command RegisterCommand("hello_csharp", new Action<int, List<object>, string>((source, args, raw) => { TriggerEvent("chat:addMessage", new { color = new[] { 255, 0, 0 }, args = new[] { "[C#]", "Hello from C# Client!" } }); }), false); } private void OnClientResourceStart(string resourceName) { if (GetCurrentResourceName() != resourceName) return; Debug.WriteLine($"The resource {resourceName} has started on the client."); } } }

Server Script Example (Server/Main.cs)

using System; using CitizenFX.Core; using static CitizenFX.Core.Native.API; namespace MyResource.Server { public class Main : BaseScript { public Main() { EventHandlers["onResourceStart"] += new Action<string>(OnResourceStart); } private void OnResourceStart(string resourceName) { if (GetCurrentResourceName() != resourceName) return; Debug.WriteLine($"The resource {resourceName} has started on the server."); } } }

Events and Networking

Triggering Events

// Client to Server (client script) TriggerServerEvent("myResource:serverEvent", "arg1", 123); // Server to one client (server script): `player` comes from a // [FromSource] Player handler parameter, see "Handling Events" below player.TriggerEvent("myResource:clientEvent", "data"); // Server to all clients (server script) TriggerClientEvent("myResource:clientEvent", "data");

Handling Events

public Main() { EventHandlers["myResource:serverEvent"] += new Action<Player, string, int>(OnServerEvent); } private void OnServerEvent([FromSource] Player player, string arg1, int arg2) { Debug.WriteLine($"Received from {player.Name}: {arg1}, {arg2}"); player.TriggerEvent("myResource:clientEvent", "data"); }

Using Natives

Access FiveM natives via the CitizenFX.Core.Native.API static class.

// Example: Spawning a vehicle (client BaseScript method) private async Task<int> SpawnAsync(Vector3 pos, float heading) { uint model = (uint)GetHashKey("adder"); RequestModel(model); while (!HasModelLoaded(model)) await Delay(0); int vehicle = CreateVehicle(model, pos.X, pos.Y, pos.Z, heading, true, false); SetModelAsNoLongerNeeded(model); return vehicle; }

Benefits of C#

  • Async/Await: Native support for asynchronous programming makes handling delays and API calls cleaner.
  • Type Safety: Catch errors at compile time rather than runtime.
  • Performance: Generally faster execution for complex logic compared to interpreted languages.

Troubleshooting

  • FileNotFoundException: Ensure all referenced DLLs are in the resource folder or properly referenced in fxmanifest.lua.
  • Runtime Errors: Check the FXServer console for server-side stack traces and the client F8 console for client-side ones. C# stack traces are usually very detailed.