.... I didn't forget to commit for a while... You can't tell
This commit is contained in:
@@ -12,7 +12,7 @@ Each capture zone uses:
|
||||
|
||||
- A **TICK** volume type so it fires continuously while players are standing inside it.
|
||||
- A `CurrentRound` condition that passes only when the correct round number is active.
|
||||
- A `ModifyPlayerScore` effect that adds 1 point per trigger fire.
|
||||
- A `ModifyScore` effect that adds 1 point per trigger fire.
|
||||
|
||||
The tick rate on the volume controls how often points are awarded. Set it to **1 second** in the editor so players earn 1 point per second. If the tick fires every 0.5 seconds, players would earn 2 points per second : adjust the amount or tick rate to your preference.
|
||||
leaving it at zero would be everytick its fired, Giving 30 points
|
||||
@@ -42,7 +42,7 @@ Place this volume on Hilltop A, the first round's scoring area. Size it so that
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `ModifyPlayerScore` | `MinigameId = King_Of_The_Hill`, `Operation = ADD`, `Amount = 1` |
|
||||
| `ModifyScore` | `MinigameId = King_Of_The_Hill`, `TargetType = PLAYER`, `TargetSource = TRIGGERING_PLAYER`, `Operation = ADD`, `Amount = 1` |
|
||||
|
||||
---
|
||||
|
||||
@@ -65,7 +65,7 @@ Place this volume on Hilltop B. Same setup as Zone A with only the round number
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `ModifyPlayerScore` | `MinigameId = King_Of_The_Hill`, `Operation = ADD`, `Amount = 1` |
|
||||
| `ModifyScore` | `MinigameId = King_Of_The_Hill`, `TargetType = PLAYER`, `TargetSource = TRIGGERING_PLAYER`, `Operation = ADD`, `Amount = 1` |
|
||||
|
||||
---
|
||||
|
||||
@@ -88,7 +88,7 @@ Place this volume on Hilltop C.
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `ModifyPlayerScore` | `MinigameId = King_Of_The_Hill`, `Operation = ADD`, `Amount = 1` |
|
||||
| `ModifyScore` | `MinigameId = King_Of_The_Hill`, `TargetType = PLAYER`, `TargetSource = TRIGGERING_PLAYER`, `Operation = ADD`, `Amount = 1` |
|
||||
|
||||
---
|
||||
|
||||
@@ -106,7 +106,7 @@ On Tag Added trigger
|
||||
|
||||
|
||||
|
||||
**Multiple players on the hill at once** : each player in the volume gets the `ModifyPlayerScore` effect independently. If two players stand on Hilltop A during Round 1, both earn +1/second. This is intentional for KOTH : fighting over the hill is part of the game.
|
||||
**Multiple players on the hill at once** : each player in the volume gets the `ModifyScore` effect independently. If two players stand on Hilltop A during Round 1, both earn +1/second. This is intentional for KOTH : fighting over the hill is part of the game.
|
||||
|
||||
**Zone size** : make your capture zones intentionally tight so there is real competition for the spot. A zone that is too large removes the "king of the hill" tension.
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ All volumes and the definition file in one place. Use this as a checklist when s
|
||||
| 2 | Queue Pad | Enter | `MinigameId=King_Of_The_Hill` | — | `JoinMinigameQueue` → `StartQueuedMinigame` |
|
||||
| 3 | Starting Signal | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalPhaseStart=STARTING` | — | `SetMinigamePhase ACTIVE` |
|
||||
| 4 | Spawn Zone | Enter | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `MinigamePhase=ACTIVE` | `SetPlayerStatus ACTIVE` → `SetSpawnPoint` |
|
||||
| 5 | Capture Zone A | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 1` | `ModifyPlayerScore ADD 1` |
|
||||
| 6 | Capture Zone B | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 2` | `ModifyPlayerScore ADD 1` |
|
||||
| 7 | Capture Zone C | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 3` | `ModifyPlayerScore ADD 1` |
|
||||
| 5 | Capture Zone A | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 1` | `ModifyScore PLAYER TRIGGERING_PLAYER ADD 1` |
|
||||
| 6 | Capture Zone B | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 2` | `ModifyScore PLAYER TRIGGERING_PLAYER ADD 1` |
|
||||
| 7 | Capture Zone C | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 3` | `ModifyScore PLAYER TRIGGERING_PLAYER ADD 1` |
|
||||
| 8 | Round 2 Signal | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalRoundStart=2` | — | `SendMinigameMessage round_2_start ALL` |
|
||||
| 9 | Round 3 Signal | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalRoundStart=3` | — | `SendMinigameMessage round_3_start ALL` |
|
||||
| 10 | End Announcement | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalPhaseStart=ENDING` | — | `SendMinigameMessage game_over ALL` *(optional)* |
|
||||
@@ -115,7 +115,7 @@ Conditions:
|
||||
CurrentRound MinigameId=King_Of_The_Hill Compare=EQUAL Round=1
|
||||
|
||||
Effects:
|
||||
ModifyPlayerScore MinigameId=King_Of_The_Hill Operation=ADD Amount=1
|
||||
ModifyScore MinigameId=King_Of_The_Hill TargetType=PLAYER TargetSource=TRIGGERING_PLAYER Operation=ADD Amount=1
|
||||
```
|
||||
|
||||
Change `Round=1` to `Round=2` and `Round=3` for Zones B and C.
|
||||
|
||||
+51
-3
@@ -49,6 +49,55 @@ Runtime state includes:
|
||||
|
||||
`DefaultMinigameService` handles definition-level actions and delegates live actions to the runtime service.
|
||||
|
||||
## Lifecycle Contract
|
||||
|
||||
The built-in lifecycle is intentionally minimal — most progression is **volume-driven**
|
||||
so map designers control exactly when things happen:
|
||||
|
||||
```text
|
||||
WAITING_FOR_PLAYERS set automatically on start; countdown runs (CountdownSeconds)
|
||||
|
|
||||
v
|
||||
STARTING set automatically when the countdown finishes
|
||||
|
|
||||
v
|
||||
ACTIVE set by a volume: SetMinigamePhase(ACTIVE) <-- REQUIRED
|
||||
|
|
||||
v (rounds: a SetRound effect starts round 1 and the $round timer)
|
||||
OVERTIME / SUDDEN_DEATH automatic after the final round, when enabled (timed)
|
||||
|
|
||||
v
|
||||
ENDING -> RESETTING via EndMinigame effect, /minigame stop, or round completion
|
||||
```
|
||||
|
||||
Hard rules:
|
||||
|
||||
- **A game refuses to start when no trigger volume carries a `SetMinigamePhase(ACTIVE)`
|
||||
effect for its minigame/map/variant ids.** Queued players are told why. This catches
|
||||
maps whose lifecycle wiring is incomplete instead of leaving the game stuck in `STARTING`.
|
||||
- The round system only runs after a `SetRound` effect fires (typically from the
|
||||
`SignalPhaseStart=ACTIVE` volume). `TotalRounds`/`RoundLengthSeconds` alone do nothing.
|
||||
- `SetMinigamePhase(ENDING)` and `(RESETTING)` route through the full end/reset lifecycle
|
||||
(cleanup, rewards, inventory restore) — they are equivalent to `EndMinigame`/`ResetMinigame`.
|
||||
- With `MapSelectionMode: VOTE` and more than one voteable map, reaching `MinPlayers`
|
||||
opens a 30-second vote window. The game starts when every queued player has voted or
|
||||
the window expires.
|
||||
|
||||
## Threading Model
|
||||
|
||||
Each Hytale world ticks on its own thread. The rules this module follows:
|
||||
|
||||
- Every `MinigameRuntime` records a **home world** at start (adopted on first pregame
|
||||
tick if unknown). All mutation of runtime state happens on that world's thread.
|
||||
- Ticking systems (pregame, HUD, queue UI, menu) run per world and only touch runtimes
|
||||
homed in their world.
|
||||
- The signal-service scheduler thread never mutates state directly — it hops onto the
|
||||
home world via `world.execute(...)`.
|
||||
- Queue sessions are shared across worlds and synchronized internally.
|
||||
- Adapter calls that need a result (`saveInventory`) only run on the player's own world
|
||||
thread; cross-world void calls (give item, teleport, restore) are forwarded with
|
||||
`world.execute` and never block the calling thread.
|
||||
|
||||
## Events
|
||||
|
||||
`MinigameEvent` implements Hytale's `IEvent<String>`.
|
||||
@@ -94,10 +143,9 @@ Current effect type IDs:
|
||||
- `ResetMinigame`
|
||||
- `SetMinigamePhase`
|
||||
- `ResetScores`
|
||||
- `ModifyPlayerScore`
|
||||
- `ModifyTeamScore`
|
||||
- `ModifyScore`
|
||||
- `ModifyCounter`
|
||||
- `ModifyPlayerLives`
|
||||
- `ModifyLives`
|
||||
- `SetPlayerStatus`
|
||||
- `JoinMinigameQueue`
|
||||
- `LeaveMinigameQueue`
|
||||
|
||||
+48
-37
@@ -8,62 +8,67 @@ All commands are subcommands of `/minigame`.
|
||||
|
||||
Lists registered minigames and basic runtime state.
|
||||
|
||||
### `/minigame create <id> <name>`
|
||||
### `/minigame create <pack> <id> <name>`
|
||||
|
||||
Creates a new minigame definition with default settings.
|
||||
Creates a new minigame definition with default settings and saves it **into the named
|
||||
asset pack** (`<pack>/Server/Minigames/<id>.json`). The pack must exist and be writable
|
||||
(not a read-only/zipped pack). Because the definition lives in an asset pack, it is
|
||||
reloaded by the normal asset scan on every server start.
|
||||
|
||||
```text
|
||||
/minigame create Beach_Race "Beach Race"
|
||||
/minigame create KingOfHillAssetPack Beach_Race "Beach Race"
|
||||
```
|
||||
|
||||
Definitions created by command start disabled. Enable them when the asset is configured.
|
||||
Ids may only contain letters, numbers, `_` and `-`.
|
||||
|
||||
### `/minigame info <id>`
|
||||
|
||||
Shows the loaded definition and runtime status for a minigame.
|
||||
|
||||
### `/minigame edit <id> <field> <value>`
|
||||
### `/minigame edit <id> <property> <value>`
|
||||
|
||||
Edits a single definition field and saves the definition.
|
||||
Edits a simple definition property and saves it back into its asset pack.
|
||||
Supported properties: `name`, `description`, `enabled`. Use the Hytale asset
|
||||
editor for everything else.
|
||||
|
||||
```text
|
||||
/minigame edit Beach_Race MaxPlayers 16
|
||||
/minigame edit Beach_Race RoundLengthSeconds 600
|
||||
/minigame edit Beach_Race name Beach Race Deluxe
|
||||
/minigame edit Beach_Race enabled true
|
||||
```
|
||||
|
||||
### `/minigame enable <id>`
|
||||
### `/minigame enable <id>` / `/minigame disable <id>`
|
||||
|
||||
Sets `Enabled = true`.
|
||||
|
||||
### `/minigame disable <id>`
|
||||
|
||||
Sets `Enabled = false`. This prevents new starts but does not necessarily stop an already running runtime.
|
||||
Sets `Enabled` and persists the definition to its asset pack. Disabling prevents new
|
||||
queue joins and starts but does not stop an already running runtime.
|
||||
|
||||
### `/minigame validate <id>`
|
||||
|
||||
Runs definition validation. Current validation focuses on definition fields. The old custom-volume requirement for `MinigameAreaVolume` no longer applies.
|
||||
Runs definition validation (player counts, round length, countdown, overtime/sudden-death
|
||||
timer settings).
|
||||
|
||||
### `/minigame delete <id>`
|
||||
|
||||
Deletes the minigame definition.
|
||||
|
||||
### `/minigame export <id>`
|
||||
|
||||
Exports the current definition JSON.
|
||||
|
||||
### `/minigame import <file>`
|
||||
|
||||
Imports a definition from a JSON file path relative to the data directory.
|
||||
Ends any running runtimes, removes the definition from the asset store, and deletes its
|
||||
file from its asset pack. Definitions in read-only packs cannot be deleted.
|
||||
|
||||
## Runtime Management
|
||||
|
||||
### `/minigame start <id>`
|
||||
|
||||
Starts a queued runtime for the given minigame. The selected map comes from `MapSelectionMode`: highest vote for `VOTE`, random discovered map for `RANDOM`.
|
||||
Starts a queued runtime for the given minigame as an **admin start**: the min-player
|
||||
pregame check is skipped, so the game runs even with an empty or short queue.
|
||||
The selected map comes from `MapSelectionMode`: highest vote for `VOTE`, random
|
||||
discovered map for `RANDOM`.
|
||||
|
||||
### `/minigame stop <id>`
|
||||
A start is refused (with a message) when:
|
||||
|
||||
Stops all active runtimes for the minigame ID. An optional greedy `reason` argument can override the default admin-stop reason.
|
||||
- the definition has a `WorldId` and you are in a different world, or
|
||||
- no trigger volume sets the game's phase to `ACTIVE` (see *Lifecycle contract*
|
||||
in `architecture.md`).
|
||||
|
||||
### `/minigame stop <id> [reason]`
|
||||
|
||||
Stops all active runtimes for the minigame ID.
|
||||
|
||||
### `/minigame reset <id>`
|
||||
|
||||
@@ -73,28 +78,34 @@ Resets all active runtimes for the minigame ID.
|
||||
|
||||
### `/minigame maps <id>`
|
||||
|
||||
Lists maps discovered from trigger volumes in the sender's current world. Run this command as a player in the world containing the tagged volumes.
|
||||
Lists maps discovered from trigger volumes in the sender's current world. Run this command
|
||||
as a player in the world containing the tagged volumes.
|
||||
|
||||
### `/minigame vote <id> <mapId>`
|
||||
|
||||
Casts or updates the sender's vote in the minigame waiting session.
|
||||
Casts or updates the sender's vote. Only players who are in the queue may vote.
|
||||
|
||||
## Player Commands
|
||||
|
||||
### `/minigame join <id> [player]`
|
||||
|
||||
Adds the command sender, or the optional player target, to the minigame waiting queue.
|
||||
Adds the command sender, or the optional player target, to the minigame queue.
|
||||
Fails when the queue is full (`MaxPlayers`) or the minigame is disabled.
|
||||
|
||||
### `/minigame leave [player]`
|
||||
|
||||
Currently registered but not implemented. Use the `LeaveMinigameQueue` trigger effect for in-world queue leaving until the command is wired.
|
||||
Removes the player from every queue and from their current game. Leaving a game restores
|
||||
the player's saved inventory; if nobody is left in the runtime, it ends.
|
||||
|
||||
### `/minigame spectate <id>`
|
||||
### `/minigame spectate <id> [player]`
|
||||
|
||||
Currently registered but not implemented. The command validates that the minigame exists and has a running runtime, then returns a not-implemented message.
|
||||
Joins a running game as a spectator (requires `AllowSpectators: true` in the definition)
|
||||
and teleports the spectator to the game's MainArena volume when one is visible from
|
||||
their world. Spectators are excluded from rankings and the scoreboard.
|
||||
|
||||
## Volume Commands
|
||||
## Volume Workflow
|
||||
|
||||
The old custom minigame volume system was removed. Use Hytale's trigger-volume editor for real volume placement and attach the minigame trigger effects and conditions there.
|
||||
|
||||
`/minigame volume create <type>` currently remains as a command stub for future Hytale trigger-volume integration. It should not be used as the primary way to define arenas.
|
||||
The old custom minigame volume system was removed. Use Hytale's trigger-volume editor for
|
||||
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.
|
||||
|
||||
@@ -20,7 +20,7 @@ Current runtime events emitted by the service layer:
|
||||
| `on_sudden_death_start` | The final round ends and `SuddenDeathEnabled=true`. Phase is set to `SUDDEN_DEATH`. Fired before `on_game_rounds_complete`. |
|
||||
| `on_game_rounds_complete` | The final configured round ends (after any overtime/sudden-death events). |
|
||||
| `on_timer_expired` | A named signal timer expires. The internal `$round` timer is consumed by runtime round progression and is not re-dispatched. |
|
||||
| `on_player_eliminated` | `SetPlayerStatus` sets `ELIMINATED`, or `ModifyPlayerLives` reduces lives to zero. |
|
||||
| `on_player_eliminated` | `SetPlayerStatus` sets `ELIMINATED`, or `ModifyLives` reduces lives to zero. |
|
||||
| `on_objective_complete` | An objective status becomes `COMPLETE` or objective progress reaches completion. |
|
||||
| `on_kill_score` | The kill scoring system awards points for a configured kill. |
|
||||
|
||||
@@ -60,7 +60,7 @@ All minigame conditions share a `MinigameId` field. In the editor this is regist
|
||||
|
||||
## Effects
|
||||
|
||||
All minigame effects that operate on a runtime include a `MinigameId` field. In the editor this is registered as an asset picker backed by `MinigameDefinition` assets.
|
||||
All minigame effects that operate on a runtime include a `MinigameId` field. In the editor this is registered as an asset picker backed by `MinigameDefinition` assets. Item and block fields are likewise registered as the editor's built-in pickers: `SpawnItem`'s `ItemId` uses the `Item` picker and `PlaceBlocks`'s `BlockId` uses the `BlockType` picker (the same menus the vanilla `GiveItem` / `PlaceBlock` effects use), so designers select from the live asset list instead of typing raw ids.
|
||||
|
||||
| Type ID | Fields | Description |
|
||||
|---------|--------|-------------|
|
||||
@@ -69,7 +69,7 @@ All minigame effects that operate on a runtime include a `MinigameId` field. In
|
||||
| `LeaveMinigameQueue` | `MinigameId` | Removes the triggering player from the minigame waiting session and clears their vote. |
|
||||
| `VoteForMap` | `MinigameId`, optional `MapId` | Votes for a map in the waiting session. If `MapId` is blank, the triggering volume's `MapId` tag is used. |
|
||||
| `StartQueuedMinigame` | `MinigameId` | Starts a queued match using `MapSelectionMode` and discovered map tags. |
|
||||
| `SpawnItem` | optional `MinigameId`, `ItemId`, optional `Amount`, `RespawnDelaySeconds`, `SpawnKey`, `OffsetX`, `OffsetY`, `OffsetZ` | Spawns an item entity on the ground at the trigger volume position. When attached to a `TICK` volume, it respawns after the previous item is picked up or despawns and the delay has elapsed. |
|
||||
| `SpawnItem` | optional `MinigameId`, `ItemId`, optional `Amount`, `RespawnDelaySeconds`, `SpawnKey`, `OffsetX`, `OffsetY`, `OffsetZ`, optional `IgnoreRespawnTimer` | Spawns an item entity on the ground at the trigger volume position. When attached to a `TICK` volume, it respawns after the previous item is picked up or despawns and the delay has elapsed. When `IgnoreRespawnTimer` is `true`, it ignores whether the previous item still exists and spawns a fresh copy every `RespawnDelaySeconds` (or every tick when the delay is `0`). |
|
||||
| `SpawnNpc` | optional `MinigameId`, `RoleId`, optional `Count`, `RespawnDelaySeconds`, `SpawnKey`, `OffsetX`, `OffsetY`, `OffsetZ`, `Yaw`, `Pitch`, `Roll`, `SpreadRadius` | Spawns one or more NPCs at the trigger volume position. Spawned NPCs are tracked as temporary runtime entities and can respawn after all active NPCs for the spawn key are gone. |
|
||||
| `MountPlayer` | optional `MinigameId`, `PlayerId`, `NpcId`, `NpcRoleId`, `MaxDistance`, `AnchorX`, `AnchorY`, `AnchorZ`, `MovementConfig`, `EmptyRoleId`, optional `PreventManualDismount` | Mounts the triggering or configured player onto the nearest matching tracked NPC. When `PreventManualDismount` is `true`, the player cannot dismount manually until a `DismountPlayer` effect runs. |
|
||||
| `DismountPlayer` | optional `MinigameId`, optional `PlayerId`, optional `NpcRoleId`, optional `RemoveNpc` | Dismounts the player from their NPC mount. `RemoveNpc` defaults to `true` and removes the mount entity from the world. Clears any manual-dismount lock set by `MountPlayer`. |
|
||||
@@ -79,17 +79,18 @@ All minigame effects that operate on a runtime include a `MinigameId` field. In
|
||||
| `ResetMinigame` | `MinigameId` | Resets the selected minigame runtime. |
|
||||
| `SetMinigamePhase` | `MinigameId`, `Phase` | Sets the runtime phase directly. |
|
||||
| `ResetScores` | `MinigameId` | Resets all player and team scores for the runtime. |
|
||||
| `ModifyPlayerScore` | `MinigameId`, optional `PlayerId`, `Operation`, `Amount` | Sets, adds, or subtracts a player's score. |
|
||||
| `ModifyTeamScore` | `MinigameId`, `TeamId`, `Operation`, `Amount` | Sets, adds, or subtracts a team's score. |
|
||||
| `ModifyScore` | `MinigameId`, `TargetType`, `TargetSource`, `Operation`, `Amount` | Sets, adds, or subtracts player or team score. `TargetType=TEAM` with `TargetSource=TAG_TEAM_ID` uses the volume's `TeamId` tag. |
|
||||
| `ModifyCounter` | `MinigameId`, `CounterId`, `Operation`, `Amount` | Sets, adds, or subtracts a named runtime counter. |
|
||||
| `ModifyPlayerLives` | `MinigameId`, optional `PlayerId`, `Operation`, `Amount` | Sets, adds, or subtracts a player's remaining lives. |
|
||||
| `ModifyLives` | `MinigameId`, `TargetType`, `TargetSource`, `Operation`, `Amount` | Sets, adds, or subtracts one player's lives or all players on a resolved team. `TargetType=TEAM` with `TargetSource=TAG_TEAM_ID` uses the volume's `TeamId` tag. |
|
||||
| `SetPlayerStatus` | `MinigameId`, optional `PlayerId`, `Status` | Sets a player's minigame status. Setting `ACTIVE` triggers the activation lifecycle: saves inventory (if `SavePlayerInventory`), gives loadout or start items, and applies `RequiredGameMode`. |
|
||||
| `SetPlayerLoadout` | `MinigameId`, optional `PlayerId`, `LoadoutId` | Assigns a named loadout to a player. The loadout must exist in `StartLoadouts`. Takes effect the next time the player becomes `ACTIVE`. Pass an empty `LoadoutId` to clear the assignment. |
|
||||
| `SetRound` | `MinigameId`, `Operation`, `Amount` | Sets, adds, or subtracts the runtime round number and dispatches `on_round_start`. |
|
||||
| `StartTimer` | `MinigameId`, `TimerName`, `DurationSeconds` | Starts a named runtime timer and signal timer. |
|
||||
| `StopTimer` | `MinigameId`, `TimerName` | Stops a named runtime timer and cancels the signal timer. |
|
||||
| `SetSpawnPoint` | `MinigameId`, optional `PlayerId`, `DestinationId` | Stores a player's respawn destination/checkpoint. |
|
||||
| `SetSpawnPoint` | `MinigameId`, optional `PlayerId`, `X`, `Y`, `Z` | Stores a player's respawn destination/checkpoint. |
|
||||
| `RespawnPlayer` | `MinigameId`, optional `PlayerId`, optional `DestinationId` | Respawns a player using explicit destination, checkpoint, then team spawn fallback. |
|
||||
| `RespawnAllPlayers` | `MinigameId`, optional `DestinationId`, optional `ClearCheckpoints`, optional `ActiveOnly`, optional `ReactivateEliminated` | Respawns every player in the runtime in one pass (round reset). `ClearCheckpoints` wipes stored checkpoints first so players go to their team spawn / start instead of their last checkpoint. `DestinationId` overrides every player's spawn for this respawn (e.g. a shared race start). `ActiveOnly` (default `true`) skips spectators and eliminated players. `ReactivateEliminated` returns eliminated players to `ACTIVE` before respawning them. |
|
||||
| `SwapTeams` | `MinigameId`, optional `Rotation`, optional `ClearCheckpoints`, optional `Respawn` | Rotates players between teams for alternating-sides games. `Rotation` (default `1`) shifts each team's members forward in the id-sorted team list; `1` is a straight swap for two teams. `ClearCheckpoints` (default `true`) wipes checkpoints so respawn resolves the new side's spawn. `Respawn` (default `true`) teleports reassigned `ACTIVE` players to their new team spawn. Needs at least two teams. |
|
||||
| `SendMinigameMessage` | `MinigameId`, `MessageKey`, `Target` | Sends a translated message to `PLAYER`, `TEAM`, or `ALL`. |
|
||||
| `AssignTeam` | `MinigameId`, optional `PlayerId`, `TeamId`, optional `BalanceTeams` | Assigns a player to a team in the runtime. If `BalanceTeams` is true, evenly distributes all runtime players across existing teams or auto-creates `team1..teamN` using `TeamCount`, or `PlayersPerTeam` when `TeamCount` is `0`. |
|
||||
| `SaveInventory` | `MinigameId`, optional `PlayerId` | Saves the player's current inventory into runtime state. |
|
||||
@@ -127,7 +128,11 @@ Use an explicit `PlayerId` only when the trigger is not naturally tied to the pl
|
||||
|
||||
Team spawn volumes are normal Hytale trigger volumes tagged with `MinigameId`, `MapId`, optional `VariantId`, `SpawnRole=TeamSpawn`, and `TeamId=<team id>`.
|
||||
|
||||
Player deaths during a minigame use the same resolution order automatically. `DestinationId` and `SetSpawnPoint` checkpoint values are coordinate strings, such as `100,64,200` or `world_name,100,64,200`.
|
||||
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`.
|
||||
|
||||
`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.
|
||||
|
||||
## Item Spawners
|
||||
|
||||
@@ -135,6 +140,8 @@ Player deaths during a minigame use the same resolution order automatically. `De
|
||||
|
||||
For automatic respawns, attach it to a trigger volume that fires on `TICK`. The effect keeps one active item per volume plus `SpawnKey`; once that item reference is invalid, it waits `RespawnDelaySeconds` before spawning the next copy. If one volume hosts several item spawners, give each effect a different `SpawnKey`.
|
||||
|
||||
Set `IgnoreRespawnTimer=true` to drop the one-active-item rule and instead spawn a fresh copy on a fixed cadence regardless of whether the previous item was picked up or removed. The cadence is `RespawnDelaySeconds` between spawns (or every tick when the delay is `0`). Use this for a steady drip of items rather than a single replaceable pickup — be mindful that uncollected items accumulate in the world.
|
||||
|
||||
## NPC Spawners
|
||||
|
||||
`SpawnNpc` uses Hytale NPC role ids. `RoleId` is registered as a spawnable NPC role asset picker in the editor. Use `Count` plus `SpreadRadius` for small packs, and use `RespawnDelaySeconds` on a repeatedly firing volume when the encounter should come back after all NPCs for the same `SpawnKey` are gone.
|
||||
|
||||
+8
-5
@@ -62,10 +62,10 @@ Editor setup:
|
||||
|
||||
1. Create a normal Hytale trigger volume around the scoring area.
|
||||
2. Add `PlayerInMinigame` as a condition.
|
||||
3. Add `ModifyPlayerScore` as an effect.
|
||||
4. Set `MinigameId = Hill_Points`, `Operation = ADD`, and `Amount = 1`.
|
||||
3. Add `ModifyScore` as an effect.
|
||||
4. Set `MinigameId = Hill_Points`, `TargetType = PLAYER`, `TargetSource = TRIGGERING_PLAYER`, `Operation = ADD`, and `Amount = 1`.
|
||||
|
||||
If the trigger context already contains the player who entered the volume, leave `PlayerId` blank.
|
||||
If the trigger context contains the player who entered the volume, `TargetSource = TRIGGERING_PLAYER` awards that player.
|
||||
|
||||
## End When Score Reaches a Target
|
||||
|
||||
@@ -84,15 +84,18 @@ Effect:
|
||||
|
||||
## Team Score Zone
|
||||
|
||||
Use `ModifyTeamScore` when the score belongs to a team instead of a player.
|
||||
Use `ModifyScore` with `TargetType=TEAM` when the score belongs to a team instead of a player.
|
||||
|
||||
Required fields:
|
||||
|
||||
- `MinigameId`
|
||||
- `TeamId`
|
||||
- `TargetType = TEAM`
|
||||
- `TargetSource = TRIGGERING_TEAM` or `TAG_TEAM_ID`
|
||||
- `Operation`
|
||||
- `Amount`
|
||||
|
||||
When using `TargetSource = TAG_TEAM_ID`, add `TeamId=<team>` to the trigger volume tags.
|
||||
|
||||
Use `AssignTeam` with `BalanceTeams=true` to split all players in the started runtime evenly across teams. If no teams already exist, the effect creates `team1..teamN` from the minigame's `TeamCount`.
|
||||
|
||||
## Counter Gate
|
||||
|
||||
+12
-10
@@ -17,7 +17,7 @@ Minigame definitions live in `src/main/resources/Server/Minigames/<Id>.json`. JS
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `WorldId` | String | No | `""` | Optional world identifier. |
|
||||
| `WorldId` | String | No | `""` | When set, the game may only be started in this world; starts from other worlds are refused with a message. |
|
||||
| `RequiredGameMode` | Enum | No | `Adventure` | Game mode applied to each player when they become active. |
|
||||
|
||||
## Players
|
||||
@@ -27,14 +27,14 @@ Minigame definitions live in `src/main/resources/Server/Minigames/<Id>.json`. JS
|
||||
| `MinPlayers` | Integer | No | `1` | Minimum player count. |
|
||||
| `MaxPlayers` | Integer | No | `16` | Maximum player count. |
|
||||
| `DefaultPlayerLives` | Integer | No | `0` | Initial lives assigned to each player when a queued runtime starts. |
|
||||
| `AllowJoinMidgame` | Boolean | No | `false` | Whether players can join after the game starts. |
|
||||
| `AllowSpectators` | Boolean | No | `true` | Whether spectators are allowed. |
|
||||
| `AllowJoinMidgame` | Boolean | No | `false` | When `true`, a player who disconnects mid-game is re-activated on reconnect. When `false`, reconnecting players get their saved inventory back and are dropped from the game. |
|
||||
| `AllowSpectators` | Boolean | No | `true` | Whether `/minigame spectate` may join the game as a spectator. |
|
||||
|
||||
## Teams
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `TeamMode` | Enum | No | `SOLO` | `SOLO`, `TEAMS`, or `FREE_FOR_ALL`. |
|
||||
| `TeamMode` | Enum | No | `SOLO` | `SOLO`, `TEAMS`, or `FREE_FOR_ALL`. With `TEAMS`, teams are auto-created and balanced when a queued game starts (using `TeamCount` / `PlayersPerTeam`). |
|
||||
| `TeamCount` | Integer | No | `0` | Explicit number of teams when using `BalanceTeams`. `0` defers to `PlayersPerTeam`. |
|
||||
| `PlayersPerTeam` | Integer | No | `0` | When `TeamCount` is `0`, `BalanceTeams` divides total players by this to determine team count. `0` means no automatic splitting. |
|
||||
|
||||
@@ -45,8 +45,10 @@ Minigame definitions live in `src/main/resources/Server/Minigames/<Id>.json`. JS
|
||||
| `RoundLengthSeconds` | Integer | No | `300` | Active round duration. |
|
||||
| `TotalRounds` | Integer | No | `1` | Number of rounds to run. Values less than or equal to `0` allow open-ended round progression. |
|
||||
| `CountdownSeconds` | Integer | No | `10` | Pre-game countdown duration. |
|
||||
| `OvertimeEnabled` | Boolean | No | `false` | When the final round ends, sets the phase to `OVERTIME` and dispatches `on_overtime_start` before `on_game_rounds_complete`. |
|
||||
| `SuddenDeathEnabled` | Boolean | No | `false` | When the final round ends (after overtime if also enabled), sets the phase to `SUDDEN_DEATH` and dispatches `on_sudden_death_start`. |
|
||||
| `OvertimeEnabled` | Boolean | No | `false` | When the final round ends, enters `OVERTIME` for `OvertimeSeconds` and dispatches `on_overtime_start`. When the overtime timer expires the game either enters sudden death (if enabled) or ends. |
|
||||
| `OvertimeSeconds` | Integer | No | `60` | Overtime duration. Must be positive when overtime is enabled. |
|
||||
| `SuddenDeathEnabled` | Boolean | No | `false` | After the final round (and overtime, if enabled), enters `SUDDEN_DEATH` for `SuddenDeathSeconds` and dispatches `on_sudden_death_start`. The game ends when the timer expires. |
|
||||
| `SuddenDeathSeconds` | Integer | No | `60` | Sudden-death duration. Must be positive when sudden death is enabled. |
|
||||
|
||||
## Win Condition
|
||||
|
||||
@@ -72,16 +74,16 @@ Supported values:
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `AllowPvp` | Boolean | No | `false` | Whether players can damage each other. |
|
||||
| `AllowBlockBreaking` | Boolean | No | `false` | Whether blocks can be broken. Readable via definition; enforcement relies on `RequiredGameMode` (`Adventure` blocks both break and place by default). |
|
||||
| `AllowBlockPlacing` | Boolean | No | `false` | Whether blocks can be placed. Same enforcement note as above. |
|
||||
| `AllowPvp` | Boolean | No | `false` | Enforced: player-vs-player damage is cancelled for players in this game when `false` (applies when either the attacker or the victim is in a no-PvP game). |
|
||||
| `AllowBlockBreaking` | Boolean | No | `false` | Enforced: block breaking by players in this game is cancelled when `false`. |
|
||||
| `AllowBlockPlacing` | Boolean | No | `false` | Enforced: block placing by players in this game is cancelled when `false`. |
|
||||
|
||||
## Lifecycle
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `ResetOnEnd` | Boolean | No | `true` | After clearing runtime state at game end, dispatches `on_arena_reset` so trigger volumes can reset world state. |
|
||||
| `SavePlayerInventory` | Boolean | No | `true` | Saves each player's inventory the first time they become `ACTIVE`. Restored on game end if `RestorePlayerInventory` is true. |
|
||||
| `SavePlayerInventory` | Boolean | No | `true` | Saves and then **clears** each player's inventory the first time they become `ACTIVE`. Items are only granted by volume effects (`SetPlayerLoadout`, `SpawnItem`) — nothing is given automatically. Restored on game end if `RestorePlayerInventory` is true, and when a player leaves or disconnects. |
|
||||
| `RestorePlayerInventory` | Boolean | No | `true` | Restores each player's saved inventory when the game ends. |
|
||||
|
||||
## Items
|
||||
|
||||
@@ -11,13 +11,4 @@ Make it in the set spawn point you can type the XYZ for where to spawn the playe
|
||||
the double send message name. Need to change the custom one.
|
||||
|
||||
|
||||
|
||||
## Bugs
|
||||
|
||||
|
||||
|
||||
## Completed
|
||||
|
||||
- **HUD top-right positioning** — HUD anchor now uses `setRight(8).setTop(8)` and renders in the top-right corner.
|
||||
- **Scoreboard HUD panel** (`ShowScoreboard` in definition) — ranked player list with name + score shown below the standard HUD tiles. Capped at 10 rows. IDs are stable for delta refresh.
|
||||
- **Queue UI system** (`OpenMinigameQueueUI` effect) — three modes: Global (all UIQueueable games), Single (one game's maps), Local (single arena popup). Join auto-attempts game start. Leave queue button shown when already queued. Volume tags: `UIQueue=True` + `UIQueueType=Global|Single|Local` on `MainArena` volumes. Definition flag: `UIQueueable=true`.
|
||||
|
||||
+3
-1
@@ -42,7 +42,7 @@ Team spawn volumes are normal trigger volumes used as teleport destinations by `
|
||||
| `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 |
|
||||
| `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` |
|
||||
|
||||
Example:
|
||||
|
||||
@@ -55,6 +55,8 @@ TeamId=red
|
||||
|
||||
`RespawnPlayer` chooses a random matching team spawn when no explicit `DestinationId` and no player checkpoint are available.
|
||||
|
||||
`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.
|
||||
|
||||
## Signal Tags
|
||||
|
||||
Signal tags let runtime state changes fire normal Hytale trigger-volume logic by toggling a tag on matching volumes.
|
||||
|
||||
+3
-3
@@ -58,10 +58,10 @@ Use a normal trigger volume around the scoring area.
|
||||
Attach:
|
||||
|
||||
- Condition: `PlayerInMinigame`
|
||||
- Effect: `ModifyPlayerScore`
|
||||
- Effect: `ModifyScore`
|
||||
- Fields: `Operation = ADD`, `Amount = <points>`
|
||||
|
||||
If the score is team-based, use `ModifyTeamScore` instead.
|
||||
If the score is team-based, use `ModifyScore` with `TargetType=TEAM`.
|
||||
|
||||
### Phase Gate
|
||||
|
||||
@@ -90,7 +90,7 @@ Tag each team spawn volume with:
|
||||
|
||||
This means checkpoint-based games can still override spawns per player, while team arena games can rely on tagged team spawn volumes.
|
||||
|
||||
Player deaths during a minigame automatically use the same destination order. `DestinationId` and `SetSpawnPoint` values are coordinate strings, such as `100,64,200` or `world_name,100,64,200`; 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. Team-spawn fallback is resolved from tagged spawn volumes.
|
||||
|
||||
### Counters
|
||||
|
||||
|
||||
Reference in New Issue
Block a user