refactor/communication-commands #505

Merged
scion merged 24 commits from refactor/communication-commands into master 2026-05-29 16:54:56 -07:00
Owner

Major refactor of all forms of communication. Brought all the command implementations for communication commands together into a single command driven by configuration that lives in the database and comes with an editor to change it from inside the game. From the perspective of a player it should look and work exactly the same, but now admins can create and edit "channels" on the fly as much as they want with no code changes.

Major refactor of all forms of communication. Brought all the command implementations for communication commands together into a single command driven by configuration that lives in the database and comes with an editor to change it from inside the game. From the perspective of a player it should look and work exactly the same, but now admins can create and edit "channels" on the fly as much as they want with no code changes.
Add the foundation entities, enums, repository, and seed data loader
for the data-driven communication channel refactor:

- PoolType enum: ROOM, ZONE, WORLD, ALL_ONLINE candidate pools
- FilterType enum: NOT_SENDER, NOT_TARGET, ROLE, CLAN, LEVEL_MIN, LEVEL_MAX
- CommChannel entity: name, description, format strings, pool type,
  direct target type, aliases, and cascaded ChannelFilter list
- ChannelFilter entity: filter type and parameter linked to a channel
- CommChannelRepository: JPA repository with case-insensitive lookup
- CommChannelLoader: seeds the 6 existing channels (SAY, EMOTE, SHOUT,
  GOSSIP, TELL, WHISPER) with identical behavior at startup
Add the single command that replaces all six individual comm commands
(Say, Emote, Shout, Gossip, Tell, Whisper).

- CommChannelCommand: @PostConstruct loads all CommChannel entities
  and dynamically registers a syntax for each. At runtime the first
  binding token determines which channel to dispatch to.

- Local output is formatted using the channel's localFormat string
  with sender/target/message arguments resolved per channel type.

- Remote delivery dispatches via existing CommService methods
  (sendToRoom, sendToZone, sendToAll, sendTo) based on the channel's
  pool type, preserving identical behavior.

- Bystander notifications (e.g. Whisper) are handled when the channel
  has a bystanderFormat configured.

- RepositoryBundle extended with CommChannelRepository so the command
  can look up channel configuration at runtime.
- AbstractCommand: change syntaxes field from private to protected so
  CommChannelCommand can clear and re-register syntaxes at runtime

- RepositoryBundleTest: add new CommChannelRepository mock parameter
  to match the updated constructor signature
Add a protected clearSyntaxes() method to AbstractCommand so subclasses
can rebuild their syntax list without needing direct access to the
private syntaxes field. Restore syntaxes to private.
Introduce the unified delivery method driven by CommChannel config:

- deliverChannel(): single entry point that builds a candidate pool,
  applies all ChannelFilter predicates, and delivers the appropriately
  formatted message to each recipient.

- buildPool(): constructs the initial candidate pool by pool type
  (ROOM, ZONE, WORLD, ALL_ONLINE). Returns only player-controlled
  characters in a valid room.

- filterPool() / filterMatches(): apply each ChannelFilter predicate
  (NOT_SENDER, NOT_TARGET, ROLE are fully implemented; CLAN,
  LEVEL_MIN, LEVEL_MAX return true as pass-through until the model
  supports those fields).

- CommChannelCommand now delegates all remote delivery to
  deliverChannel() instead of calling individual sendToRoom/Zone/All
  methods with a manual switch.

Legacy sendToRoom/Zone/All methods are preserved for existing non-channel
code (ForceCommand, etc.).
- ChannelConfigCommand: thin wrapper that transitions into the admin menu
- ChannelConfigQuestion: main menu (List/Create/Edit/Delete/View/Exit)
- ChannelConfigTargetQuestion: numbered channel picker for Edit/Delete/View
- ChannelConfigCreateQuestion: step-by-step wizard to create new channels
- ChannelConfigEditQuestion: field edit menu with filter management

Fixes:
- Use arrow-style switch syntax consistently (no mixing colon/break with arrow)
- Use java.lang.Enum.valueOf instead of nonexistent java.util.Enum
- Update SAY, TELL, WHISPER, SHOUT, GOSSIP, and EMOTE CommandReference entries
  to point to 'commChannelCommand' bean instead of individual command classes
- Add CHANNELCONFIG command reference (priority 30) pointing to
  'channelConfigCommand' bean for admin channel configuration
- CHANNELCONFIG is automatically available to Implementors via existing
  blanket permission model
- Add test for CommChannelCommand.init() via reflection to cover @PostConstruct
- Add test verifying registerSyntaxes() calls clearSyntaxes() before re-registering
- Strengthen CommChannel.addFilter() test to verify setChannel back-reference
- Add PoolTypeTest and FilterTypeTest for getDescription() enum coverage
- Add ChannelFilterTest for getId() and getChannel() coverage
- Add CommChannelTest covering getAliases() and removeFilter()
- Add CommServiceDeliverChannelTest for delivery path coverage

These changes address NO_COVERAGE and SURVIVED mutations across
PoolType, FilterType, ChannelFilter, CommChannel, and CommChannelCommand.
- Reject TokenType.INVALID as a valid direct target type in both
  ChannelConfigCreateQuestion and ChannelConfigEditQuestion
- Set nextStep to null before clearing wizard state in STEP_DESCRIPTION
  so the wizard step attribute isn't re-set after cleanup
- ChannelConfigCreateQuestionTest: section headers, null wizard step test
- ChannelConfigEditQuestionTest: section headers, null field rendering tests
- ChannelConfigQuestionTest: tests for null pool type, description,
  and direct target in channel list output
- ChannelConfigTargetQuestionTest: new test for target selection edge cases
remove refactor plan
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m32s
a38fa58a87
forgot to update tests
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m20s
9302aa1d3b
scion changed title from refactor/communication-commands to WIP: refactor/communication-commands 2026-05-28 01:40:22 -07:00
scion self-assigned this 2026-05-28 01:40:58 -07:00
fix: prevent ClassCastException in TELL/WHISPER commands
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m30s
caa8ce320c
The TELL and WHISPER commands were throwing ClassCastException because
broadcast channel syntaxes (single QUOTED_WORDS token) could match input
intended for direct-target channels (TARGET + QUOTED_WORDS) before the
more specific direct-target syntax was tried. This resulted in a 2-token
binding being passed to code expecting 3 tokens, causing String-to-
MudCharacter cast failure.

Fixes:

1. registerSyntaxes() now sorts channels so direct-target channels
   (TELL, WHISPER) are registered before broadcast channels (SAY, EMOTE,
   etc.), giving the more specific syntax first priority in matching.

2. execute() guards against a wrong binding count for direct-target
   channels: if fewer than 3 bindings arrive for a channel that
   expects a target + message, it returns silently instead of crashing.

Tests added:

- testDirectTargetSyntaxesRegisteredBeforeBroadcast: verifies sorting
- testTellWithWrongBindingCountReturnsSilently: verifies guard for TELL
- testWhisperWithWrongBindingCountReturnsSilently: verifies guard for WHISPER
Split CommChannelCommand into broadcast and direct-target variants
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m50s
39c00bccae
The original CommChannelCommand registered both broadcast (SAY, SHOUT, etc.)
and direct-target (TELL, WHISPER) syntaxes on a single command bean. When
CommandQuestion looped through these syntaxes trying to match input, the
broadcast [QUOTED_WORDS] syntax could match a direct-target command like
"tell jeff hello" as ["TELL", "jeff hello"] if the target player couldn't
be resolved — resulting in only 2 bindings instead of the expected 3,
and producing silent empty output.

The fix is two separate command beans:

- CommChannelCommand: registers only broadcast channels (no directTargetType)
  with a [QUOTED_WORDS] syntax.
- DirectCommChannelCommand: registers only direct-target channels with a
  [TARGET_TYPE, QUOTED_WORDS] syntax.

TELL and WHISPER CommandReference entries now point to
directCommChannelCommand instead of commChannelCommand. Admin channel
questions call registerSyntaxes() on both beans.
only show one error message, and only on failure
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m49s
0d106bdaf4
scion changed title from WIP: refactor/communication-commands to refactor/communication-commands 2026-05-29 09:04:10 -07:00
fix: return to filter sub-menu after adding a channel filter
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m39s
5a6af571c0
When editing a channel and adding a filter, the code was resetting
the edit state to null (main menu) instead of returning to the
filter management sub-menu (STATE_FILTER_SUB). This caused the
next user input to be interpreted as the filter type prompt again,
resulting in spurious 'Invalid filter type' errors.

Apply the same fix to:
- STATE_FILTER_ADD_TYPE on success (NOT_SENDER/NOT_TARGET paths)
- STATE_FILTER_ADD_TYPE on invalid input (IllegalArgumentException)
- STATE_FILTER_ADD_PARAM on success and on internal error

Add tests verifying the return state for all three cases.
Standardize ChannelConfig menus to use MenuPane/MenuItem
Some checks failed
CI Build & Test / build-and-test (pull_request) Has been cancelled
b632ae56de
Refactor ChannelConfigEditQuestion and ChannelConfigTargetQuestion to
use the standard MenuPane/MenuItem/MenuTitle/MenuPrompt pattern instead
of hand-crafted output.append lines. This brings the channel editor
menus in line with other editors (RoomEditor, ItemEditor, NPCCreature
Editor) for consistent look and feel:

- ChannelConfigEditQuestion: uses MenuPane with dynamic title
  "Edit Channel: <name>" and MenuItem entries for each field
- ChannelConfigEditQuestion: filter sub-menu now renders via its
  own MenuPane with "Filter Management" title
- ChannelConfigTargetQuestion: uses MenuPane with "Select Channel"
  title and MenuItem entries for each channel
- ChannelConfigTargetQuestion: added "X" Cancel option to back out
- Updated tests to match new MenuPane output format
javax annotation doesn't work anymore
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m38s
1be0d1008e
# Conflicts:
#	agonyforge-mud-demo/src/main/java/com/agonyforge/mud/demo/config/CommandLoader.java
#	agonyforge-mud-demo/src/main/java/com/agonyforge/mud/demo/config/ProfessionLoader.java
#	agonyforge-mud-demo/src/main/java/com/agonyforge/mud/demo/config/SpeciesLoader.java
#	agonyforge-mud-demo/src/main/java/com/agonyforge/mud/demo/config/WorldLoader.java
fix: replace put(key, null) with remove(key) in ChannelConfigEditQuestion
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m47s
a2ef8ccc4d
ConcurrentHashMap.put(key, null) throws NullPointerException, but the
production WebSocket session attributes are backed by ConcurrentHashMap
(via Spring SimpMessageHeaderAccessor). This caused NPEs when editing any
channel field (local/remote format, bystander, pool type, target,
description, filter sub-menu back, filter remove).

Replace all .put(ChanConfigField, null) with .remove(ChanConfigField)
in handleFieldInput. Semantically equivalent for clearing state, but
works correctly with ConcurrentHashMap.

Also add tests using a real ConcurrentHashMap as the attributes map to
regress against this bug.
Merge branch 'master' into refactor/communication-commands
All checks were successful
CI Build & Test / build-and-test (pull_request) Successful in 11m46s
47fd0d66a7
scion merged commit efdff09d3d into master 2026-05-29 16:54:56 -07:00
scion deleted branch refactor/communication-commands 2026-05-29 16:54:56 -07:00
Sign in to join this conversation.
No description provided.