Summary
Add an export function which generates player-facing documentation from the
GameConfiguration of a running server. The output is a set of Markdown/MDX and JSON
files that a static site generator (Docusaurus, or any comparable tool) turns into a
website for the players of that specific server.
The important property: because the docs are generated from the actual configuration
of that deployment, they describe the server as it really is — including custom items,
adjusted drop rates, changed experience rates and enabled/disabled plugins — instead of
generic MU Online information copied from a fan wiki.
Motivation
Every hosted OpenMU server currently has the same problem: players ask where an item
drops, which monsters are on which map, what the requirements of a skill are, or what
the Chaos Machine success rates are. Operators answer this with hand-maintained wikis,
forum posts or Discord pins, which are laborious to write and silently go stale as soon
as the configuration is changed.
All of this information already exists in the GameConfiguration aggregate. Rendering it
is a projection of existing data, not a new source of truth. Doing it once, in the
project, means every server operator benefits and nobody has to maintain a wiki by hand.
Scope
In scope
- A generator that reads the
GameConfiguration and writes Markdown/MDX + JSON.
- An "Export documentation" action in the admin panel, plus an equivalent CLI entry point
so it can be scripted.
- Writing the result to a configurable output folder.
Out of scope (deliberately)
- The Docusaurus site itself — theme, branding, server rules, connection guide, event
schedule. That is operator-specific content and belongs in a separate template
repository that operators fork. This issue only covers producing the content that
such a site consumes.
- Publishing/deployment (see "Publishing" below).
Proposed content
Generated from configuration:
- Items —
ItemDefinition with requirements, level table, possible options
(ItemOptionDefinition), set bonuses (ItemSetGroup), which classes can wear them.
- Monsters —
MonsterDefinition with attributes, on which maps they spawn, and their
drops.
- Maps —
GameMapDefinition with spawn areas, exit gates, safezone, level
requirements, connections to other maps.
- Skills — requirements, damage, mana/AG cost, which classes learn them.
- Character classes — stat growth, evolution paths, starting equipment.
- Crafting — Chaos Machine /
ItemCrafting definitions with success rates,
ingredients and results; jewel mixes.
- Quests — requirements, steps, rewards.
- Server settings — experience rate, drop rate, and other values players care about.
Technical approach (open for discussion)
Where the code lives
A new project under src/, e.g. MUnique.OpenMU.PlayerDocs.Generator, referenced by the
admin panel and by a small CLI host. Nothing in the runtime path should depend on it —
MUnique.OpenMU.Startup must not gain a dependency.
The configuration is loaded through IPersistenceContextProvider, the same way the
DataInitialization projects do it. Supporting an exported configuration JSON as an
alternative input would make the generator usable in CI without a running server.
Derived values — the part that needs care
Some of the most useful information for players is not a stored field but a derived
value:
- "Which monsters drop item X" follows from
DropItemGroup chances, monster-level
dependent group selection, map-specific groups and the item level/option roll.
- Character damage and stat values come out of the
AttributeSystem with its power-up
definitions.
These must be computed by reusing the existing game logic, not reimplemented in the
generator (and certainly not in JavaScript in the site). A parallel implementation will
silently drift from the server and publish wrong numbers, which is worse than publishing
nothing. Enabled PlugInConfiguration entries should be taken into account as well,
since they can change behaviour.
Output shape
Season 6 has on the order of a thousand item definitions and several hundred monsters.
Generating one page per item per level would produce a page count that makes static
site builds slow and memory-hungry.
Suggested instead:
- One page per definition, with a level table.
- For large catalogues, emit JSON and let the site render it with client-side
components (filterable item browser, drop lookup). Docusaurus is React-based, so this
is straightforward and gives players filtering that static tables cannot.
- Real pages only where they add value: maps, classes, guides.
Determinism
Output must be deterministic: stable ordering, stable slugs, stable file names, no
timestamps in frontmatter. Operators will want to commit the generated output and see a
meaningful diff when they change a drop rate. Non-deterministic output makes that
useless.
Atomic writes
The export should write to a temporary directory and move it into place when finished,
so a consumer never picks up a half-written tree. A manifest.json with a content hash
lets a build step skip work when nothing changed.
Localisation
Emit stable translation keys rather than baking English strings into the generated
Markdown, so the site's i18n layer can sit on top. A large share of OpenMU servers are
not English-speaking; if translating means hand-editing generated files, it will not
happen.
Assets / licensing
Item icons, monster renders and map images come from the MU client and belong to Webzen.
They cannot be committed to this repository. Proposal: an optional local step where
the operator points the generator at their own client files to extract images into the
site's static/ folder, with neutral placeholders when that step is not run.
Publishing
Kept intentionally outside the generator. Two deployment styles operators will want:
- Local build — a container runs the static site generator over the output folder
and a web server container serves the result.
- External build — the generated content is pushed to a Git repository from which a
hosting provider (Cloudflare Pages, Netlify, ...) builds and deploys. This moves the
build off the game host entirely, which matters because static site builds are
memory-hungry and should not compete with a latency-sensitive game server.
If a publisher is wanted inside OpenMU at all, an IDocumentationPublisher abstraction
with a filesystem implementation by default would fit the project's existing style, and
keep any extra dependencies out of the default dependency graph. A Git publisher would be
the most generic second implementation; a provider-specific one would bake a vendor into
the server codebase and is better left to the template repository.
If a Git publisher is added, two details matter: use a repo-scoped SSH deploy key from an
environment variable or secret mount (never the configuration database, never logged),
and push a single-commit orphan branch with force-push so the repository does not grow
without bound from regenerated files.
Proposed increments
- Generator project + one entity type end-to-end (maps, or monsters) + golden-file tests.
- Admin panel export action and CLI entry point, atomic write, manifest hash.
- Remaining entity types.
- Optional asset extraction step.
- Template repository for the site itself.
Questions for discussion
- Is a Node-based static site generator acceptable in the CI of a .NET repository, or
should the site template live in a separate repository from the start?
- Preferred location and naming for the generator project.
- Should the generator support both a live database and an exported configuration JSON as
input, or only one?
- Is the admin panel the right place for the trigger, or should this be CLI-only?
- Any concerns about the docs container(s) in
docker-compose? A separate compose profile
so they are opt-in seems safest.
Summary
Add an export function which generates player-facing documentation from the
GameConfigurationof a running server. The output is a set of Markdown/MDX and JSONfiles that a static site generator (Docusaurus, or any comparable tool) turns into a
website for the players of that specific server.
The important property: because the docs are generated from the actual configuration
of that deployment, they describe the server as it really is — including custom items,
adjusted drop rates, changed experience rates and enabled/disabled plugins — instead of
generic MU Online information copied from a fan wiki.
Motivation
Every hosted OpenMU server currently has the same problem: players ask where an item
drops, which monsters are on which map, what the requirements of a skill are, or what
the Chaos Machine success rates are. Operators answer this with hand-maintained wikis,
forum posts or Discord pins, which are laborious to write and silently go stale as soon
as the configuration is changed.
All of this information already exists in the
GameConfigurationaggregate. Rendering itis a projection of existing data, not a new source of truth. Doing it once, in the
project, means every server operator benefits and nobody has to maintain a wiki by hand.
Scope
In scope
GameConfigurationand writes Markdown/MDX + JSON.so it can be scripted.
Out of scope (deliberately)
schedule. That is operator-specific content and belongs in a separate template
repository that operators fork. This issue only covers producing the content that
such a site consumes.
Proposed content
Generated from configuration:
ItemDefinitionwith requirements, level table, possible options(
ItemOptionDefinition), set bonuses (ItemSetGroup), which classes can wear them.MonsterDefinitionwith attributes, on which maps they spawn, and theirdrops.
GameMapDefinitionwith spawn areas, exit gates, safezone, levelrequirements, connections to other maps.
ItemCraftingdefinitions with success rates,ingredients and results; jewel mixes.
Technical approach (open for discussion)
Where the code lives
A new project under
src/, e.g.MUnique.OpenMU.PlayerDocs.Generator, referenced by theadmin panel and by a small CLI host. Nothing in the runtime path should depend on it —
MUnique.OpenMU.Startupmust not gain a dependency.The configuration is loaded through
IPersistenceContextProvider, the same way theDataInitializationprojects do it. Supporting an exported configuration JSON as analternative input would make the generator usable in CI without a running server.
Derived values — the part that needs care
Some of the most useful information for players is not a stored field but a derived
value:
DropItemGroupchances, monster-leveldependent group selection, map-specific groups and the item level/option roll.
AttributeSystemwith its power-updefinitions.
These must be computed by reusing the existing game logic, not reimplemented in the
generator (and certainly not in JavaScript in the site). A parallel implementation will
silently drift from the server and publish wrong numbers, which is worse than publishing
nothing. Enabled
PlugInConfigurationentries should be taken into account as well,since they can change behaviour.
Output shape
Season 6 has on the order of a thousand item definitions and several hundred monsters.
Generating one page per item per level would produce a page count that makes static
site builds slow and memory-hungry.
Suggested instead:
components (filterable item browser, drop lookup). Docusaurus is React-based, so this
is straightforward and gives players filtering that static tables cannot.
Determinism
Output must be deterministic: stable ordering, stable slugs, stable file names, no
timestamps in frontmatter. Operators will want to commit the generated output and see a
meaningful diff when they change a drop rate. Non-deterministic output makes that
useless.
Atomic writes
The export should write to a temporary directory and move it into place when finished,
so a consumer never picks up a half-written tree. A
manifest.jsonwith a content hashlets a build step skip work when nothing changed.
Localisation
Emit stable translation keys rather than baking English strings into the generated
Markdown, so the site's i18n layer can sit on top. A large share of OpenMU servers are
not English-speaking; if translating means hand-editing generated files, it will not
happen.
Assets / licensing
Item icons, monster renders and map images come from the MU client and belong to Webzen.
They cannot be committed to this repository. Proposal: an optional local step where
the operator points the generator at their own client files to extract images into the
site's
static/folder, with neutral placeholders when that step is not run.Publishing
Kept intentionally outside the generator. Two deployment styles operators will want:
and a web server container serves the result.
hosting provider (Cloudflare Pages, Netlify, ...) builds and deploys. This moves the
build off the game host entirely, which matters because static site builds are
memory-hungry and should not compete with a latency-sensitive game server.
If a publisher is wanted inside OpenMU at all, an
IDocumentationPublisherabstractionwith a filesystem implementation by default would fit the project's existing style, and
keep any extra dependencies out of the default dependency graph. A Git publisher would be
the most generic second implementation; a provider-specific one would bake a vendor into
the server codebase and is better left to the template repository.
If a Git publisher is added, two details matter: use a repo-scoped SSH deploy key from an
environment variable or secret mount (never the configuration database, never logged),
and push a single-commit orphan branch with force-push so the repository does not grow
without bound from regenerated files.
Proposed increments
Questions for discussion
should the site template live in a separate repository from the start?
input, or only one?
docker-compose? A separate compose profileso they are opt-in seems safest.