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-resource2. 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.