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 toFileVersion) and parsed leniently —ParseVersiontolerates prefixes/suffixes likev1.124.1393.17586-betaand 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
Notifieris 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:
| Status | Meaning | Message tone |
|---|---|---|
UpdateAvailable | a newer minor/patch release exists | plain update notice |
MajorUpdateAvailable | a newer major release exists | "your build may now be unstable — please update" |
Beta | you 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));
}