Example code: Lab 0
This is one way to meet the brief, not the only correct answer. Read it to compare with your own attempt and understand the trade-offs, not to copy a definitive template. Any approach that passes the validation checklist is just as valid.
← Back to the public project brief
Build the diagnostic DLL
Create a Class Library (.NET Framework) targeting net48. Add a reference to the ScriptHookVDotNet3.dll from your game installation, add a C# file containing the code below, then build. Copy only the resulting P0Diagnostic.dll into the game's scripts/ folder. The installation guide covers the loader files that belong in the game root. This sample is also compiled by the site's verification harness against the real SDK; its behavior still needs your in-game check.
The code
using System;
using System.IO;
using GTA;
public sealed class P0Diagnostic : Script
{
private const string LogPath = "scripts/p0_diagnostic.log";
private int _nextAnnouncement;
public P0Diagnostic()
{
Tick += OnTick;
Aborted += OnAborted;
}
private void OnTick(object sender, EventArgs e)
{
if (Game.GameTime < _nextAnnouncement)
{
return;
}
_nextAnnouncement = Game.GameTime + 5000;
WriteLog("diagnostic active");
GTA.UI.Screen.ShowSubtitle("Diagnostic: ScriptHookVDotNet is working.", 3000);
}
private void OnAborted(object sender, EventArgs e)
{
WriteLog("script unloaded");
}
private static void WriteLog(string message)
{
try
{
string line = $"{DateTime.Now:HH:mm:ss} P0 {message}{Environment.NewLine}";
File.AppendAllText(LogPath, line);
}
catch (Exception)
{
// The log is secondary: the subtitle is sufficient visual proof.
}
}
}
Key decisions
- Inheriting from
GTA.Script: Any C# class loaded by ScriptHookVDotNet must inherit fromGTA.Script. The bridge scans assemblies inscripts/and instantiates these classes on reload. - Event attachment in constructor: Subscribing to
Tick += OnTick;andAborted += OnAborted;registers execution callbacks.Tickruns every frame, whileAbortedruns when the script is unloaded or reloaded. - Time throttling with
Game.GameTime:Tickruns dozens of times per second. Writing to disk or displaying subtitles on every frame would cause severe performance stutter._nextAnnouncement = Game.GameTime + 5000;ensures code runs only once every 5 seconds. - Defensive logging with
try-catch: Disk writes can fail if a file is locked by an editor or antivirus. WrappingFile.AppendAllTextintry-catchprevents disk access errors from crashing the game. - Teardown notification: In
OnAborted, logging"script unloaded"proves that ScriptHookVDotNet cleanly alerts running scripts before removing them from memory.