You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
Chat command arguments are currently described only by their CLR type, their
short name, a required flag and — for small sets — [ValidValues]. That is
enough to render a text box, but not enough to render anything helpful.
Every one of those numbers is opaque. group=1 number=2 is a Blade, 417 is
some monster, 235 is some model — the admin has to look them up externally.
But the client already knows what these numbers mean, and so does the game
configuration. With a bit of metadata saying "this parameter is a monster
number", a UI can offer a searchable dropdown of monster names instead of an
empty number field.
[ValidValues] can't express this: it's meant for small, fixed, server-defined
sets (str|agi|vit|ene|cmd, PK levels 1|2|3, ancient discriminator 0|1|2),
and it would be absurd to enumerate thousands of item names into it and send
them over the wire.
Describe the solution you'd like
Two additions to the argument metadata, both purely descriptive — server-side
validation and parsing are unchanged.
1. Value ranges — reuse [Range]
No new attribute needed: System.ComponentModel.DataAnnotations.RangeAttribute
is already used in this codebase (GameLogic/Bots/BotConfiguration.cs), and it
resolves the // todo: ranges in ParameterAttribute left in CommandExtensions.GetParameters:
Min/max should be carried as values on the DTO, not read straight from the
attribute by every consumer, so a builder can override them from the game
configuration where the real limit isn't a compile-time constant (maximum item
level, map dimensions, …).
2. Reference kinds — a new attribute
publicenumChatCommandValueReference{None,CharacterName,AccountName,GuildName,Map,MapCoordinateX,MapCoordinateY,ItemGroup,ItemNumber,MonsterNumber,ObjectId,// an object currently in scopeSkillNumber,LanguageIsoCode,}
A UI then renders one item picker that fills both fields, instead of two
disconnected number boxes.
Why this works — the client really does know these numbers
Verified in the MuMain sources, so this isn't speculative:
Monsters: getMonsterName(int type) — Engine/Object/ZzzInfomation.cpp.
Covers both MonsterNumber and the /skin model number.
Items: GetItemName(int iType, int iLevel, wchar_t*) and GetItemDisplayName — Engine/Object/ZzzInventory.h. Crucially the client's
item type encoding is ITEM_GROUP_x * MAX_ITEM_INDEX + index
(Core/Globals/_define.h), i.e. exactly group and number — so group=1 number=2 maps to a client item name with no translation table.
Maps: gMapManager.GetMapName(...).
In-scope objects: the client holds CharactersClient, so an ObjectId
parameter can offer the objects around the player — or even a "pick target on
screen" button.
Character names: the client can't know every character on the server, but
it can suggest party members, guild members and players in scope.
Two design rules follow from that last point:
A reference kind is a hint, never a constraint. The UI must always allow
raw entry. The client's data files can be out of sync with the server's
configuration — custom items or monsters added server-side won't be in the
client's list, and the command must still be usable.
Nothing changes on the validation path. The server keeps parsing and
validating exactly as before; this metadata only makes input easier.
How it interacts with the other issues
Provide the available chat commands in a machine-readable form to the client #847 (machine-readable command list for the client): two more fields per
parameter — ReferenceKind (byte) and the companion parameter name — plus
min/max. Purely additive; if the parameter strings are length-prefixed and
may be empty as proposed there, this can land before or after the packet
without a breaking change.
This issue is independent of both and is useful on its own: even /help
output could read /createmonster number={MonsterNumber} instead of {Number:Int16}.
Describe alternatives you've considered
Send the full value lists from the server (e.g. as ValidValues). Fine
for maps (~60) or languages, hopeless for items and monsters, and it would
ship English server-side names to a client that already has them translated.
The sensible split is: small server-defined sets → ValidValues inline;
large sets the client already knows → reference kind.
Hardcode a parameter→picker mapping in the client, keyed on command name.
Brittle, and it breaks for exactly the commands where discovery matters most:
custom plugins the client has never heard of. That defeats the purpose of a
dynamic command list.
Do nothing and rely on [Range] alone. Ranges help for coordinates and
levels, but a range of 0–511 on an item number is still an empty box.
Is your feature request related to a problem? Please describe.
Chat command arguments are currently described only by their CLR type, their
short name, a required flag and — for small sets —
[ValidValues]. That isenough to render a text box, but not enough to render anything helpful.
Look at what a GM actually has to type today:
Every one of those numbers is opaque.
group=1 number=2is a Blade,417issome monster,
235is some model — the admin has to look them up externally.But the client already knows what these numbers mean, and so does the game
configuration. With a bit of metadata saying "this parameter is a monster
number", a UI can offer a searchable dropdown of monster names instead of an
empty number field.
[ValidValues]can't express this: it's meant for small, fixed, server-definedsets (
str|agi|vit|ene|cmd, PK levels1|2|3, ancient discriminator0|1|2),and it would be absurd to enumerate thousands of item names into it and send
them over the wire.
Describe the solution you'd like
Two additions to the argument metadata, both purely descriptive — server-side
validation and parsing are unchanged.
1. Value ranges — reuse
[Range]No new attribute needed:
System.ComponentModel.DataAnnotations.RangeAttributeis already used in this codebase (
GameLogic/Bots/BotConfiguration.cs), and itresolves the
// todo: ranges in ParameterAttributeleft inCommandExtensions.GetParameters:Min/max should be carried as values on the DTO, not read straight from the
attribute by every consumer, so a builder can override them from the game
configuration where the real limit isn't a compile-time constant (maximum item
level, map dimensions, …).
2. Reference kinds — a new attribute
Mapped onto what exists today in
PlugIns/ChatCommands/Arguments:ItemChatCommandArgsGroup,NumberItemGroup+ItemNumber(composite, see below)CreateMonsterChatCommandArgsMonsterNumberMonsterNumberSkinChatCommandArgsSkinNumberMonsterNumberMoveMonsterCommandArgs,IdCommandArgsIdObjectIdMoveChatCommandArgs,GuildMoveChatCommandArgsMapIdOrNameMapCoordinatesCommandArgsand derivedX,YMapCoordinateX/MapCoordinateYBanCharChatCommandArgs,CharInfoChatCommandArgs,ChatBanCharChatCommandArgs,DisconnectChatCommandArgs,PkChatCommandArgs,TraceChatCommandArgs, …CharacterNameCharacterName(12+ occurrences)BanAccChatCommandArgs,UnBanAccChatCommandArgsAccountNameAccountNameGuildWarChatCommandArgs,GuildMoveChatCommandArgs,GuildDisconnectChatCommandArgsGuildNameGuildNameChangeLanguageChatCommandArgsIsoLanguageCodeLanguageIsoCodeComposite references.
/itemidentifies one item with two parameters, sothe attribute should be able to name its companion:
A UI then renders one item picker that fills both fields, instead of two
disconnected number boxes.
Why this works — the client really does know these numbers
Verified in the MuMain sources, so this isn't speculative:
getMonsterName(int type)—Engine/Object/ZzzInfomation.cpp.Covers both
MonsterNumberand the/skinmodel number.GetItemName(int iType, int iLevel, wchar_t*)andGetItemDisplayName—Engine/Object/ZzzInventory.h. Crucially the client'sitem type encoding is
ITEM_GROUP_x * MAX_ITEM_INDEX + index(
Core/Globals/_define.h), i.e. exactlygroupandnumber— sogroup=1 number=2maps to a client item name with no translation table.gMapManager.GetMapName(...).CharactersClient, so anObjectIdparameter can offer the objects around the player — or even a "pick target on
screen" button.
it can suggest party members, guild members and players in scope.
Two design rules follow from that last point:
raw entry. The client's data files can be out of sync with the server's
configuration — custom items or monsters added server-side won't be in the
client's list, and the command must still be usable.
validating exactly as before; this metadata only makes input easier.
How it interacts with the other issues
parameter —
ReferenceKind(byte) and the companion parameter name — plusmin/max. Purely additive; if the parameter strings are length-prefixed and
may be empty as proposed there, this can land before or after the packet
without a breaking change.
better than the game client, because the admin panel has the authoritative
GameConfiguration— the dropdowns can be built fromGameConfiguration.Items,.Monstersand.Mapsrather than from clientdata files.
/helpoutput could read
/createmonster number={MonsterNumber}instead of{Number:Int16}.Describe alternatives you've considered
ValidValues). Finefor maps (~60) or languages, hopeless for items and monsters, and it would
ship English server-side names to a client that already has them translated.
The sensible split is: small server-defined sets →
ValidValuesinline;large sets the client already knows → reference kind.
Brittle, and it breaks for exactly the commands where discovery matters most:
custom plugins the client has never heard of. That defeats the purpose of a
dynamic command list.
[Range]alone. Ranges help for coordinates andlevels, but a range of
0–511on an item number is still an empty box.Additional context
Related: #847, #848, sven-n/MuMain#539
Open questions:
[ValueReference]attribute with an enum, or separate marker attributesper kind?
GroupWiththe right way to express the item group/number pair, or shouldthere be a dedicated composite parameter concept?
into the DTO server-side, or left to the consumer?
attributes are being touched anyway?