Namespace McServerLauncher.Services
Classes
- AppSettingsService
Loads and saves the global settings in %APPDATA%\McServerLauncher\settings.json.
- AtomicDownload
Downloads a file so that a failure can never damage what was already on disk.
Writing straight to the destination truncates it the moment the stream opens, long before the download is known to be good. A connection dropped halfway then leaves a valid path holding a half a file — and for the Fabric server jar it was worse than that: the structural check that runs afterwards deletes what it rejects, so an interrupted loader change turned a working server into one with no jar to start at all.
So the bytes go to "<dest>.part", verification runs against that, and only a file that arrived complete and passed its check replaces the real one — in a single filesystem move. This is the same guarantee AtomicJsonFile gives the app's JSON, applied to binaries.
- AtomicJsonFile
Atomic load/save for the app's JSON files (servers.json, settings.json), so a crash or power loss mid-write can never truncate them. Writes go to a ".tmp" file that atomically replaces the target, keeping the previous version as ".bak". A corrupt file is quarantined as ".bad" and the ".bak" copy is restored when possible, instead of silently starting from scratch.
- AtomicTextFile
Writing a config file the app owns: only when it actually changed, and never half-written.
- BrowserLauncher
Opens a link in the user's browser.
Everywhere else in the app the URL is a constant we wrote. In the store it comes from Modrinth — an author fills in "source", "wiki" or "discord", and the long description is full of links — so it is untrusted input.
UseShellExecutehands whatever it is given to the shell, which would happily run a local executable or a registered custom scheme, so only absolute http/https URLs are ever passed through.
- BukkitPathRule
The two characters a Paper or Purpur server refuses to run from.
- Changelog
Per-version "what's new" notes. When the user updates across several versions at once, the notes for every version they hadn't seen yet are shown together (newest first), so nothing is missed. Add a new entry (newest first) plus its
Whatsnew_x_y_zresx keys on each release.
- ConsoleColors
The colour each kind of console line is drawn in, as data.
- ConsoleLineClassifier
What a console line is about: its severity, and whether it is chat, a player event, or the app.
- ConsoleLogService
Persists every server's console output to a shared, dated log file (%APPDATA%/McServerLauncher/logs/launcher-yyyy-MM-dd.log) so the history survives the app being closed or crashing, not just the in-memory console shown in the UI. A new file starts each day; files older than McServerLauncher.Services.ConsoleLogService.RetentionDays are pruned so the folder doesn't grow forever.
- ConsolePreferences
The two console colours the user can change, app-wide.
- ContentDependencyCheck
Whether every installed mod and plugin has what it needs, answered from the jars alone.
- ContentDependencyCheck.Missing
Something needed that nothing installed provides.
- ContentManifest
What a mod or plugin jar says about itself: the names it provides, and the ones it needs.
- ContentManifest.Manifest
One jar: what it offers under what names, and what it needs to be there.
- ContentMigrationService
What happens to the mods or plugins already installed when a server changes family.
- CrashReportService
Looks for a Minecraft server crash report relevant to the server's most recent run, to show a short human-readable reason alongside "the server exited unexpectedly" instead of just an exit code. Vanilla/Fabric/Forge/Paper all write crash reports to "<folder>/crash-reports/" with a stable, decade-old format: a "---- Minecraft Crash Report ----" header followed by a "Description: ..." line summarizing what went wrong.
- CreateAgentResult
Result of
/v1/partner/create_agent: the per-user self-managed agent minted for the user from their setup code. AgentSecretKey is what the app stores (encrypted) and uses as theagent-keyfor all subsequent tunnel management.
- CrossplayService
Setting a server up so people can join from Bedrock as well as Java.
- DeathMessageDetector
Detects Minecraft death/kill messages in a server console line, for the "deaths" notification. Best-effort and English/vanilla-oriented: the server's locale or plugins may word some deaths differently. Pairing a death-phrase match with a "subject is a valid player name" check keeps it from firing on chat lines (which start with a "<name>" tag) or other log output.
- DesktopShortcutService
Puts a shortcut to the app on the user's desktop.
Each desktop means something different by "shortcut": Windows wants a
.lnk, Linux a.desktopentry that has to be executable and, on GNOME, explicitly trusted, and macOS a symlink to the bundle. What they share is that the target must be whatever this copy is really running from — an AppImage the user dropped in Downloads, a bundle in /Applications — and not a guessed install path.
- DownloadVerifier
Verifies a downloaded file's hash against the checksum an official API (Mojang, Adoptium, Paper) already returns alongside the download URL. On mismatch the file is deleted and an exception is thrown, so a corrupted or tampered download is never silently trusted.
- FileHashCache
The SHA-1 of a file, remembered for as long as the file has not changed.
- GeyserConfigService
Geyser's
config.yml: where it lives, and the two ports the launcher has to set in it.
- GeyserDownloadsApi
GeyserMC's downloads API, which the app reads for Floodgate and for Hydraulic.
- GeyserDownloadsApi.Artifact
One published artifact: which build it came from, and how to verify it.
- HydraulicService
Hydraulic: what lets Bedrock players actually see the blocks and items that mods add.
- ImageCache
Remote images (project icons and gallery screenshots) with a memory + disk cache in front.
The URLs come from Modrinth's API, but they are still remote input, so every download is guarded: the response has to declare an image content-type and stay under a byte cap that is enforced while streaming, so a missing or lying Content-Length can't balloon memory either. Anything odd yields null and the caller keeps its placeholder.
Decoding happens on the calling (background) thread, never on the UI thread. Bitmaps are cached and handed to several views at once, so they are deliberately never disposed here — a disposed bitmap still bound to an
Imagewould throw when it is drawn.
- JavaService
Detects the machine's Java installations and, if needed, downloads the right version (Adoptium Temurin) for a specific Minecraft version. Works on Windows and Linux.
- LoaderPaths
Where each mod loader leaves the files the launcher has to find again afterwards.
- MarkdownBlock
One block of the description: a paragraph, a heading, a list item…
- MarkdownParser
A small Markdown reader for the long descriptions Modrinth returns.
It is deliberately partial. Those descriptions are Markdown with raw HTML mixed in, written to be rendered by a web page, and pulling in a full Markdown engine (and an HTML sanitiser behind it) to show them in a desktop panel would be a large dependency for a read-only view. What is supported is what those pages actually use: headings, lists, quotes, code, emphasis, links and rules. Everything else — HTML tags, images, scripts — is dropped rather than shown raw, so a project page can never inject markup into the app.
Images are dropped on purpose: the gallery already shows them, and a description with thirty remote images would mean thirty downloads for a page the user may only skim.
- MarkdownSpan
A run of text inside a block, with the formatting that applies to it.
- MinecraftRange
Does this Minecraft version satisfy the range a mod declares?
- MinecraftVersionService
Gets the list of Minecraft versions from Mojang's official manifest and downloads the server.jar of the chosen version.
- MinecraftVersionService.VersionDetails
server.jar URL, required Java version and its official SHA-1 (for integrity checking).
- ModDependencyService
The library mods almost every mod needs, and that nobody remembers to install by hand.
- ModDependencyService.Needed
One dependency that has to be downloaded, already resolved to a concrete file.
- ModDependencyService.Plan
What is missing, and what could not be worked out.
- ModLoaderService.ForgeInstallResult
Outcome of a Forge server install: a runnable jar (old Forge) or an args id (modern Forge).
- MultiVersionService
Letting people join from a Minecraft version other than the one the server runs.
- NameIssue
The problem found, and whatever detail the message needs.
- NeoForgeVersions
Turning "which Minecraft version?" into "which NeoForge build?".
- NeoForgeVersions.Choice
A chosen build, and whether the user is about to install a pre-release.
- NotificationCatalog
What each kind of notification looks like: its level, and the emoji that identifies it.
- NotificationCatalog.Entry
One kind of notification: how serious it is, and how it is marked.
- NotificationPalette
The default colour of each notification level, and what counts as a valid one.
- NotificationPreferences
Decides whether a given notification should be shown for a given server, combining the global settings with an optional per-server override. Global is app-wide state (like
ToastService.Shared): set once at startup from AppSettings and updated when the user edits the global notification settings.
- PaperService
Downloads the Paper server jar from PaperMC's "fill" API (v3). Paper is a runnable jar, so it launches like vanilla (-jar). Plugins go in the server's plugins/ folder.
- PlayersService
Reads the player lists the server stores in JSON files: ops.json (operators), banned-players.json (banned) and usercache.json (known).
- PlayitAgentRunner
Runs Playit's official agent (
playitd) as a child process so the user's tunnels actually forward traffic — without them installing anything. The binary is downloaded once (pinned to the same version the app registers, McServerLauncher.Services.PlayitAgentRunner.AgentVersion) and launched with--secret-path(see McServerLauncher.Services.PlayitAgentRunner.SecretPath) pointing at the per-user agent key from the setup-code flow. One agent serves all of the user's tunnels; it runs while the app is open and connected, and is stopped on shutdown. App-wide singleton.
- PlayitApiException
Error returned by the Playit API (status != success).
- PlayitApiService
Playit.gg API client.
- Preferred: a per-user self-managed agent secret key from the partner setup-code flow
(PlayitPartnerService), set app-wide via SetAgentKey(string?) and used as
agent-keyfor both reads AND writes. - Fallback (legacy): the agent's secret_key from playit.toml (reads) and a user-pasted write key (writes, sent as Api-Key/Agent-Key). Auth is resolved by trying the schemes in order, so a caller doesn't need to know which kind of key it holds.
- Preferred: a per-user self-managed agent secret key from the partner setup-code flow
(PlayitPartnerService), set app-wide via SetAgentKey(string?) and used as
- PlayitApiService.PlayitTunnel
One tunnel as the agent reports it.
- PlayitManager
Playit.gg integration that relies on the background Playit agent already keeping the tunnels up 24/7. The app does not launch its own playit binary: it only queries and, when possible, starts/stops the agent.
- On Windows the agent is a Windows service ("playitd"), managed via ServiceController.
- On Linux it is typically a systemd unit, managed via
systemctl(start/stop may need privileges).
- PlayitPartnerService
Third-party "Integration"-tier onboarding: exchanges a Playit
account_setup_code(that the user obtained from playit.gg) for a per-user self-managed agent secret key. The request goes through a small proxy (a Cloudflare Worker, seeplayit-proxy/) that injects the partner Api-Key server-side — so NO secret ships inside this (public, open-source) app. Everything after uses the returned per-user secret via PlayitApiService.
- PortService
Checks which ports are in use on the machine (by any application) and helps find the next free one. TCP and UDP are asked separately because they are separate namespaces.
- ProcessStatsService
Computes CPU usage (%) and RAM (MB) of a process, sampling the CPU time between consecutive calls.
- PurpurService
Downloads the Purpur server jar. Purpur is a Paper fork: a runnable jar, plugins in
plugins/, and every Bukkit plugin works on it unchanged.
- PurpurService.PurpurBuild
A build of Purpur, and the hash their API publishes for it.
- SecretProtector
Protects small secrets (like the Playit API key) at rest, on every platform:
- Windows: DPAPI scoped to the current user, stored as "dpapi:" + base64. Only the same Windows user on the same machine can decrypt it.
- Linux/macOS: AES-256-GCM with a random per-user key kept in a file only the user can read (0600), stored as "aes:" + base64(nonce | tag | ciphertext). Both protect the settings file against other users and accidental leaks (backups, sharing the file); neither protects against malware already running as the same user — DPAPI can't either.
- SelfUpdater
Replaces the running application with an already downloaded and verified package, then restarts it — the same "press Update and it just happens" behaviour on every platform.
Each platform ships differently, so each is applied differently: Windows runs the silent installer, Linux swaps the AppImage file the app is running from, and macOS mounts the .dmg and replaces the .app bundle. What they share is the shape: nothing is touched until a complete, checksum-verified package exists on disk, and any failure leaves the current install working.
- ServerCreationService
Generates the initial files of a new server: eula.txt, run.bat and a minimal server.properties with the chosen port (Minecraft fills in the rest on the first launch).
- ServerDetectionService
Fills in Type/GameVersion/loader info for servers saved before those fields existed (i.e. GameVersion empty), by inspecting the server folder. Best-effort, runs on load so the mods browser works for older Fabric/Forge servers.
- ServerIconService
Generates a server's server-icon.png (64x64 PNG) from any image, cropping it to a centered square and scaling. This is the icon players see in the server list. Uses SkiaSharp so it works on Windows and Linux.
- ServerJarInstaller
Puts the right server files on disk for a server type, whichever way that type is obtained.
- ServerJarInstaller.InstallResult
What the install left behind, in the shape the caller needs for its config.
- ServerNameRule
Checking a server's folder name before it becomes a server that will not start.
- ServerProcessManager
Manages the lifecycle of a Minecraft server's java process: startup, clean shutdown (sending "stop" over stdin), command sending and re-emitting the console output in real time.
- ServerPropertiesService
Reads and writes the server.properties file (key=value format, one per line). Used to read values (e.g. the port) and to update them from the visual configuration screen.
- ServerStorageService
Loads and saves the list of registered servers in %APPDATA%\McServerLauncher\servers.json.
- ServerTypeCatalog
One row per server type: what it is called, what it takes, and whether Bedrock can reach it.
- ServerTypeCatalog.Entry
Everything the app knows about one server type.
- SingleInstance
Keeps the app to one running copy per user, and lets a second launch bring the first one back to the front instead of opening a window of its own.
- StoreCache
Two-level cache (memory, then disk, then the network) for the store's API responses. It exists so that opening a mod — and going back and opening it again — costs one request, not one per visit, and so that a project already seen still opens with no connection.
Concurrent callers asking for the same key share a single fetch: opening a details page kicks off the project, its versions and its dependencies at once, and the related-mods strip may ask for a project that is already in flight.
Entries are kept on disk beyond their freshness window on purpose: when the network fails, a stale entry is a much better answer than an empty page. Anything older than McServerLauncher.Services.StoreCache.MaxDiskAge is pruned once per run.
- StoreSummaryService
Answers "what does this actually do to my server?" in the user's own language.
Modrinth's own one-line description is written by the author, in English, and often for other modders ("An intermediary api aimed to ease developing multiplatform mods"). So the store ships a hand-written catalogue for the projects a server owner is most likely to meet, in the five languages the app speaks. It is looked up locally: no request, no key, no cost, and it works offline.
Anything outside the catalogue falls back to a sentence built from what Modrinth does tell us — the kind of project, its main tag and, above all, whether players have to install it too, which is the one thing that decides whether a mod is usable on a public server.
The catalogue can be replaced without rebuilding by dropping a
store-summaries.jsonin the user's data folder.
- StoreTagService
Turns a store item into the app's own tags.
Modrinth's categories are a good start but they are coarse — nearly half of the top server mods are filed under "utility" — and they don't say the one thing a server owner cares most about: whether players have to install the mod as well. So the categories are combined with keyword rules and with the client/server side, all of which live in
Resources/store-tags.json.The catalogue is read from the embedded copy, unless
%APPDATA%\McServerLauncher\store-tags.jsonexists, in which case that file is used instead. Tags can therefore be added, translated, recoloured or re-mapped without a new build.
- UpdateService
Checks the GitHub Releases for a version newer than the installed one.
- UpdateService.UpdateInfo
Update data. PackageUrl/PackageName are the package for the platform this app is running on — the Windows installer, the Linux AppImage or the macOS .dmg for this architecture — and are null when the release ships nothing usable here. ChecksumUrl is the asset that carries its SHA-256, used to verify the download before it is installed; null on releases published before that existed.
- VerifiedJarDownload
Fetching a server jar: announce the size, download atomically, verify, say it is done.
- WakeOnDemandListener
Answers Minecraft clients on the server's port while the real server is stopped, so a stopped server can say "I'm asleep, come in and I'll wake up" instead of just refusing the connection.
It speaks the small, stable part of the protocol needed for that: the handshake, the server-list status, and the login disconnect. Pressing Join is what wakes the server — the client re-pings every few seconds while the multiplayer screen is open, so waking on a status request would start the server over and over for people who are not even playing.
With a Playit tunnel this socket is reachable from the internet, so everything it reads is treated as hostile: lengths are bounded before anything is allocated, every connection has a deadline, and the number of them at once is capped.
- WakeStatus
What a client is told about a server that is currently asleep.
- WhitelistService
Manages a server's whitelist.json file (list of allowed players). Each entry has uuid + name. It resolves the UUID from Mojang (online mode) or computes it offline when the server does not use official accounts.
- WindowBehavior
What the window's minimize and close buttons do, as chosen in the settings. App-wide state (like Global): set at startup from the saved settings and updated when the user edits them, so the change takes effect without restarting the app.
- WorldBackupService
Creates and restores zip backups of a server's world folder — the "level-name" directory from server.properties ("world" by default). That single folder holds every dimension, including the modern layout that nests them under "dimensions/", so zipping it alone is a complete backup. Backups live in "<server folder>/backups/"; old ones beyond the configured retention are pruned after each new one.
Structs
- Changelog.Section
A version and its localized notes.
Enums
- AgentRunState
State of the embedded Playit agent process.
- AtomicJsonFile.LoadOutcome
What happened when loading a JSON file.
- CrossplayLevel
How well Bedrock players can actually play on a server type.
- MarkdownBlockKind
What a parsed block of a project's long description is.
- NameIssueKind
What is wrong with a server's folder name, when something is.
- PlayitApiService.TunnelEdition
Which edition a tunnel carries: they are different protocols, not a preference.
- ServerFamily
What a server type accepts: plugins, mods, or neither.