Pantheon is a RuneScape private server. If you've never heard of an RSPS, here's the short version: Old School RuneScape is an MMO that Jagex has run since 2013 (as a nostalgia re-release of the 2007 version). An RSPS is an independently operated server that emulates the official game — same client, same world, custom content. Thousands of them exist. Most are terrible. I built one that isn't.
This is the technical story of what it takes to build an MMO server from scratch in 2026. Even if you've never played RuneScape, the engineering problems are genuinely interesting.
Why People Build Private Servers
The official game has problems. Updates that the community hates. Grind timescales measured in months. Monetization pressure from Jagex's parent company. Bot infestations. A polling system that blocks content because 24.9% of players voted no.
Private servers fix this by giving the operator full control. Want 10x XP rates so players can reach endgame in a week instead of a year? Done. Want to add a custom boss that drops items the official game never will? Done. Want to run a pure PvP server with no skilling at all? Done. The RSPS scene is essentially modding culture for an MMO that doesn't officially support mods.
The 4-Repo Architecture
Pantheon is split across four repositories, each handling a different layer of the stack:
- Server (Kotlin): Built on the Zenyte framework. This is the game engine — it handles player connections, world simulation, NPC behavior, combat calculations, skill processing, item systems, and every piece of game logic. Kotlin was chosen over Java (the traditional RSPS language) for null safety, coroutines for async tick processing, and extension functions that make the game content DSL readable. The server processes game ticks at 600ms intervals, the same rate as the official game.
- Client (Java): A fork of RuneLite, the most popular open-source OSRS client. RuneLite gives us GPU rendering, plugin support, and a UI framework that players already know. Our fork adds custom login screens, server-specific UI panels, and modified networking to connect to Pantheon instead of the official servers.
- Web (Next.js 16): The website and content hub. Player hiscores, item databases, quest guides, server status, vote pages, and a store for cosmetic items. 180+ statically generated pages built from game data. Next.js 16 with Tailwind for the frontend, PostgreSQL for player data, and ISR for pages that update when game content changes.
- Bot (Discord.js 14): Community management and game integration. Links Discord accounts to in-game accounts. Posts automated announcements when players hit milestones. Handles support tickets. Syncs donor ranks between the store and the game server. Runs the QA automation pipeline.
The Cache: Where Everything Lives
This is the part that makes RSPS development genuinely hard. The game cache is a compressed binary archive that contains every visual and data asset the client needs:
- Models: 3D meshes for every item, NPC, object, and player equipment piece in the game. Thousands of models, each stored as indexed vertex/face data in a custom binary format.
- Animations: Skeletal animation data for every action — walking, running, combat attacks, skill actions, emotes. Each animation references a skeleton and a sequence of frame transformations.
- Definitions: Structured data for every game entity. Item definitions (name, value, equip slot, bonuses). NPC definitions (name, combat level, hit points, attack speed). Object definitions (name, interaction options, collision data). These are the lookup tables that both the client and server reference constantly.
- Maps: Terrain data for the entire game world. Height maps, overlay tiles, underlay tiles, object placements, NPC spawn points. The world is divided into regions, each region stored as compressed map data in the cache.
Pantheon uses the rev-236 cache format. That number — 236 — refers to the game revision. Each revision changes the binary format slightly, adds new assets, and sometimes reorganizes entire sections. Building for rev-236 means every cache tool, every definition loader, every model renderer has to understand that specific format. Tools built for rev-220 won't work. Documentation is sparse. You read the cache format by reading decompilers and other servers' source code.
The Plugin System
Game content in Pantheon is written as plugins. A plugin is a self-contained unit of game logic: a quest, a minigame, a skill training method, an NPC dialogue tree, a shop. The plugin system gives each piece of content its own file (or set of files), its own state management, and its own event hooks.
A typical plugin hooks into game events — player clicks object, player enters region, NPC dies, timer expires — and executes content logic in response. The Kotlin DSL makes this readable. A woodcutting plugin reads like a description of woodcutting: check the player's level, check if they have an axe, start the chopping animation, roll for success on each tick, grant logs and XP on success, deplete the tree and start a respawn timer.
This architecture means contributors can add content without understanding the engine. You don't need to know how tick processing works or how the network protocol serializes messages. You write a plugin, register it, and the engine handles the rest.
The QA Skill Grinder Bot
Here's where automation gets interesting. RuneScape has 23 skills (Attack, Strength, Defence, Ranged, Prayer, Magic, Cooking, Woodcutting, Fletching, Fishing, Firemaking, Crafting, Smithing, Mining, Herblore, Agility, Thieving, Slayer, Farming, Runecraft, Hunter, Construction, and Hitpoints). Each skill has dozens of training methods across 99 levels. That's hundreds of interactions that need to work correctly.
I built a bot that automates all 23 skills. It creates a test account, logs in, and methodically trains every skill from level 1 to a target level using every available training method. It verifies that XP is granted correctly, that items are consumed and produced correctly, that animations play, that level-up messages fire, and that unlocks happen at the right thresholds.
When a code change breaks fishing at level 45 because a definition ID shifted in a cache update, the bot catches it before any player does. It runs as part of the CI pipeline. Every PR that touches game content gets a full skill regression pass.
Content Pipeline: Wiki to Web
The 180+ pages on the Pantheon website are generated from game data, not written by hand. The pipeline works like this: cache definitions get extracted into JSON (every item, NPC, and object becomes a structured data file). That JSON feeds into Next.js static generation. Each item page shows the item's stats, where it drops from, what it's used in, and its trade value. Each NPC page shows combat stats, drop tables, and location.
When game content changes — a new item is added, a drop table is rebalanced, an NPC is moved — the pipeline regenerates the affected pages automatically. No manual wiki editing. No stale data. The website is always in sync with the actual game server.
Balancing Nostalgia and Modernity
The hardest design problem in RSPS development isn't technical — it's philosophical. Players come to private servers because they love Old School RuneScape. They want the nostalgia. But they also expect modern quality of life: smooth UIs, fast load times, responsive controls, clear feedback. You can't just clone the 2007 experience exactly, because the 2007 experience had terrible UX by modern standards.
Pantheon's approach: keep the core game loop identical (same tick rate, same combat formulas, same skill mechanics) but modernize everything around it (better client rendering via RuneLite, a real website instead of a forum, Discord integration instead of in-game-only chat, automated systems instead of manual admin intervention). The game feels like RuneScape. The experience around the game feels like 2026.
Why Kotlin Over Java
The RSPS community has used Java for 15+ years. Almost every framework, every tool, every tutorial is in Java. Going with Kotlin was a deliberate choice:
- Null safety: Game servers are full of nullable state — a player's target might be null, an item slot might be empty, an NPC's spawn point might not be set yet. Kotlin's null safety catches these at compile time instead of crashing at runtime.
- Coroutines: Game tick processing is inherently sequential (process all players, then all NPCs, then all timers, then send updates), but within each category, work can be parallelized. Coroutines make this clean.
- Extension functions: The content DSL uses extension functions heavily. Player.giveItem(), NPC.walkTo(), World.spawnObject() — these read naturally and keep content code separate from engine code.
- Full Java interop: Every existing Java RSPS library works in Kotlin without modification. We didn't give up the ecosystem — we added to it.
The Result
Four repos. Thousands of game assets. 23 skills automated for QA. 180+ generated web pages. A Discord bot tying it all together. And a game server that processes ticks at exactly 600ms because that's what makes it feel like RuneScape.
Building an MMO server — even a private one — is one of the most complex software projects a solo developer can attempt. It touches every domain: networking, databases, 3D rendering, binary file formats, game design, web development, DevOps, community management. Pantheon is the project that taught me more about software engineering than any other, and it's still the one I'm most proud of.