Skip to content

feat(warps): send the warp list to the open source client - #1504

Merged
sven-n merged 9 commits into
MUnique:masterfrom
pllanosclaria:feat/warp-list-for-open-source-client
Nov 14, 2026
Merged

sven-n merged 9 commits into
MUnique:masterfrom
pllanosclaria:feat/warp-list-for-open-source-client

Conversation

@pllanosclaria

@pllanosclaria pllanosclaria commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1503

The open source client takes its warp list from its data files, which follow Webzen's Season 6 (see #1503, sven-n/MuMain#1057), so it can't follow the warp list which the server is configured with. With this change the server sends its warp list to the open source client when a character enters the game; original clients don't get it.

Following the review, WarpInfo.IsWarpable decides which warps players can use. By default that's the warp window of the original client: Crywolf and Loren Market weren't in it, since Crywolf is reached by walking and Loren Market through an NPC, so they're game master only now. An admin who wants them in the warp window turns them on in the admin panel. Before this change, any player could already use them by their index, e.g. with /move Crywolf.

Changes

  • Packet WarpListExtended (C2 F5 09, server to client), in the XML with the generated code, docs and tests: a count, then per warp the index, map number, level requirement (as configured), costs and the name (32 bytes, UTF-8).
  • View IShowWarpListPlugIn, implemented only by ShowWarpListExtendedPlugIn with [MinimumClient(106, 3, ClientLanguage.Invariant)], like ShowShopCurrenciesExtendedPlugIn. The name is WarpInfo.Name in the player's culture; a name which doesn't fit into the 32 bytes is shortened to whole characters instead of failing the message.
  • Plugin ShowWarpListAfterEnterWorldPlugIn (IPlayerStateChangedPlugIn, CharacterSelection → EnteredWorld, so not on map changes): sends the warps ordered by index, without warps whose gate has no map, and of warps with the same index only the first one, because that's the one WarpHandlerPlugIn uses.
  • Flag WarpInfo.IsWarpable (default true), as suggested in the review. It only restricts players, and only when it's off: then the warp isn't sent to the client, and WarpAction refuses it for characters below game master status, with a message (WarpOnlyForGameMasters, en/de/pt). Game masters can still use it. Bots warp through WarpAction like players, so BotNavigator.GetLegalWarps leaves these warps out.
  • Defaults like the original warp window: a new season 6 configuration has it off for Crywolf (26, reached by walking), Loren Market (44, reached through Julia) and LaCleon (48, which the client offers as 34). The optional update RestrictWarpsOutsideOfOriginalWarpWindowPlugIn does the same for existing configurations, for warps which still lead to their original map; it's optional because it changes what the players of a running server can do (today any player can use these warps, e.g. /move Crywolf).
  • Migration AddWarpInfoIsWarpable (existing warps stay warpable), with the compiled model and the generated loader code updated; caption and description in English and German.
  • Plugin names and descriptions in English and German.
  • The admin panel docs of the warp list say that the open source client shows it.
  • PlayerTestHelper.CreateGameConfiguration sets up an empty warp list, like its other collections. Without it, the existing tests which enter the world with that mock failed on the new plugin.

The client side is sven-n/MuMain#1110. It reads the message by hand, like the other F5 messages, so it doesn't need a new package version.

Testing

  • New WarpListTests: the fields of the message (including the translated name), the shortened names, that only client 106.3 gets the view plugin, the selection and order of the warps, that warps which aren't warpable are left out (also when such a warp is the first of its index), that a player is refused such a warp (with the message, and without paying) while a game master isn't, and that the list is sent after entering the game but not after a map change. New WarpableWarpsTest: a new season 6 database has exactly 26, 44 and 48 not warpable; the update does the same on a database which has them warpable, leaves a warp alone whose map was changed, and a second run changes nothing.
  • dotnet build src/MUnique.OpenMU.sln, then dotnet test src/MUnique.OpenMU.sln --no-build: everything passed (MUnique.OpenMU.Tests 2899 passed, 2 skipped, including CompiledModelTests and GameConfigurationLoaderGeneratorTest; Persistence.Initialization.Tests 853 passed, 12 skipped; the other projects passed. MapComponentTests.ControllerCreatedAfterDisposalIsDisposedAsync in the Web tests failed in two runs while the machine was busy with a docker build, and passed every time the project ran without load; it's about the live map, not this change).
  • On a local server (docker image of this branch, Season 6 data) with the MuMain branch:
    • the warp window lists Crywolf and Loren Market after the warps of the client's data, and the client warps there through its warp list (MuMain's control socket warp, which takes the entry by name) and with /warp LorenMarket in the chat box;
    • after going back to the character list and entering again, the list is sent again;
    • the migration added the column on the existing database with all warps warpable, and the optional update is offered and not applied;
    • with Crywolf (26) and LaCleon (48) not warpable: the warp window has no Crywolf and LaCleon once; /move Crywolf of a normal character is refused with the message and the character stays in Lorencia; the same /move Crywolf of a game master character warps to Crywolf;
    • with ShowWarpListExtendedPlugIn deactivated, the client falls back to its own list (no Crywolf), as with a server which doesn't know the message.
  • Not tested with the original 1.04d client. It doesn't get the view plugin (covered by the test above), so nothing new is sent to it.

Notes

  • The Season 6 data has two warps to LaCleon: 34 "Raklion" and 48 "LaCleon", both to gate 287. The original client only knew 34 (it calls it LaCleon), so 48 is not warpable by default now, and the open source client shows LaCleon once.
  • Building the packets project regenerates three docs which are already out of date on master (C1-11-ObjectHit*_by-server.md, C1-48-ShowEffect_by-server.md); I left them out of this PR.

@codacy-production

codacy-production Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 34 complexity · 14 duplication

Metric Results
Complexity 34
Duplication 14

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@pllanosclaria
pllanosclaria marked this pull request as draft November 13, 2026 01:00
@ze-dom

ze-dom commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

I think it would be maybe better to have a property in map like IsWarpable. This way the warp could exist and not be sent to the client, and could be used only by a GM. Just because OpenMU has the warp doesn't mean the client should have it as well. Then, the admins could enable/disable any warps they want.

@pllanosclaria

Copy link
Copy Markdown
Contributor Author

Thanks, good point. I'd put the flag on the warp entry instead of the map, though: a map can have several warps (Devias 1 to 4 all go to Devias, and the Season 6 data has two warps to LaCleon, 34 and 48, to the same gate), and a whole map can already be turned off with IsActive. So I'll add WarpInfo.IsShownInWarpList (default true) to this PR: warps with it turned off aren't sent to the client.

I'd keep it to the list, though. A hidden warp can still be used by its index, so "only for game masters" would be a separate feature (a check in WarpAction), better in its own PR. This one is about showing the warps the client can actually use, like Crywolf.

If this gets merged, I'm planning a follow-up with a warp list page in the admin panel, instead of the generic grid:

  1. Show or hide each warp in the client's list (the flag of this PR).
  2. Add a warp to an existing map, picking one of its gates or creating a new one.
  3. Edit the name, level requirement and costs.
  4. Change the order of the list (move entries up and down).
  5. Sort buttons: by level, alphabetically, and back to the original order of the client.
  6. Keep that order in the configuration (a new display order field, set to the original Season 6 order for new and existing configurations), so the open source client shows the list in the server's order.
  7. Point out warps which lead to the same gate, like LaCleon 34 and 48.

I'd open an issue for it first, so the layout of the page can be discussed.

@pllanosclaria
pllanosclaria force-pushed the feat/warp-list-for-open-source-client branch from 6ccf573 to a6caa19 Compare November 13, 2026 10:51
@pllanosclaria
pllanosclaria marked this pull request as ready for review November 13, 2026 10:53
@ze-dom

ze-dom commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

This one is about showing the warps the client can actually use, like Crywolf.

But Crywolf is not a map the client can warp to (only walk)! The point is to keep that by default. If admins want to enable it, then they can do it in Admin Panel. I don't see the point of not showing a warp but still allowing it by index for a regular player.

Anyway, this is just my view, maybe sven thinks differently.

@pllanosclaria

Copy link
Copy Markdown
Contributor Author

Before this PR, a regular player could already warp to Crywolf or Loren Market with /move Crywolf and /move LorenMarket. The server's /move chat command is available to normal characters, looks the name up in the server's warp list and warps through WarpAction. I checked both with a normal character in MuMain, which sends /move to the server as chat text, on a server whose /move and WarpAction were the same as on master: from Lorencia to Crywolf and to Loren Market. I didn't try it with the original 1.04d client.

So the intention of this PR was to let the warp window show, if wanted, the same warps which /move already allowed; an admin who didn't want a warp in the list could turn the flag off.

Restricting warps for regular players, both in the list and for /move, is a good solution and I agree with it, but it's a separate feature. Following "one concern per pull request", I suggested a separate PR for it. Since you insisted on having it here, I've included it in this one:

  • WarpInfo.IsWarpable (default true), with your name. It only restricts players, and only when it's off: then the warp isn't sent to the open source client, and WarpAction refuses it for characters below game master status, with a message. Game masters can still use it. Bots warp through WarpAction like players, so they skip these warps too.
  • A new season 6 configuration has it off for the warps the original warp window doesn't offer: Crywolf (26), Loren Market (44, reached through Julia) and LaCleon (48, which the client already offers as 34).
  • For existing configurations there's an optional update (Restrict warps outside of the original warp window) which does the same. It's optional because, as described above, applying it takes something away from the players of a running server.

@sven-n sven-n left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR conflicts with current master, so I can't merge it. Please rebase it onto master. These files conflict:

  • src/GameLogic/Properties/PlugInResources.resx

Most of them are resource files (.resx / .Designer.cs) which other merged PRs also extended. When you resolve them, keep the entries of both sides, and regenerate the designer file instead of merging it by hand. I'll review it in full once it's rebased.


Generated by Claude Code

…e client

The open source client takes its warp list from its data files, which follow
Webzen's Season 6. Warps which OpenMU has and Webzen doesn't, like Crywolf and
Loren Market, can't be selected there, and the client can't add them to its
files because it's used with Webzen's servers, too.

WarpListExtended (C2 F5 09) carries the warp list of the server: per warp the
index, map, level requirement, costs and the name in the player's language.
When a character enters the game, the server sends its warp list to the open
source client (WarpListExtended), so that its warp window offers the warps of
the server instead of the ones of its data files. Original clients don't get
it: the view plugin exists only for the open source client.

The warps are ordered by index; warps without a map are left out, and of warps
with the same index only the first one is sent, because it's the one which a
warp request uses. Names which don't fit into the 32 bytes of the field are
shortened to whole characters instead of failing the message.

The mocked game configuration of the tests gets an empty warp list, like its
other collections.
WarpInfo.IsShownInWarpList (default true) decides whether the warp is sent
to the open source client. It only affects the list: a warp which isn't shown
can still be used by its index. This allows to hide e.g. a second warp to the
same place, like LaCleon (48) next to Raklion (34) in the season 6 data.

The migration adds the column with true for the existing warps; the compiled
model and the generated loader code include the new property.
…iginal warp window

As suggested in the review, the flag is WarpInfo.IsWarpable, and it restricts
the warp instead of only leaving it out of the list. Hiding a warp alone didn't
keep players away from it: they could still use it by its index, e.g. with the
move chat command.

When it's off, the warp isn't sent to the open source client, and WarpAction
refuses it for characters below game master status with a message. Bots warp
through WarpAction like players, so they don't pick these warps either.

A new season 6 configuration has it off for the warps which the original client
doesn't offer in its warp window: Crywolf (26), reached by walking, Loren Market
(44), reached through an NPC, and LaCleon (48), which the client offers as 34.
The optional update RestrictWarpsOutsideOfOriginalWarpWindowPlugIn does the same
for existing configurations; it's optional because it changes what the players
of a running server can do.

The migration replaces the one of IsShownInWarpList (not merged yet).
…e logic

Regenerated from PlugInResources.resx after resolving the conflict with master,
instead of merging the designer by hand. The properties are in the order of the
generator, and the ones of CastleSiegeGuardsmanTalkPlugIn, which were in the
resx but not in the designer, are added.
@pllanosclaria
pllanosclaria force-pushed the feat/warp-list-for-open-source-client branch from 500668c to 224d294 Compare November 14, 2026 14:10
@pllanosclaria

Copy link
Copy Markdown
Contributor Author

Rebased onto current master. The conflict in src/GameLogic/Properties/PlugInResources.resx was both sides appending entries (the bot chat ones from #1438 and the warp list ones); I kept both.

I regenerated PlugInResources.Designer.cs from the resolved resx instead of merging it, in its own commit (224d294). Because of that it moves a lot of lines: the designer on master had entries added by hand out of the generator's order, and it was missing CastleSiegeGuardsmanTalkPlugIn_Name / _Description, which are in the resx. The regenerated file has all 850 entries of the resx, in the generator's order. If you'd rather keep the reordering out of this PR, I can drop that commit and keep the designer as git merged it (both sides' entries, nothing else).

No migration was added on master in between, so AddWarpInfoIsWarpable is still the last one. Build and dotnet test src/MUnique.OpenMU.sln pass, including CompiledModelTests and GameConfigurationLoaderGeneratorTest.

@pllanosclaria
pllanosclaria requested a review from sven-n November 14, 2026 16:49

@sven-n sven-n left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the rebase. The open source client's warp list (WarpListExtended) is sent after entering the world. IsWarpable is enforced in WarpAction (game masters excepted) and respected by the bots. The migration adds the column with defaultValue: true, so existing warps stay usable, and the update which restricts Crywolf, Loren Market and the second LaCleon warp is optional. That's the right call, since it takes something away from running servers.

The fully regenerated GameLogic/Properties/PlugInResources.Designer.cs makes the diff big, but I checked it: it's the same set of strings (plus two which were missing on master), only in the generator's standard form, which is what the rules ask for.

I built it on current master and ran the tests, including Persistence.Initialization.Tests (858 passed): everything passes except the known flaky ControllerCreatedAfterDisposalIsDisposedAsync, which is unrelated.

Nit for later: RestrictWarpsOutsideOfOriginalWarpWindowPlugIn returns English constants for Name/Description, although the Display attribute already points to localized resources.


Generated by Claude Code

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.

Send the server's warp list to the open source client

3 participants