Skip to content

feat: server list as JSON with a Server List editor window - #845

Merged
Mosch0512 merged 26 commits into
sven-n:mainfrom
Mosch0512:feat/server-list-editor
Oct 22, 2026
Merged

Mosch0512 merged 26 commits into
sven-n:mainfrom
Mosch0512:feat/server-list-editor

Conversation

@Mosch0512

Copy link
Copy Markdown
Collaborator

What this does

The server groups of the login screen (Valhalla, Helheim, Midgard and their channel types) now come from Data/Local/ServerList.json instead of the encrypted ServerList.bmd, and MU Editor gets a Server List window to change them.

ServerList.json

{
  "formatVersion": 1,
  "groups": [
    {
      "id": 0,
      "name": "Valhalla",
      "channels": {"1": "gold", "2": "gold", "3": "gold", "4": "gold", "5": "goldPvp", "6": "nonPvp", "7": "nonPvp", "8": "nonPvp"}
    }
  ]
}
  • id is the server ID / 20 (servers 0-19 are group 0), the list order is the button order, channels gives normal (default), nonPvp, goldPvp or gold per channel number. description and testServer are optional; of the test server groups, the login screen shows only the first, at its place in the list.
  • A name may have 32 and a description 254 UTF-16 units (an emoji counts as two, as the client's wide strings hold it on Windows); longer text is cut with a warning.
  • Errors stop the start with a message, as broken item data does; all problems go to the log.
  • The shipped file was converted from ServerList.bmd; a one-time test (added with the conversion, removed with the bmd) compared every group, its order and all 20 channel types with what the old loader read.

Server List window (Windows → Server List)

  • Groups in their order on the left (Add, Remove, Move up, Move down); the selected group's ID (with the server IDs it covers), name, description, test server mark and a type for each of the 20 channels on the right, with the name the login screen gives each channel.
  • The login screen shows each change right away, and keeps the group that is open there when the list is reordered.
  • Groups the connect server sent that the list does not have are listed with an Add button; the channel table shows which channels the connect server sent and their load.
  • Save writes the file and refuses errors (no name, an ID twice). After the file was read with errors, Save stays off until it is fixed and Revert reads it again, so it cannot remove the groups the read left out.
  • Undo and Redo in the editor bar now act on the tool used last: after a click into the Server List window they undo server list changes, after a click into an item tool item edits (MuEditor::UndoTargets); while the Server List window is closed, item edits. Their tooltips name the step ("Remove Helheim", "Valhalla: channel 3"). In the window, Ctrl+Z and Ctrl+Y (or Ctrl+Shift+Z) work while the keyboard is the editor's.
  • Strings in English and German.

Fixes on the way

  • The old loader read each group's description but never kept it, so the login screen's description panel was always empty. The JSON description is shown. (The shipped groups have none, so nothing changes on screen.)
  • Channel types covered only the first 15 of the 20 channels a group can have.
  • A server of a group the list does not have leaked the group object it built.

Review fixes

This went through two reviews on the fork PR Mosch0512#128 (the second: ready to merge); every finding is fixed, one commit each:

Finding Commit
Required: undo keys fired while the game had the keyboard 959096b
Required: Save after a read with errors wrote a shorter list be743f2, c4286d7 (docs)
Hidden server select window kept a pointer to a deleted group 13f2a43
Reordering changed the group open on the login screen f86a535
Name limit in characters could overflow wide buffers (emoji) ff0d39b, d60a5cf (format)
"Test server is shown first" in docs, comment and note 0a3a37f
## in a group name read as an ImGui ID e2be005
Login screen suffixes copied in the editor 7f9d274 (tests first), 5dbfd65
CopyText repeated wcsncpy_s e8638af
Channel maps built every frame 50d4b48
No test for CServerListManager 7f9d274
Functions over the ~40-line aim aaaeb87
Two ServerGroup.h files d8f4da0
Follow-up: a closed Server List window kept the bar's Undo and Redo f8b374e
Follow-up: the bar's tooltip did not name the Server List step 42de110
Follow-up: dev-editor.md said the bar's Undo and Redo are the item tools' f9f5b94
Follow-up: SyncRmlModel's comment above the new editor functions f96eca0
Follow-up: an unwrapped docs line 487c7cd

The shared Undo/Redo in the editor bar (f8fe9cd) was asked for while testing.

Not in this PR

  • No download from OpenMU: OpenMU only knows a game server's ID, description and PvP flag, so the list stays client-side.

Testing

  • server_list_data_tests (38 test cases): reader/writer (errors, warnings, cuts in UTF-16 units, round trip, save refusing errors without touching the file), the shipped file reads cleanly and is written exactly as the editor writes it, the editor's edits, undo, step names and the Save guard, and CServerListManager (list order, all 20 channel types, channel names, unknown groups, description, test server, rebuild). The channel name tests went in before the suffix refactor and pass after it.
  • The one-time comparison of ServerList.json with ServerList.bmd passed in the conversion commit (removed with the bmd in the next one).
  • Windows editor build; test_item_database, test_item_database_files and light_mood_data_tests still pass (the item tools' undo now goes through the shared bar).
  • clang-format 21.1.8 and cppcheck with the CI flags on the changed files.
  • In game (Windows, editor build, local OpenMU), before the review fixes: the login screen shows the groups from the JSON; renaming a group, changing a channel type, adding a description and reordering in the Server List window showed on the login screen right away. The review fixes are not checked in game yet.
  • Not built on Linux or macOS with the editor on: the fork CI skips those jobs, and the fork CI of the last push was still running when this was opened.

Commits

  1. fix: a server of a group the list does not have no longer leaks the group
  2. feat: ServerList.json (+ converted file, one-time comparison test, LF in .gitattributes)
  3. chore: remove ServerList.bmd and the comparison
  4. feat(editor): the Server List window
  5. docs: docs/server-list.md
  6. 21 commits for the review findings and the shared Undo/Redo (table above)

…r leaks it

The connect server can send a server whose group (server ID / 20) is not
in the server list. Such a server is not shown, but InsertServerGroup had
already built a CServerGroup for it, which nobody deleted. The group is a
unique_ptr now until the map owns it.
…ist.json

The server groups of the login screen (name, order, test server, channel
types) are read from Data/Local/ServerList.json instead of the encrypted
ServerList.bmd:

  { "formatVersion": 1, "groups": [
    { "id": 0, "name": "Valhalla", "channels": {"1": "gold", "5": "goldPvp", "6": "nonPvp"} } ] }

"id" is the server ID / 20, the list order is the button order, and a
channel not listed is normal. Errors stop the start with a message, as
broken item data does; every problem goes to the log. The file is
written with LF like the item and effect data, since the editor writes it.

The shipped file was converted from ServerList.bmd. A one-time test reads
the bmd the way the old loader did and compares each group with what the
JSON gives the login screen: name, order, position and all 20 channel
types. The bmd and that test go in the next commit.

Two things change on the way:
- The old loader read each group's description but never kept it, so the
  login screen's description panel was always empty. The description is
  shown now; the shipped groups have none.
- Channel types covered only the first 15 of the 20 channels of a group.
The client reads ServerList.json since the last commit, whose test showed
the JSON holds what the bmd held. Neither the bmd nor that test is needed
any more.
Windows > Server List shows the groups of Data/Local/ServerList.json in
their order (Add, Remove, Move up, Move down) and the selected group: its
ID with the server IDs it covers, name, description, the test server mark
and the type of each of its 20 channels, with the name the login screen
gives the channel.

- The login screen shows each change right away: the server list manager
  keeps the last list the connect server sent (editor builds only) and
  builds the groups from it again.
- Groups the connect server sent that the list does not have are listed
  with an Add button; the channel table shows which channels the connect
  server sent, with their load.
- Save writes the file and refuses errors (a group without a name, an ID
  twice), Revert reads it again, Undo and Redo (Ctrl+Z, Ctrl+Y) go through
  the changes of the session; a text field's whole edit is one step.
- Texts in English and German.
How the login screen turns the connect server's server IDs into groups
and channels, the fields of ServerList.json, the Server List window, and
what changed from the original ServerList.bmd.
…rd is the editor's

ImGui keeps the Server List window focused after the keyboard has gone
back to the game. Ctrl+Z typed into the login screen's ID or password
field then also undid the last server list change and built the login
screen's groups again. The keys now need the editor's keyboard
(IsKeyboardWithEditor), as the item tools and the map editor check, and
Ctrl+Shift+Z redoes too, as there.

Review of #128 (required).
The reader leaves out every group with an error, and a file it rejects
as a whole (a JSON syntax error, formatVersion 2) gives no groups at all.
Save then wrote that shorter list, which reads back without errors, so a
group mistyped by hand while the game ran, or the whole list, was gone
from ServerList.json without a warning.

After a read with errors the groups are not complete (ServerListEdits::
IsComplete): Save is off and the window says why, until the file is
fixed and Revert reads it again.

Review of #128 (required).
…ebuilt

The Server List window builds the login screen's groups again after each
change, which deletes the old CServerGroup objects. The server select
window was refreshed only while it was visible; after a server was picked
it is hidden and kept m_pSelectServerGroup on a deleted group, and the new
groups had no button position. Nothing used the pointer before the next
UpdateDisplay, but a path that shows the window without one (MsgWin's
RECEIVE_JOIN_SERVER_WAITING) would have read freed memory on a click.
UpdateDisplay now runs after every rebuild; it does nothing visible while
the window is hidden.

Review of #128.
…st window reorders

The server select window remembers the open group by its button
position, and the rebuild after an edit numbers the buttons again in the
new list order. With Valhalla open, moving Midgard above it in the Server
List window opened Midgard on the login screen, with its channels;
Remove and the Test server box did the same.

The window now finds the open group again by its ID after a rebuild
(CServerSelWin::GetOpenGroupId and ShowRebuiltGroups, editor builds only).
A group that is gone leaves none open.

Review of #128.
The limits counted characters. A character outside the Basic
Multilingual Plane (most emoji) takes two wchar_t on Windows, so a
32-character name could be 64 wchar_t long, and the screenshot message
(SceneManager.cpp) formats the group name and the character name into
wchar_t[64] without a size: 24 emoji and a 10-letter name wrote past it.
The description's 254 characters could also be more than the 254 wchar_t
the group keeps, and that cut could split a surrogate pair.

CutToUtf16Length counts an emoji as two and never cuts inside a
character; the reader and the Server List window use it for both limits.

Review of #128.
The docs, a comment and the editor's note said a test server group is
shown first. CServerSelWin::UpdateDisplay adds the groups in list order
and server_select.rml keeps that order: testServer only hides every test
server group after the first, it does not move one. The four texts say so
now.

Review of #128.
The group list used the name as the Selectable's label, so ImGui read a
"##" in it as the start of the ID: a group named "PvP##EU" showed as
"PvP", without its ID and test server mark. The row's label is now only
an ID (the rows are told apart by PushID already) and the name is drawn
as plain text over it.

Review of #128.
…ilds them

The tests covered the JSON reader and writer and the editor's edits, but
not the game side, where the list becomes the login screen's groups:
- the list order becomes m_iSequence,
- a server of a group the list does not have is not shown,
- all 20 channel types reach m_abyNonPvpServer, m_bPvPServer and the
  channel names ("Valhalla-1(Gold) ..."),
- description and test server (SBP_CENTER) reach the group,
- new groups replace the old ones, and a rebuild (editor builds) names
  the servers last sent with the new groups.

Review of #128.
…ogin screen

The Server List window had a copy of the four suffixes InsertServer
writes after "<group name>-<channel>" ((Non-PVP), (Gold PVP), (Gold)),
so a change on one side would have left the window's "On the login
screen" column showing something else. GetChannelSuffix, next to the
channel types, gives them to both. InsertServer formats the name with
it in one call instead of a switch over four formats; the channel names
stay the same, as the manager tests of the last commit check.

Review of #128.
CopyText repeated what wcsncpy_s with _TRUNCATE does on every platform
(the CRT on Windows, Core/Platform/SecureCrt.h elsewhere), as
TextLineWrap.cpp already uses it.

Review of #128.
…ls only when they change

FindSentChannels built nested maps from every server the connect server
sent on each frame the window was drawn, while that list only changes
when a new one arrives. CServerListManager counts the changes of the
received servers (editor builds only), and the window builds its maps
again only when the count moved.

Review of #128.
…t window

The Server List window had Undo and Redo buttons of its own beside the
editor bar's, which only undid item edits. The bar's buttons now act on
the tool worked in last: a tool window that has the focus makes its
history the bar's (MuEditor::UndoTargets), the item tools until another
tool is used. The item edit history and the Server List window are the
two UndoTargets; the window's own buttons are gone, its Ctrl+Z and Ctrl+Y
stay.
The Server List window turns Save off while the groups come from a read with errors, so it cannot remove the groups the read left out; the doc says so now.
…parts

Render (65 lines) and RenderChannels (57) were over the ~40-line aim of
the coding rules. Render now begins the window with the editor's bar
(BeginWindow), draws the two panes (RenderPanes) and handles what
changed (AfterEdits); one channel row (number, type combo, login screen
name, load) is a function of its own. No change in what the window does.

Review of #128.
Data/GameData/ServerListData/ServerGroup.h had the name of
Network/Server/ServerGroup.h (CServerGroup), and ServerListManager.h
includes both. The data header is ServerListGroup.h now, so the two are
not mixed up when reading or including; the type stays
Data::ServerList::ServerGroup.

Review of #128.
The rename of maxCharacters to maxUnits made the parameter list fit differently; clang-format 21.1.8 (the Quality Gates version) wraps it after std::string& text. Formatting only.
… tools

The bar's Undo and Redo stayed with the tool whose window had the focus
last, also after that window was closed. With the Server List window
closed, the bar's Undo then took back a server list change, from a
window no longer shown, instead of the last item edit, and its tooltip
offered Ctrl+Z, which does nothing there.

UndoTarget::IsOpen tells whether the tool's window is open; while the
last tool is closed the bar falls back to the item tools, whose edits
stay undoable with their windows closed, as before.

Follow-up review of #128.
For the Server List window the editor bar's tooltip only said "Server
List (Ctrl+Z)", while item edits name their step; after a few changes it
did not tell whether Undo takes back a rename, a removed group or a
channel type. Each step of ServerListEdits now has a label: Add, Remove
and Move name the group ("Remove Helheim"), a change of fields names the
group as it was and the field ("Valhalla: name", "Valhalla: channel 3").
A step keeps its label when it is undone and redone. English and German.

Follow-up review of #128.
dev-editor.md still said the editor bar has the Undo and Redo of the item
tools, and item-data.md points there for them. Since the shared Undo and
Redo they act on the tool used last, the item tools or the Server List
window (item edits while that window is closed). The Windows menu list
names the Server List too.

Follow-up review of #128.
The editor-only GetOpenGroupId and ShowRebuiltGroups went in between
SyncRmlModel and its comment, and the comment's claim that the window's
state only changes from its own click handlers is no longer true. The
editor block now comes before the comment, which names ShowRebuiltGroups.

Follow-up review of #128.
One line of the paragraph was 142 characters; the file wraps at about 78. Wording unchanged.

Follow-up review of #128.
@Mosch0512
Mosch0512 merged commit 7382106 into sven-n:main Oct 22, 2026
7 checks passed
@Mosch0512
Mosch0512 deleted the feat/server-list-editor branch October 25, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant