Architecture

Static Content, Dynamic State, Runtime Cache

Game data lives in three places. Knowing which is which saves you hours.

   STATIC CONTENT           DYNAMIC STATE             RUNTIME CACHE
   ──────────────           ─────────────             ─────────────
   dist/data/*.xml           MySQL                    Singletons in
   buylists/                (per-chronicle            data/xml/ &
   multisell/                schema in                data/sql/
   spawns/                   dist/db_installer/
   stats/                    *.sql)                   HtmCache
   zones/                                             World grid
   scripts/ (java)          players, clans,           Managers
   html/                    items, mail,
   geodata/                 olympiad, ...

      ▲                       ▲                         ▲
      parsed on boot          read/write at            filled on boot,
      into POJOs              runtime via JDBC         queried by code

                                  ▼
                            gameserver code
                  (XML loaders, SQL tables, in-memory singletons
                   all called from handlers, managers, packets)

The three tiers

Static content - dist/data/*.xml

Items, skills, NPCs, multisell lists, buylists, spawns, zones, drop tables, geodata. Authored as XML, hand-written or copied from retail observation. Parsed exactly once at boot by Java loaders in gameserver/data/xml/, turned into immutable POJOs, and kept in singletons for the rest of the server's life.

If you change an XML file the on-disk content has updated, but the in-memory singleton is stale. On a development server you can refresh it with the matching //reload <type> admin command (see the reload reference); on a live server the recommended fix is a restart, because //reload carries a dev-only warning.

Dynamic state - MySQL

Anything that has to survive a server restart and that changes during play:

  • Player characters: name, class, position, stats, inventory, skills learned.
  • Clans: members, reputation, alliance, war declarations.
  • Items in the world: existing item instances and their owners.
  • Mail, offline trade listings, Olympiad standings, daily mission progress.

The schema lives in dist/db_installer/*.sql. Java access goes through table classes under gameserver/data/sql/ (e.g. ClanTable, OfflineTraderTable) which wrap JDBC reads/writes against the HikariCP pool.

Runtime cache - Java singletons

The in-memory state derived from the first two tiers:

  • ItemData, SkillData, NpcData, MultisellData, ... - the parsed XML.
  • ClanTable, AnnouncementsTable, ... - the cached SQL.
  • HtmCache - in-game HTML pages, loaded lazily.
  • World - the spatial grid of every WorldObject currently online.
  • Every *Manager singleton - its working state.

Most code talks to this tier, not directly to XML or SQL.

Why the split matters

Confusing these tiers is the most common reason a change "doesn't take":

  • Edit an item XML and forget to //reload item (or restart)? Old values still in the singleton cache.
  • Edit a row in the database while the server runs? Singletons that cache it will not notice.
  • Add a new field to the XML but not the loader? It is silently ignored.
  • Add a column to the schema but not to the table class? The new column is invisible.

The rule is simple: XML changes need a restart, SQL changes need a restart unless that table has a reload command, code changes need a rebuild + restart.