Skip to content

Data Configs

Kit Oliynyk edited this page Nov 2, 2026 · 2 revisions

TL;DR: Game data lives in dreamland_world, mounted at the runtime table directory. One folder per kind of data. XML folders are read by table loaders, JSON files by Configurable plugins. Both are read when their plugin starts, so plugin reload most applies a change. Areas are the exception and load at boot only. Use when: you tune a number, add a skill, race, religion or command, need to know which code reads a file, or wonder why an edit did not show up. Source of truth: plug-ins/system/configurable.h, plug-ins/system/xmltableloaderplugin.h (TABLE_LOADER), src/dreamland.h (main config fields), src/plugin/pluginmanager.cpp, dreamland_world/. Verified: 2026-11-02 against dreamland_code 88da8302, dreamland_world 43880467, dreamland_fenia_public c28874b

How data is loaded

Mechanism What it reads When
Main config etc/dreamland.xml, the DreamLand object (src/dreamland.h) boot. The server rewrites it with the new worldTime every tick
Table loader (TABLE_LOADER(Class, "folder", "Node")) every .xml in dreamland_world/<folder>, one object per file when the owning plugin loads
Configurable (CONFIGURABLE_LOADED(folder, name)) dreamland_world/<folder>/<name>.json when the owning plugin loads
Area list area.lst.xml in areaDir, then each area file boot only
Fenia scripts the script directories named in the main config hot reload with cs commands, see Fenia-Scripts

Rules:

  • A table loader or configurable runs in the plugin's initialization. To apply an edit, reload that plugin by name or use plugin reload most. plugin reload changed compares the mtime of the plugin .so, so an XML-only edit never marks anything changed. Use most.
  • plugin reload all also unloads the [descriptor] plugin and drops every connection. most keeps it. Do neither with players online if you can avoid it.
  • A configurable file is parsed from UTF-8 and converted to the internal KOI8 encoding. A broken JSON file keeps the old value and logs an error. A missing file, or a file that did not parse, leaves C++ on its compiled defaults.
  • .config("folder/name") in Fenia returns the loaded JSON. Objects become Maps and arrays become array containers. A JSON float such as 0.5 reads as 0 and a boolean reads as 1 or 0 (measured live 2026-09-24), so a tunable shared by C++ and Fenia must be an integer (percent, centi-M). On a config array, for (v in arr) and a bare variable index throw, write arr[i + 0] instead. .config() copies the whole file on every call, so read once and keep the result.
  • A new JSON file needs a CONFIGURABLE_DECL in a plugin that has the JSON headers, otherwise .config() cannot see it. The fight plugin works, the ai plugin does not compile that way.
  • Never hand-edit a file the server writes (see the table below). The server rewrites it, and an edit made while it runs is lost.
  • In-game editors (hedit, skedit, cmdedit, socedit, raceedit, reledit, fedit, gredit and others) rewrite the XML of their table on the running server. A checkout on a running server can therefore differ from git until it is synced back.

Folder map

Folder Holds Loader (plugin) Notes
behaviors behavior definitions, one XML per behavior, plus services.json feniaroot (BehaviorLoader) each carries its help article. services.json lists the services mobs sell
bonuses daily and event bonuses (experience, learning, black friday) bonus
card-skills skills of the card deck skills_loader
clans clan definitions clan
clan-skills clan skills skills_loader
commands command definitions: name, aliases in three languages, flags, order flags, help command (CommandPluginLoader), commands/fenia by feniaroot channels.xml holds the channel wording
config JSON settings, weather XML and translations/ catalogs see the JSON table
craft-professions crafting professions craft
craft-skills craft skills skills_loader
craft-wearlocs tattoo wear locations craft
descriptions per-race, per-profession character descriptions for creation iomanager (nannyhandler.cpp) JSON, registered under descriptions/<race>
desires hunger, thirst, drunkenness, bloodlust desire
fenia.examples one sample script per Fenia entity kind none documentation only
fenia.local legacy .f++ scripts for a local server none by name, see Local-Setup KOI8-R text
fight combat and item JSON fight_core, fight, loadsave, race the biggest folder, listed below
generic-skills class skills and spells, one XML each, with the help article inside skills_loader the skill help id is the handler id, never delete or move it
gquests global quest definitions gquest the server writes these files
grammar declension rules and argument synonyms system
helps standalone help articles help abc maxhelp gives the next free id
hometowns hometowns: altar, recall, pit, limits hometown
languages in-game languages languages
legacy-behaviors old-style mob behavior definitions loadsave (mobilebehaviormanager)
liquids liquids liquid
notes note boards note the server writes these files
other-skills affect-only skills, set bonuses, tattoo gifts, breath attacks skills_loader
ports one XML per listening socket iomanager see below
prio command lookup priority, one JSON per language command decides which command a prefix resolves to
professions the thirteen professions profession
quests quest type definitions for the questor quest
race-aptitudes racial skills skills_loader
races races and mob races race
religions gods religion
scripts lint scripts for world data none run by hand
skill-groups skill groups with their cast flavour lines skills_impl
socials socials, one XML each social
spell spell JSON skills_impl
wearlocations wear locations wearlocation
areas.local demo areas for a local server areas through areaDir not live data

Top-level files: badnames.xml (names refused at creation), bugtracker.xml and spellpriority.xml (a KOI8-R file, the priority order of spells, read by SpellManager).

Encoding: XML files declare their own encoding. Nearly all are UTF-8. bugtracker.xml, spellpriority.xml and one note board are still KOI8-R. Keep the declaration when you edit.

Ports

ports/<number>.xml has port, listen, local (only localhost), backdoor (one-line login protocol, no character creation prompts), websock (WebSocket framing), wrapped, allowedIP. The shipped files:

Port Role
9000 telnet, character creation
1234 WebSocket for the web client
1236 WebSocket with the old character creation flow
9001 backdoor, open to the network
9127 backdoor, localhost only

apiPort in the main config is the HTTP API port and is not in ports.

Main config

etc/dreamland.xml, loaded into DreamLand (src/dreamland.h):

Field Meaning
pulsePerSecond, pulseViolence, pulseMobile, pulseTick timing, see Engine-Time-and-Pulses
options server flags: pk, log_all, log_imm, wizlock, newlock, save_objs, save_mobs, shutdown, buildplot, log_comm
basePath, tablePath, miscPath, libexecPath, dbPath runtime directories. tablePath is where dreamland_world is mounted
areaDir, areaListFile, savedDir area files, the list of areas to load, saved rooms and mobs
playerDir, playerDeleteDir, playerRemortDir, playerBackupDir, tempFile player files and their backups
feniaDbDir, feniaScriptDir, feniaPublicScriptDir Fenia database and script directories
immLogFile, logPattern, shutdownFile logs and the shutdown marker
apiPort HTTP API, 0 turns it off
bootVersion, worldTime, merchantBank counters the server maintains

buildplot marks a builder server: it turns off hunger and thirst updates and mob aggression against players.

JSON tunables

One row per file. "Read by" names the C++ source (under plug-ins/) that declares the file. Fenia scripts may read more files through .config().

fight/

File Read by Controls
to_hit.json loadsave/tohit.cpp hit chance, armor damage reduction, model switch, see Mechanics-Combat
saves.json fight/magic.cpp saving throw model and dispel chance, model 0 is the legacy roll
str_app.json, int_app.json, wis_app.json, dex_app.json loadsave/stats_apply.cpp per-stat bonus rows indexed by stat value: hit, carry, wield, damage, learn, practice, spell level bonus, missile hit and damage, defensive AC
damage_nouns.json, damage_verbs.json, attack_nouns.json, skill_dammsg.json fight_core/damage_impl.cpp, damage.cpp, attacks.cpp words used in damage messages, per language
material.json fight_core/material.cpp materials: price per kg, density, hardness, burns (ignition ease and burn duration, 0 never burns, -1 puts fire out), floats, vuln immunity bit, names. Wool at 4 to 5 is deliberate
item_value.json, item_affixes.json, item_weight.json, pc_baseline.json, spell_value.json, spell_combat_value.json, magic_items.json fight_core/* the item power ruler, see Item-Power
weapon_tiers.json, weapon_damroll_tiers.json, weapon_ave_tiers.json, weapon_ave_penalty.json, weapon_level_penalty.json, weapon_value2.json fight_core/weapontier.cpp, weaponcalculator.cpp weapon tiers, base hitroll and damroll, average damage per tier and level, per-class multipliers, level penalty and dice. Rows are indexed by the weapon_class table order
weapon_classes.json, weapon_names.json fight_core/weapongenerator.cpp weapon classes and generated names
weapon_affixes.json fight_core/weaponaffixes.cpp weapon flag affixes with prices, tier, alignment window and adjectives
weapon_defense.json fight_core/weapons.cpp defence factors per weapon class in percent
armor_profiles.json, armor_names.json fight_core/armorgenerator.cpp armor families and names
mob_tiers.json race/mobbodyconfig.cpp mob tiers: how hit points, damage, armor, experience and variance derive from level, race and form. Tier 10 is the training dummy
mob_forms.json race/mobbodyconfig.cpp mob forms and parts, their groups, renames and effects
loot.json fight/fight_death.cpp corpse looting: share lost by a wanted player, items allowed per corpse for others, which loot kinds can be taken
combat_ai.json, boss_mods.json declared in fight/fight_death.cpp profiles and boss moves for the scripted combat AI

weapon_names.json and weapon_classes.json must have the same set of weapon class keys. If one has a key the other lacks, name generation returns early, the name config stays at its default and the next short-description build throws, which crashes the server on every area reset.

config/, spell/, grammar/, prio/, behaviors/

File Read by Controls
config/update.json updates/update.cpp autoquit: minutes idle before a player is quit, -1 off. lostlink: minutes before a link-dead player is quit, 0 means at once
config/areaquest.json quest/core/areaquestcleanupplugin.cpp lifetime: days before an untouched area quest is cancelled
config/affectpanel.json web/impl.cpp the columns and short labels of the web affects panel
config/flagmessages.json system/morphology.cpp per-language names of flag table entries
config/mssp.json iomanager/mssp.cpp MSSP server status fields
config/settings.json comm/configweb.cpp pages, wording and limits of the web settings dialog
config/achievements_public.json comm/help.cpp public achievement list
config/weather.xml updates/weather.cpp weather and sunrise lines per season, three languages
config/translations/*.json system/translations.cpp translation catalogs, see L10n
spell/damage_tiers.json skills_impl/feniaskillaction.cpp spell damage dice per tier at level 1 and level 110
spell/handless_flavour.json skills_impl/defaultspell.cpp cast lines for casters without hands
grammar/rules.json system/morphology.cpp Russian and Ukrainian ending rules for declension
grammar/synonyms.json system/arg_utils.cpp argument synonyms: all, yes, no, in, on, from, to, by
prio/commands_<lang>.json command/commandmanager.cpp command order for prefix matching, one list per language
behaviors/services.json feniaroot/behaviorloader.cpp services sold by mobs: names, prices, spell, target

Files the server writes

Do not hand-edit while a server runs: config main file values (worldTime), gquests/*.xml, notes/*.xml, bugtracker.xml, and anything an in-game editor owns.

Adding a file or a tunable

  1. New value in an existing file: add the key, read it with a default in C++ (item_value("measure", "key", default) style) and tolerate absence. In Fenia, check for null.
  2. New JSON file: declare it with CONFIGURABLE_DECL(folder, name) or CONFIGURABLE_LOADED(folder, name) in a plugin with JSON headers. Rebuild. The file name and folder become the .config() path.
  3. New XML table: add a TABLE_LOADER(Class, "folder", "Node") and register the class. See Engine-Architecture.
  4. After editing, plugin reload most for a running dev server, then check the log for Configurable <path> loaded with N entries.

See also

Clone this wiki locally