Burnsies HideoutDocsBurnsie.Common

Diagnostics & Updates — DependencyReport, UpdateChecker, LcpdfrVersionChecker, LibraryInfo

Burnsie.Common.Diagnostics covers install validation and update notification. The design inverts the historical mistakes in this ecosystem: versions are compared as System.Version (never floats — as floats, RPH 1.124 reads older than 1.98), network checks run off-thread with tight timeouts, and "you're up to date" is a log line, never a toast.

DependencyReport — install validation

Checks that required files exist and meet minimum versions, and gives you a structured result to act on.

var report = new DependencyReport(log);
report.CheckFile("RAGE Plugin Hook", "RAGEPluginHook.exe", new Version(1, 124), hardRequirement: true);
report.CheckFile("Optional companion", "plugins/LSPDFR/Companion.dll", null, hardRequirement: false);

if (report.HasBlockingFailure)
{
    // disable features and tell the user what's missing/old — don't crash later instead
}

foreach (var result in report.Results)
{
    // result.Name, Found, FoundVersion, MinimumVersion, IsBlocking, Message
}

Semantics worth knowing:

  • Versions are read from FileVersionInfo.ProductVersion (falling back to FileVersion) and parsed leniently — ParseVersion tolerates prefixes/suffixes like v1.124.1393.17586-beta and single-number versions.
  • Newer than expected is a warning, never a failure.
  • A failed check (exception while checking) never blocks; only a confirmed missing or outdated hard dependency does.
  • Every outcome is logged at the appropriate level automatically.

DependencyReport.ParseVersion(string) is public — use it anywhere you need to parse a version out of loose text.

UpdateChecker — GitHub releases

Checks a GitHub repository's latest release once per day, entirely off the game thread, and only speaks up when a newer version exists.

new UpdateChecker(log).CheckDaily(
    "you/your-repo",                                  // owner/name slug
    myVersion,                                        // the running version
    "plugins/LSPDFR/MyPlugin/update.stamp",           // remembers the last check time
    tag => notifier.Show("Update " + tag + " available"));  // called only when newer

Hardening you inherit:

  • Runs on a background thread (never a fiber), 5-second timeout (the framework default of 100 s would sit on the game's path).
  • TLS 1.2 is OR-ed into ServicePointManager.SecurityProtocol — assigning would strip protocols other plugins enabled.
  • Throttled via the stamp file to one check per day; offline/failed checks are debug-log lines, not errors.
  • The callback fires on a background thread — it must be thread-safe. Enqueueing into a Notifier is the intended pattern (its queue is lock-protected).

LcpdfrVersionChecker — LCPDFR downloads API

Same discipline as UpdateChecker, but against the official LCPDFR downloads API, which is where LSPDFR plugins actually ship. It distinguishes three noteworthy states and hands you a ready-made message:

StatusMeaningMessage tone
UpdateAvailablea newer minor/patch release existsplain update notice
MajorUpdateAvailablea newer major release exists"your build may now be unstable — please update"
Betayou are running ahead of the public release"BETA build — expect rough edges"

UpToDate never reaches the callback (it's a log line).

// Your own plugin's file id — the number in your lcpdfr.com download URL:
new LcpdfrVersionChecker(log).CheckDaily(12345, myVersion,
    "plugins/LSPDFR/MyPlugin/lcpdfr-version.stamp",
    result => notifier.Show(result.Message));   // Message includes color codes + URL

// Burnsie.Common's own download page (file id 54637), for library-freshness warnings:
new LcpdfrVersionChecker(log).CheckLibraryDaily(
    "plugins/LSPDFR/MyPlugin/burnsie-common-version.stamp",
    result => notifier.Show(result.Message));

The Result gives you Status, CurrentVersion, LatestVersion, DownloadUrl and Message (pre-formatted with LSPDFR color codes — pass it straight to a notifier). Comparison normalizes missing version components to zero, so a 4-component assembly version (1.1.0.0) equals the API's 1.1.0 instead of misreporting every install as a beta. The callback runs on a background thread — same thread-safety rule as above.

LibraryInfo — library identity

Version v = LibraryInfo.Version;          // the loaded Burnsie.Common assembly version
string name = LibraryInfo.DisplayName;    // "Burnsie.Common 1.0.1"

// At duty start (from a GameFiber): one-time "loaded successfully" toast + log line.
// Only the FIRST caller in the game session announces — several Burnsie plugins
// installed together never stack toasts.
LibraryInfo.AnnounceLoadedOnce();

Putting it together — a startup diagnostics pass

var report = new DependencyReport(log);
report.CheckFile("RAGE Plugin Hook", "RAGEPluginHook.exe", new Version(1, 124), true);

if (!report.HasBlockingFailure)
{
    LibraryInfo.AnnounceLoadedOnce();
    new LcpdfrVersionChecker(log).CheckDaily(myFileId, myVersion, stampPath,
        r => notifier.Show(r.Message));
}