Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The closed-source Mod remains authoritative for generated client and server API

## Structure

- `guides/` contains scripting concepts and tutorials. Each subdirectory is a sidebar section named after the directory (`guides/Getting started/first-resource.md` is served at `/guides/getting-started/first-resource/`). Sections are ordered by the lowest `sidebar.order` among their pages, so each section owns a range: Getting started 10–19, Core concepts 20–29, Players 30–39, NPCs and creatures 40–49, World 50–59, User interface 60–69, Camera and sound 70–79, Mounts and races 80–89, Hosting a server 90–99.
- `guides/` contains scripting concepts and tutorials. Each subdirectory is a sidebar section named after the directory (`guides/Getting started/first-resource.md` is served at `/guides/getting-started/first-resource/`). Sections are ordered by the lowest `sidebar.order` among their pages, so each section owns a range: Getting started 100–199, Core concepts 200–299, Players 300–399, NPCs and creatures 400–429, PvE 430–449, Encounters 450–469, PvP 470–499, World 500–549, Room of Requirement 550–599, User interface 600–699, Camera and sound 700–799, Mounts and races 800–849, Quidditch 850–899, Hosting a server 900–999. A section added between two takes the free part of a hundred, such as 450–499.
- Image directories live beside the Markdown document that references them.
- `docs.config.json` owns the generator pin, branding, links, navigation, and community-content mapping.
- `scripts/sync_contract.mjs` downloads and verifies the public scripting contract.
Expand Down
2 changes: 1 addition & 1 deletion guides/Camera and sound/audio.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Audio
description: Play the game's sounds at a place, on a player or for one player, stop sounds that keep playing, load soundbanks and change the music, from the server or a client.
sidebar:
order: 71
order: 710
---

Every sound in the game is a Wwise event, named like `cabbage_explosion` or `accio_cast`. The server's `Audio` global plays events on players' clients, and a client's `Audio` plays them for its own player. Event names ignore case, and positions and ranges are world centimetres.
Expand Down
2 changes: 1 addition & 1 deletion guides/Camera and sound/camera.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Camera
description: Take over the player's view with a camera of your own, move it in shots, paths and orbits, fade the screen, and hand the view back.
sidebar:
order: 70
order: 700
---

Each client has one custom camera that client scripts drive with the `Camera` global. While it is active, the player sees through it instead of the game's own camera, and `Camera.restore()` hands the view back. Positions are world centimetres, rotations are degrees and durations are seconds.
Expand Down
2 changes: 1 addition & 1 deletion guides/Camera and sound/voice-chat.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Voice chat
description: Who hears whom in proximity voice chat, how far voices carry, whispering and shouting, muting players, and the voice settings each player controls.
sidebar:
order: 72
order: 720
---

Players talk to the people near them, holding push-to-talk, which is V by default. The server's `Voice` global decides how far voices carry and who may talk or listen, and each client's `Voice` controls that player's own microphone and volume. Ranges are world centimetres.
Expand Down
4 changes: 2 additions & 2 deletions guides/Core concepts/authority.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Authority
description: What the server decides, what players' clients run and report, and how to handle what a client sends.
sidebar:
order: 20
order: 200
---

A HogwartsMP server and its players' clients split the work. The server owns the state that matters, and each client runs the game for its player and reports what happens in it. Knowing which side owns what tells you which input to trust.
Expand Down Expand Up @@ -36,7 +36,7 @@ Everything a client sends is a claim about its own game, and a modified client c
| `npcDamaged` | Clamped and rate-capped by the server, but reported by the attacker's client. |
| `playerInventoryChanged`, `playerInventoryNativeDelta` | The client's account of its game's inventory. Adopt a delta with `player.inventory.adoptNative()` only for items on an allowlist. |
| `playerLocationChanged`, teleport and fast-travel completions | The client's account of where it is and how a request went. |
| `housePointsRequest`, `beastCared` | Requests. They take effect unless a handler refuses them by returning `false`. |
| `housePointsRequest`, `beastCared`, `beastCaptureStart`, `beastCaptureRequest` | Requests. They take effect unless a handler refuses them by returning `false`. |
| `doorUnlockRequest` | A request. The door stays locked unless a script releases it. |
| `steamId`, `epicId`, `discordId`, `hardwareId` | Announced by the client. Never authorize anyone with them. |

Expand Down
50 changes: 41 additions & 9 deletions guides/Core concepts/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Events
description: Listen and emit across resources and the client/server boundary, the runtime event catalog, and what to trust.
sidebar:
order: 21
order: 210
---

`Events` is the asynchronous, named event bus available to both server and client resources. Resources use it to react to runtime activity, communicate with other resources in the same environment, and exchange messages across the client/server boundary.
Expand Down Expand Up @@ -136,6 +136,8 @@ Events.on("seasonChanged", (payload) => {

Runtime-generated events use the normal `Events.on` and `Events.once` subscriptions. They are raised by the framework or the native HogwartsMP module rather than by `Events.emit`. Avoid emitting custom events with these names.

The declarations type the handlers of the events in these tables, so an editor knows each argument. Events of your own, and the few native ones the declarations leave out, such as `chatSend` and the voice events, hand a TypeScript handler `unknown` arguments.

`resourceStart(resourceName)` and `resourceStop(resourceName)` are emitted by both the server and client resource managers when a JavaScript resource starts or is about to stop.

### Native server events
Expand All @@ -156,6 +158,8 @@ Runtime-generated events use the normal `Events.on` and `Events.once` subscripti
| `playerDownedEnd` | `(player)` | A player recovers from the downed state or respawns |
| `playerHoldEnded` | `(player, owner, reason)` | A server-owned hold ends; `reason` identifies why |
| `playerHoldStrained` | `(player, owner, distanceCm)` | A held player continues reporting positions beyond the hold boundary |
| `playerWandChanged` | `(player)` | The player's wand changes |
| `playerGearChanged` | `(player)` | What the player wears changes |
| `worldReady` | `(player)` | The player's world, pawn, and replication are ready |
| `loadingFinished` | `(player)` | The player's load screen is dismissed after `worldReady` |
| `playerInventoryChanged` | `(player, items)` | The player's reported native inventory changes; `items` is the full native inventory |
Expand All @@ -165,9 +169,32 @@ Runtime-generated events use the normal `Events.on` and `Events.once` subscripti
| `playerAppearanceChanged` | `(player, look, revision)` | The server accepts a new look from the player's game or `player.setLook`; `look` is the checked [look](/guides/players/appearance/#the-look) and `revision` increases for the connection |
| `playerTeleportComplete` | `(player, requestId, status, completion)` | A `player.teleport` request finishes; `completion` includes the normalized request, client-observed final transform, and ground-snap result |
| `playerFastTravelComplete` | `(player, requestId, status)` | A `player.fastTravel` request finishes or times out |
| `npcDied` | `(npcId, enemyId)` | A server-spawned NPC dies |
| `npcDied` | `(npcId, enemyId, killerId, damagerIds)` | A server-spawned NPC dies; `killerId` is the last player to damage it, or `null`, and `damagerIds` every player who did. See [Fighting NPCs](/guides/pve/fighting-npcs/#damage-and-death) |
| `npcDamaged` | `(npcId, attackerId, amount)` | A player reports damage to a server-spawned NPC |
| `beastCared` | `(beast, player, kind)` | A player pets or feeds a beast; return `false` synchronously to refuse it |
| `beastCaptureStart` | `(beast, player)` | A player's Nab-Sack starts drawing in a beast they may catch; return `false` synchronously to make it let go. See [Catching beasts](/guides/npcs-and-creatures/catching-beasts/#refereeing-a-catch) |
| `beastCaptureRequest` | `(beast, player)` | A player's Nab-Sack finished on a beast and the catch waits for the server; return `false` synchronously to refuse it |
| `beastCaptured` | `(player, captured)` | A catch landed: the beast is in the player's bag and has left the world |
| `beastReleased` | `(player, released, at)` | A player released a beast from their Field Guide; `at` is where they stood |
| `campActivated` | `(campId)` | A [camp](/guides/encounters/camps/)'s enemies spawn |
| `campCleared` | `(campId)` | Every enemy of an active camp is dead |
| `worldEventStarted` | `(spotId, kind)` | A [world event](/guides/encounters/world-events/) starts |
| `worldEventCleared` | `(spotId)` | Every enemy of a running world event is dead |
| `worldEventEnded` | `(spotId)` | A world event ends |
| `zoneEnter` | `(zone, entity)` | An entity comes into a [zone](/guides/encounters/zones/) |
| `zoneExit` | `(zone, entity, reason, entityId)` | An entity leaves a zone; `reason` is `"left"` or `"gone"` |
| `doorUnlockRequest` | `(player, door)` | A player tries to open a lock the server holds shut, by key or Alohomora |
| `lootableTaken` | `(player, lootableId, items)` | A player takes a server lootable; `items` is what it gave them |
| `housePointsChange` | `(house, points, previous)` | A house's points change |
| `housePointsRequest` | `(player, request)` | A player's game asks to change house points; return `false` synchronously to refuse it |
| `sanctuaryChanged` | `(id, revision, editor)` | An editor changes a [Room of Requirement](/guides/room-of-requirement/rooms/) room |
| `playerSanctuaryEnter` | `(player, id)` | A player enters a room |
| `playerSanctuaryLeave` | `(player, id)` | A player leaves a room |
| `pvpHit` | `(casterId, victimId, spell, damage)` | A PvP hit has passed server arbitration and policy and was relayed to its victim; `damage` is the final amount |
| `pvpDefeat` | `(victim, killer, kind)` | A player defeats another in [PvP](/guides/pvp/hits-and-defeat/#defeat); `kind` is `"death"` or `"kneel"` |
| `pvpRulesChanged` | `(rules)` | The PvP rules change |
| `pvpFlagChanged` | `(player, on)` | A player's PvP flag changes |
| `wandLinkEnded` | `(link, winner, reason)` | A [wand link](/guides/pvp/duels-and-wand-links/#wand-links) ends |
| `entityStateChange` | `(entity, key, value, previous)` | A script writes or removes one key of an entity's state or of `World.state`; `value` is `undefined` for a removal |

Some native server events originate in the connected player's game. The reserved `playerDied`, `playerDowned`, and `playerDownedEnd` messages use a dedicated native RPC and cannot be forged through `Events.emitServer`, but they are still client-authored observations. Location context, native inventory reports, request completions, and `npcDamaged` also cross the client/server boundary. Apply server-side validation appropriate to the consequences of the handler. In particular, adopt a `playerInventoryNativeDelta` with `player.inventory.adoptNative()` only under an explicit allowlist. `playerAppearanceChanged` is emitted after the server accepts and sanitizes an appearance, while `pvpHit` is a post-policy informational event; use `Pvp.setPolicy` to veto or reprice PvP hits.
Expand Down Expand Up @@ -199,11 +226,18 @@ These events are delivered only inside the client runtime. Receiving a native cl
| `chatMessage` | `({ author, text, color })` | A chat message arrives from the server |
| `chatSend` | `(text)` | The local player submits text through the chat overlay |
| `spellCast` | `(spellPath)` | The local player casts a spell; the path identifies its spell record |
| `spellProbe` | `(label)` | The native spell hook produces a diagnostic line |
| `playerRegionChanged` | `(region)` | The local player enters a named region |
| `creatorOpened` | `()` | The character creator opens |
| `creatorOpened` | `({})` | The character creator opens |
| `creatorConfirmed` | `({ first, last })` | The character creator closes after confirmation |
| `creatorCancelled` | `()` | The character creator closes without confirmation |
| `creatorCancelled` | `({})` | The character creator closes without confirmation |
| `creatorChanged` | `(state)` | A creator session's selections change |
| `abilityStatus` | `(handle)` | An ability the local player plays starts or settles |
| `spellAssignment` | `({ source, loadout, slot })` | A spell is assigned to a slot, from the game's menu or a script |
| `spellLearningFinished` | `(result)` | A spell lesson the resource started finishes; it grants no spell |
| `minimapChanged` | `(state, previous)` | The [minimap](/guides/user-interface/map-markers/#the-minimap) switches map, floor or tile |
| `pvpRelationChanged` | `(relation)` | The local player's [PvP relation](/guides/pvp/rules-and-relations/) to another player is resolved or changes |
| `localDowned` | `()` | The local player kneels after a PvP defeat |
| `localDownedEnd` | `({ wasDead })` | The local player gets up, from a kneel or a respawn |
| `entityStateChange` | `(entity, key, value, previous)` | A replicated state write or removal arrives on the client; `value` is `undefined` for a removal |

A `chatSend` handler may synchronously return `false` to prevent that line from being sent. An asynchronous return value cannot veto it.
Expand All @@ -225,8 +259,6 @@ Call `CombatEvents.arm()` before subscribing to the combat observations below. A
| `spellHit` | `(spellType, spellPath, victimClass, victimNpcId, victimIsLocal, casterClass, casterIsLocal)` | A watched spell hits an actor |
| `spellHitPlayer` | `(victimId, spellId, spellPath, damage)` | The local player's native spell impact hits another player's proxy |
| `damageReceived` | `(damage, targetClass, targetNpcId, targetIsLocal, instigatorClass, instigatorIsLocal)` | A watched actor receives damage |
| `protegoBlocked` | `(spellPath, targetClass, targetIsLocal)` | Protego blocks a spell |
| `attackDeflected` | `(deflectorIsLocal)` | Protego deflects an attack |
| `gameEvent` | `(functionName, objectClass)` | Another explicitly watched native function fires |

```js
Expand All @@ -237,7 +269,7 @@ if (CombatEvents.arm()) {
}
```

`spellHitPlayer` is informational. The native client relays the impact separately for server arbitration; server resources can observe the resulting final hit through `pvpHit`. It does not currently have a typed `ClientEvents.on` overload in the public declarations.
`spellHitPlayer` is informational. The native client relays the impact separately for server arbitration; server resources can observe the resulting final hit through `pvpHit`.

`gameEvent` is not an unrestricted stream of every Unreal Engine event. It only reports functions installed by the available typed or feature-specific watchers.

Expand All @@ -250,7 +282,7 @@ The native brewing and herbology hooks currently expose two additional events us
| `brewingInput` | `(payloadJson)` | `{ action, siteUid, stationUid, potionId, yield }`; `action` is `begin`, `collect`, or `destroy` |
| `herbInput` | `(payloadJson)` | `{ action, plotUid, plantId, fertilizerId, state }`; `action` is `plant`, `fertilize`, `harvest`, or `destroy` |

These two names are native implementation events but do not yet have typed `ClientEvents.on` overloads in the public declarations.
`breakableState` fires with an object's id, `"broken"` or `"repaired"`, and its class when the local player breaks or repairs a repairable object, once `Breakables.arm()` has been called.

#### Web-view events

Expand Down
2 changes: 1 addition & 1 deletion guides/Core concepts/state-bags.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: State bags
description: Attach your own keys and values to players and other entities, choose which clients receive each key, and react when one changes.
sidebar:
order: 22
order: 220
---

Every replicated entity carries a state bag, `entity.state`: a small key/value store that the server writes and that travels with the entity to the clients that can see it. Players, NPCs, beasts, world objects, effects and characters all have one, and `World.state` is a bag for state that belongs to no entity.
Expand Down
4 changes: 2 additions & 2 deletions guides/Core concepts/virtual-worlds.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Virtual worlds
description: Split players and entities into separate copies of the world, how a player's world combines with the map they are in, and what ignores worlds.
sidebar:
order: 23
order: 230
---

A virtual world is a number that partitions replication. A player sees the players and entities in their own world and nothing in any other, so several groups can share the same place without meeting: a duel arena, a private event or a tutorial. Players in different worlds do not hear each other on voice chat either.
Expand Down Expand Up @@ -35,7 +35,7 @@ The value reads back at once and takes effect on the next server tick. A player'

The world you set is combined with the map the player is in. In Overland, the game's main map, world N is world N. Every other map, such as a dungeon, has worlds of its own: players there share a world with the others in the same map who have the same world number, and never meet anyone in another map.

During a loading screen between maps, each player is alone in a world of their own.
During a loading screen between maps, each player is alone in a world of their own. In the Room of Requirement, each room is a world of its own, combined with the world number: see [Who sees whom](/guides/room-of-requirement/doors-and-visits/#who-sees-whom).

`player.virtualWorld` returns the number you set, not this combined world.

Expand Down
Loading
Loading