Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
ServerInfo
Exposes a small HTTP JSON API with a Valheim server's world name, connected players (with Steam avatars), and installed mods - built for live status pages that read it directly from the browser.
CHANGELOG
Changelog
All notable changes to this project are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning (with the BepInEx-safe caveat in CONTRIBUTING.md — no prerelease suffixes).
Unreleased
2.2.7 - 2026-09-13
Fixed
- Stopping the server no longer logs a spurious
ObjectDisposedExceptionerror fromHandleLoop—StopServerclosing theHttpListenerwhile a request is pending is expected during shutdown, not a real failure.
2.2.6 - 2026-09-13
Added
- Licensed under GPL-3.0-or-later (see
LICENSE, full official text). GPL-3.0 requires forks/redistributions to keep this project's copyright and license notices intact — those notices point back to https://github.com/odin-sons/serverinfo. Added the matching SPDX header to every source file and aLicensesection to the README. LICENSEis now included in the published package zip.
Changed
manifest.json's andthunderstore.toml'swebsite_urlnow point to the repository instead of being empty.
2.2.5 - 2026-09-13
Added
- VirusTotal scan of the built package before publishing to either
platform, gated on the
VIRUSTOTAL_API_KEYrepository secret. A malicious/suspicious verdict fails the release before anything ships; the scan report link is added to the GitHub Release notes either way. - A VirusTotal badge in the README, linking to the latest release (where that release's own scan report is linked).
2.2.4 - 2026-09-13
Fixed
- Removed the em dash from
manifest.json'sdescription— Thunderstore's manifest validator rejects it (confirmed by hand, undocumented). Uses a plain hyphen now; a test guards against it coming back. CHANGELOG.mdis now actually included in the published package zip.tcli buildonly copiesicon/readmeautomatically; the changelog needed its own[[build.copy]]entry inthunderstore.toml.
2.2.3 - 2026-09-12
Fixed
- Hexium publish uploaded a corrupted package (
"Invalid ZIP file."from the server). PowerShell's$array[$a..$b]range-index isn't guaranteed to stay a[byte[]]— it silently decayed to a genericobject[], whichInvoke-WebRequest -Bodysent as something other than raw bytes. Switched to[Array]::Copyinto a realbyte[].
2.2.2 - 2026-09-12
Fixed
tcli publishin the release pipeline now tolerates Thunderstore's "already exists" response instead of failing the job — a version that publishes there successfully but fails at a later step (e.g. Hexium) can now be safely re-run without the Thunderstore step blocking it.
2.2.1 - 2026-09-12
Added
- Automated Hexium publishing in the release pipeline, alongside
Thunderstore. Reverse engineered from
Kesomannen/gale's open-source
client against Hexium's own (undocumented) submission API:
initiate a multipart upload,
PUTthe package bytes, finish the upload, then submit. No plugin code changes — release tooling only.
2.2.0 - 2026-09-12
Added
- Unit test project (
ServerInfo.Tests) covering the reflection helpers, ID/path parsing, and config parsing, plus packaging validation (manifest.jsonfields,icon.pngdimensions, and version consistency acrossProgram.cs/AssemblyInfo.cs/manifest.json/thunderstore.toml). - CI (
.github/workflows/ci.yml): builds and runs the full test suite on every push and pull request. - Automated release pipeline (
.github/workflows/publish.yml): pushing av*.*.*tag builds, tests, and — only if that passes — publishes to Thunderstore and attaches the package zip to a GitHub Release for a manual Hexium upload (Hexium has no public upload API yet). manifest.json,icon.png,thunderstore.toml, andpackage.ps1for publishing to Thunderstore and Hexium (see CONTRIBUTING.md).
Changed
- Breaking: no longer bundles its own copy of Newtonsoft.Json.
Declares a dependency on the shared
ValheimModding-JsonDotNETlibrary instead, to avoid two copies of the same assembly being loaded at once. Installs through a mod manager pull this in automatically; a manual DLL-only install now needs that library present too. - Packaged files no longer sit under a
plugins/subfolder in the release zip — they ship flat at the package root instead, somanifest.jsonends up next to the installed DLL (the plugin reads its own neighboring manifest.json at runtime;plugins/gets flattened straight intoBepInEx/plugins/on install, separating the two).
[2.1.0] - 2026-09-12
Added
Domainconfig ([Server]section) — this server's public domain or IP. It's purely a readiness flag for the plugin: theAccess-Control-Allow-Originheader is now only sent onceDomainis set, so a fresh install doesn't advertise a CORS policy before the server is actually meant to be reachable from the outside.AllowedOriginitself is unchanged (*by default).
[2.0.0] - 2026-09-12
Changed
- Breaking: renamed the project from PublicWebLink to Server
Info: plugin GUID changed to
Odin_Sons.ServerInfo, display name toServer Info, assembly toServerInfo.dll, namespace toServerInfo. BepInEx treats the new GUID as a different plugin and generates a freshOdin_Sons.ServerInfo.cfg; the oldMaddy.Publicweblink.cfgis not migrated.
[1.6.0] - 2026-09-12
Added
MetadataSourcesconfig ([Mods]section) — a comma-separated order of precedence (Manifest,Assembly) admins can set to control where a mod'sdescription/websiteUrl/dependenciescome from, down to disabling one source entirely or reversing the default priority.
[1.5.0] - 2026-09-12
Added
LogLevelconfig ([Logging]section) — a BepInExLogLevelflags value controlling which message levels this plugin writes to the log, defaulting toError, Warning; addInfoto also get startup/diagnostic messages.- Mods without a
manifest.jsonnow fall back to whatever their own assembly carries fordescription(AssemblyDescription),websiteUrl(an embeddedRepositoryUrl), anddependencies(their BepInEx dependency GUIDs), instead of always returningnull.
Changed
- Documented that the plugin works fully without
SteamApiKeyset —playersis still returned, just withoutAvatarUrl.
Fixed
- The "SteamApiKey is not set" warning is now logged once instead of on every refresh.
[1.4.0] - 2026-09-12
Added
- Numeric settings (
Port,RequestTimeoutSeconds,CacheIntervalSeconds,AvatarCacheMinutes) now declare an acceptable range, so BepInEx clamps an out-of-range value in the.cfgfile instead of accepting it as-is, and config-editor mods render them as a bounded slider.
Changed
- Config settings split into
[Server],[Cache], and[Steam]sections instead of one flat[General]. - Documented in README: how the avatar cache is keyed and expires, and that installing is just "drop the DLL" — BepInEx generates the config file with defaults on first run.
[1.3.1] - 2026-09-12
Changed
- The Windows URL-ACL access-denied message no longer suggests
user=Everyoneas the primary fix — it now points at finding and using the actual account running the server (whoami), withEveryonedocumented as a fallback rather than the default: it lets any local account on the machine claim the same URL reservation, not just the one that needs it.
[1.3.0] - 2026-09-12
Added
ServerInfoPathconfig option — the endpoint path no longer has to be/serverinfo.- CORS support (
AllowedOriginconfig,*by default) so a status page on another domain can call the endpoint directly from the browser. - A startup log line confirming the port and path the server is listening on.
- Startup now detects a Windows URL-ACL access-denied error specifically
and logs the exact
netshcommand to fix it.
Changed
- Errors while handling a request are now logged server-side (with the full exception), not just returned in the response body.
[1.2.0] - 2026-09-12
Added
- Avatar URLs are cached (
AvatarCacheMinutesconfig, default 60) and pruned once entries go stale, instead of being fetched fresh on every refresh for every connected player.
Changed
- Steam avatar lookups for all connected players are batched into a
single
GetPlayerSummariescall instead of one request per player. CacheIntervalSecondsandRequestTimeoutSecondsare now configurable instead of hardcoded.- Code reorganized from a single file into
GameReflection.cs,GameServerInfoProvider.cs,PackageManifestReader.cs,SteamAvatarService.cs, andModels.cs. - Renamed internal
Thunderstore*types/methods to be format-agnostic (PackageManifest,ParseNamespace) — Hexium uses the same namespace/name convention, so nothing here was Thunderstore-specific.
Security
- Steam avatar requests now use HTTPS instead of HTTP.
[1.1.1] - 2026-09-12
Fixed
namespacecoming backnullfor mods whose package folder has no version suffix (some mod managers update packages in place).
[1.1.0] - 2026-09-12
Changed
modsin/serverinfochanged from a plain string array to objects enriched with each mod's ownmanifest.json:description,websiteUrl,dependencies,namespace,packageName.- Build no longer requires a local Valheim or BepInEx install — moved to
NuGet-only dependencies (
BepInEx.Core,UnityEngine.Modules), withZNet/Peeraccess rewritten to use reflection instead of a direct assembly reference.
Removed
- The unused Harmony dependency.