Skip to main content

Data types

When you write a mod, you are constantly storing and asking questions about information: Is the player in a vehicle? How many seconds until the next check? What weather should we switch to? C# gives you specific types to hold each kind of value.

Primitive types you use every day

Four basic types form the bedrock of almost every mod:

  • bool: Holds true or false. Ideal for flags: private bool _isMissionActive;.
  • int: A whole number (32 bits). Used for counters, timer timestamps in milliseconds, or indexes: private int _nextCheckTime;.
  • float: A single-precision floating-point number. Essential in 3D games for speeds, distances, and headings. Always add the f suffix in C#: private float _speed = 15.5f;.
  • string: Text enclosed in double quotes. Used for notifications, model names, or log paths: string message = "Mission started";.

Game-specific types

SHVDN provides types specifically designed for the GTA V engine:

  • GTA.Math.Vector3: Represents a point or direction in 3D space with X, Y, and Z coordinates:
    Vector3 playerPos = Game.Player.Character.Position;
  • GTA.Weather: An enumeration (enum) of all weather types recognized by the game:
    Weather currentWeather = World.Weather;
    World.Weather = Weather.ExtraSunny;

Local variables vs fields

Where you declare a variable determines how long it survives. This is where most beginners lose hours of debugging:

Local variables: temporary within a method

A local variable is declared inside a method. It is created when the method runs, and destroyed as soon as the method exits:

private void OnKeyDown(object sender, KeyEventArgs e)
{
// Created on key press, gone as soon as this block finishes
float distance = 10.0f;
}

Fields: persistent state across frames

Because OnTick runs sixty times per second, any variable declared inside OnTick resets every single frame. If you want to remember whether a mission has started or when you last showed a message, declare a field at the class level:

public sealed class WeatherWatch : Script
{
// These survive between frames and keypresses
private bool _hasAnnounced;
private int _nextUpdateTime;

private void OnTick(object sender, EventArgs e)
{
if (_hasAnnounced)
{
return;
}

if (Game.GameTime > _nextUpdateTime)
{
_hasAnnounced = true;
GTA.UI.Screen.ShowSubtitle("Welcome to Los Santos", 3000);
}
}
}

Notice the naming convention: fields private to a class start with an underscore (_hasAnnounced). It makes it instantly clear whether you are touching long-term state or a temporary calculation.

Next, we look at control flow: making decisions with if statements and loops.