Add new minigame volume templates and corresponding tests

- Introduced various minigame volume templates including map vote pad, NPC spawn, objective progress, player activation spawn, race, score zone, solo arena, team arena, team assignment pad, timed heal pack, and waiting area.
- Each template includes specific configurations for positions, shapes, effects, and tags relevant to their functionality.
- Implemented unit tests for minigame volume template export and spawn functionalities to ensure correct behavior and tag rewriting.
- Added tests for minigame map discovery service to validate player respawn logic based on team assignments.
- Enhanced minigame queue service tests to cover player join midgame scenarios.
- Created a data store test for saving and loading player defaults in the minigame template builder.
This commit is contained in:
2026-06-21 13:04:16 -07:00
parent cefe008cae
commit ca11bbd4c0
38 changed files with 2655 additions and 23 deletions
+43
View File
@@ -109,3 +109,46 @@ The old custom minigame volume system was removed. Use Hytale's trigger-volume e
volume placement and attach the minigame trigger effects and conditions there.
`/triggervolume clone` and `/triggervolume clonegroup` (injected by this plugin) help
duplicate configured volumes between maps.
### `/triggervolume minigametemplate <templateName> <flags>`
Spawns an asset-backed minigame trigger-volume template as normal trigger volumes
relative to the command sender's position.
Supported forms:
```text
/triggervolume minigametemplate core_lifecycle --MinigameId=Fishing --MapId=Lake
/triggervolume minigametemplate team_arena --MinigameId=Battle--MapId=Castle--VariantId=Night
```
`MinigameId` and `MapId` are required. `VariantId` is optional. Spawned volume names
replace the template prefix, so `Template_MainArena` becomes
`Fishing_Lake_MainArena` or `Battle_Castle_Night_MainArena`.
The command fails before creating anything when any target volume or group name already
exists. Spawned volumes are normal Hytale trigger volumes and can be moved, resized, and
edited in the trigger-volume editor.
### `/triggervolume minigametemplates`
Opens the builder UI for template spawning. Builders can enter `MinigameId`, `MapId`,
and optional `VariantId` once, then click any loaded template to spawn it at their
current position. The variables are saved per player under the plugin data directory and
are reused until the builder changes them.
### `/triggervolume templategroup <pack> <groupName> <templateId> <name>`
Exports an existing trigger-volume group in the world as a new `MinigameVolumeTemplate`
asset in `<pack>/Server/MinigameVolumeTemplates/<templateId>.json`.
The group origin becomes the template origin. Member volumes are stored at positions
relative to that origin, their ids are rewritten to `Template_<Purpose>`, and
`MinigameId`, `MapId`, and `VariantId` tags are rewritten to `Template`.
```text
/triggervolume templategroup MyAssetPack Battle_Castle core_battle "Core Battle"
```
The new template appears after the next asset reload/server restart and can be spawned
with `/triggervolume minigametemplate` or the template builder UI.
+4 -3
View File
@@ -125,14 +125,15 @@ Use an explicit `PlayerId` only when the trigger is not naturally tied to the pl
1. The effect's explicit `DestinationId`.
2. The player's stored checkpoint from `SetSpawnPoint`.
3. A random team spawn volume matching the player's `TeamId`.
4. A random shared player spawn volume.
Team spawn volumes are normal Hytale trigger volumes tagged with `MinigameId`, `MapId`, optional `VariantId`, `SpawnRole=TeamSpawn`, and `TeamId=<team id>`.
Shared spawn volumes are normal Hytale trigger volumes tagged with `MinigameId`, `MapId`, optional `VariantId`, and `SpawnRole=PlayerSpawn`. Team spawn volumes add `SpawnRole=TeamSpawn` and `TeamId=<team id>`. Runtime chooses a matching team spawn first, then falls back to a shared `PlayerSpawn`.
Player deaths during a minigame use the same resolution order automatically. `RespawnPlayer.DestinationId` accepts coordinate strings, such as `100,64,200` or `world_name,100,64,200`; `SetSpawnPoint` exposes separate `X`, `Y`, and `Z` fields and stores them as the player's checkpoint.
`RespawnAllPlayers` applies the same resolution to every player at once, making it the building block for resetting the arena between rounds. Because checkpoints (step 2) take priority over team spawns (step 3), set `ClearCheckpoints=true` when you want players sent back to their start line or team spawn rather than wherever they last checkpointed. A typical round transition chains `SetRound``ResetScores` (optional) → `SwapTeams` (for alternating-sides maps) → `RespawnAllPlayers`.
`RespawnAllPlayers` applies the same resolution to every player at once, making it the building block for resetting the arena between rounds. Because checkpoints (step 2) take priority over tagged spawn volumes (steps 3-4), set `ClearCheckpoints=true` when you want players sent back to their start line or team spawn rather than wherever they last checkpointed. A typical round transition chains `SetRound``ResetScores` (optional) → `SwapTeams` (for alternating-sides maps) → `RespawnAllPlayers`.
`SwapTeams` rotates team membership for maps where sides alternate each round (attack/defend). It clears checkpoints by default so the follow-up respawn resolves the new team's spawn; this relies on each side having team spawn volumes tagged as above. With its `Respawn` flag left on, it moves players to their new side immediately and no separate `RespawnAllPlayers` is needed.
`SwapTeams` rotates team membership for maps where sides alternate each round (attack/defend). It clears checkpoints by default so the follow-up respawn resolves the new team's spawn; this relies on each side having team spawn volumes tagged as above, with shared `PlayerSpawn` volumes as fallback. With its `Respawn` flag left on, it moves players to their new side immediately and no separate `RespawnAllPlayers` is needed.
## Item Spawners
+14 -6
View File
@@ -1,6 +1,6 @@
# Trigger Volume Tags
core-minigames uses normal Hytale trigger-volume tags for map discovery, runtime routing, team spawns, kill scoring, and runtime signals. Tag keys and values are case-sensitive.
core-minigames uses normal Hytale trigger-volume tags for map discovery, runtime routing, player/team spawns, kill scoring, and runtime signals. Tag keys and values are case-sensitive.
## Map And Runtime Tags
@@ -34,17 +34,25 @@ Overlapping volumes are allowed. Volumes with the same `MinigameId`, `MapId`, an
## Spawn Tags
Team spawn volumes are normal trigger volumes used as teleport destinations by `RespawnPlayer`.
Spawn volumes are normal trigger volumes used as random teleport destinations by `RespawnPlayer`, `RespawnAllPlayers`, and automatic death respawns.
| Tag | Required | Values | Used By |
|-----|----------|--------|---------|
| `MinigameId` | Recommended | Minigame ID | Filters spawns to the current runtime's minigame |
| `MapId` | Recommended | Map ID | Filters spawns to the current runtime's map |
| `VariantId` | No | Variant ID | Filters spawns to the current runtime's variant when present |
| `SpawnRole` | Yes | `TeamSpawn` | Marks the volume as a team spawn candidate |
| `TeamId` | Yes | Team ID, such as `red` or `blue` | Selects spawns for the player's assigned team; also used by `ModifyScore`/`ModifyLives` when `TargetSource=TAG_TEAM_ID` |
| `SpawnRole` | Yes | `PlayerSpawn` or `TeamSpawn` | Marks the volume as a spawn candidate |
| `TeamId` | Only for team-specific spawns | Team ID, such as `red` or `blue` | Selects spawns for the player's assigned team; also used by `ModifyScore`/`ModifyLives` when `TargetSource=TAG_TEAM_ID` |
Example:
All-player spawn example:
```text
MinigameId=FFA
MapId=Arena
SpawnRole=PlayerSpawn
```
Team spawn example:
```text
MinigameId=KOTH
@@ -53,7 +61,7 @@ SpawnRole=TeamSpawn
TeamId=red
```
`RespawnPlayer` chooses a random matching team spawn when no explicit `DestinationId` and no player checkpoint are available.
`RespawnPlayer` first chooses a random matching team spawn when the player has a `TeamId`. If no matching team spawn exists, or the player has no team, it chooses a random `PlayerSpawn` volume without `TeamId`.
`ModifyScore` and `ModifyLives` can also read `TeamId` from any trigger volume, not only team spawns. This lets one volume award points to the triggering player's team while removing lives/respawns from the team named in that volume's `TeamId` tag.
+56 -4
View File
@@ -22,6 +22,50 @@ Overlapping volumes are valid. Runtime routing uses the selected `MinigameId`, `
## Common Patterns
### Template Spawning
Use `/triggervolume minigametemplate` to place a starter set of normal Hytale trigger
volumes at your current position:
```text
/triggervolume minigametemplate core_lifecycle --MinigameId=MyGame --MapId=Arena01
```
Use `/triggervolume minigametemplates` for the builder UI version. It remembers the
builder's `MinigameId`, `MapId`, and optional `VariantId`, then lists every loaded
template as a one-click spawn action.
Use `/triggervolume templategroup <pack> <groupName> <templateId> <name>` to turn a
configured trigger-volume group in the current world into a reusable template asset.
The exporter stores member positions relative to the group origin and rewrites
minigame/map/variant tags to `Template`.
Templates are assets in `Server/MinigameVolumeTemplates/` and can be edited in the
asset editor. Template volume ids should use `Template_{VolumePurpose}`. When spawned,
`Template` is replaced with `MinigameId_MapId` plus optional `VariantId`, and tags with
`MinigameId=Template`, `MapId=Template`, and `VariantId=Template` are replaced with the
provided command values.
Built-in templates:
- `core_lifecycle`
- `solo_arena`
- `team_arena`
- `race`
- `capture_point`
- `item_spawn`
- `npc_spawn`
- `waiting_area`
- `join_late_spectator`
- `timed_heal_pack`
- `checkpoint`
- `deathzone`
- `map_vote_pad`
- `score_zone`
- `objective_progress`
- `team_assignment_pad`
- `player_activation_spawn`
### Start Zone
Use a normal trigger volume at an entrance, sign, NPC, or lobby pad.
@@ -70,11 +114,18 @@ Use Hytale's normal volume behavior for the area and guard attached effects with
- Condition: `MinigamePhase`
- Field: `Phase = ACTIVE`
### Team Spawns
### Player And Team Spawns
Use normal trigger volumes as spawn markers. The volume position is the teleport destination.
Tag each team spawn volume with:
Tag shared all-player spawn volumes with:
- `MinigameId=<your minigame>`
- `MapId=<map id>`
- optional `VariantId=<variant id>`
- `SpawnRole=PlayerSpawn`
Tag each team-specific spawn volume with:
- `MinigameId=<your minigame>`
- `MapId=<map id>`
@@ -87,10 +138,11 @@ Tag each team spawn volume with:
1. The effect's explicit `DestinationId`.
2. The player's stored checkpoint from `SetSpawnPoint`.
3. A random matching team spawn volume for the player's `TeamId`.
4. A random shared `PlayerSpawn` volume with no `TeamId`.
This means checkpoint-based games can still override spawns per player, while team arena games can rely on tagged team spawn volumes.
This means checkpoint-based games can still override spawns per player, team arena games can rely on tagged team spawn volumes, and solo/FFA games can rely on a pool of shared `PlayerSpawn` volumes.
Player deaths during a minigame automatically use the same destination order. `RespawnPlayer.DestinationId` accepts coordinate strings, such as `100,64,200` or `world_name,100,64,200`; `SetSpawnPoint` uses separate `X`, `Y`, and `Z` fields. Team-spawn fallback is resolved from tagged spawn volumes.
Player deaths during a minigame automatically use the same destination order. `RespawnPlayer.DestinationId` accepts coordinate strings, such as `100,64,200` or `world_name,100,64,200`; `SetSpawnPoint` uses separate `X`, `Y`, and `Z` fields. Spawn fallback is resolved from tagged spawn volumes.
### Counters