Events
React to what happens in the game, and send messages between resources, the server and players' games. Handlers from Events.on run in the order added. Where an event says "Return false to refuse", one handler returning false is enough to refuse the action.
events.broadcast()
Events.broadcast(...args)Sends an event to all connected players' games. Client handlers from Events.on get the payload parsed from JSON, up to 32 KB. A string that is JSON text is sent as is, and any other string arrives as that string.
events.emit()
Events.emit(name, ...args)Raises an event for all resources on this side, the server or this player's game. The promise settles once all handlers have run, and rejects with an AggregateError if any threw.
events.fire()
Events.fire(...args)Raises a private event, heard only by this resource's listen handlers.
events.fromClient()
Events.fromClient(name, fn)Listens to an event sent by a player's game with Events.toServer. The handler gets the sender and the payload parsed from JSON. A changed client can send anything, so check the payload.
events.listen()
Events.listen(name, fn)Listens to an event this resource raises with fire. Other resources can neither hear nor raise it.
events.listenerCount()
Events.listenerCount(...args)How many handlers this side has for an event.
events.off()
Events.off(name, fn)Removes a handler added with on or once.
events.offFromClient()
Events.offFromClient(name, fn)Removes a handler added with fromClient or onceFromClient.
events.on()
Events.on(name, fn)Runs the handler each time the event happens, for the game's events and your own from Events.emit alike.
events.once()
Events.once(name, fn)Runs the handler the next time the event happens, then removes it.
events.onceFromClient()
Events.onceFromClient(name, fn)As fromClient, for the next arrival only.
events.toResource()
Events.toResource(...args)Raises an event for one resource only, by its name. Other resources do not hear it.
events.toServer()
Events.toServer(...args)Sends an event from this player's game to the server, where Events.fromClient handlers get it with the sender. The payload goes as JSON, up to 32 KB. A string that is JSON text is sent as is, and any other string arrives as that string.
events.on('actionHintsChanged')
on(event: "actionHintsChanged", cb: () => void): voidClient only. The HUD's hints changed: one appeared or went, its text changed, it was greyed out, or a hold ring moved. ActionHint.shown() reads the new set.
events.on('areaEnter')
on(event: "areaEnter", cb: (area, entity, matchingDimension) => void): voidA player, horse or NPC entered an area, by its shape, in any dimension. The area is the level's, such as a house, interior, private ground or settlement, or a resource's. It also fires when an area is created, moved or enabled around a body.
events.on('areaExit')
on(event: "areaExit", cb: (area, entity, matchingDimension) => void): voidA player, horse or NPC left an area, or the area was destroyed or disabled around it, or the server's map changed.
events.on('bookClosed')
on(event: "bookClosed", cb: (id, reason) => void): voidA book closed.
events.on('bookOpened')
on(event: "bookOpened", cb: (id) => void): voidA Book opened in this player's game.
events.on('bookTextChanged')
on(event: "bookTextChanged", cb: (id, text, reason) => void): voidThe text in an open book changed.
events.on('bookWritingEnded')
on(event: "bookWritingEnded", cb: (id, text) => void): voidThe player stopped writing in a book.
events.on('cameraShotEnded')
on(event: "cameraShotEnded", cb: (player, reason) => void): voidA Camera.startShot ended by itself. The server's handler gets (player, reason), and the player's game gets (reason).
events.on('cartDestroy')
on(event: "cartDestroy", cb: (cart) => void): voidA cart is being removed, with everyone on it let off first.
events.on('cartEnter')
on(event: "cartEnter", cb: (cart, player, seat) => void): voidA player took a seat on a cart.
events.on('cartEntering')
on(event: "cartEntering", cb: (cart, player, seat) => void): voidA player is about to take a seat on a cart. Return false to refuse.
events.on('cartExit')
on(event: "cartExit", cb: (cart, player, seat) => void): voidA player left a cart's seat.
events.on('cartSpawn')
on(event: "cartSpawn", cb: (cart) => void): voidA cart or wagon was spawned.
events.on('consoleCommand')
on(event: "consoleCommand", cb: (command, parts) => void): voidSomeone typed a command in the server console that the server does not handle itself.
events.on('craftingCompleted')
on(event: "craftingCompleted", cb: (player, details) => void): voidA craft gave its product.
events.on('craftingCompleting')
on(event: "craftingCompleting", cb: (player, proposal) => void): voidA craft is about to give its product. Return false to refuse, and the product is taken back.
events.on('craftingEnded')
on(event: "craftingEnded", cb: (player, details) => void): voidA crafting session ended: 'success', 'failed' or 'cancelled'.
events.on('craftingRecipeLearned')
on(event: "craftingRecipeLearned", cb: (player, details) => void): voidA player learned a custom recipe.
events.on('craftingRefunding')
on(event: "craftingRefunding", cb: (player, details, refund) => void): voidAn unfinished craft is settling. Call refund() to return all materials still held, and otherwise the game's rules apply.
events.on('craftingStarted')
on(event: "craftingStarted", cb: (player, details) => void): voidA player started an alchemy batch, a smithing workpiece or a custom recipe.
events.on('craftingStarting')
on(event: "craftingStarting", cb: (player, proposal) => void): voidA player is about to start crafting. Return false to refuse.
events.on('craftingStationUsed')
on(event: "craftingStationUsed", cb: (player, details) => void): voidA player used a Crafting station with more than one recipe, and your resource chooses what they craft.
events.on('dialogueClosed')
on(event: "dialogueClosed", cb: (session, player, reason) => void): voidA conversation ended.
events.on('dialogueChoice')
on(event: "dialogueChoice", cb: (session, player, option) => void): voidA player chose an option in a conversation from Dialogue.open.
events.on('diceBadge')
on(event: "diceBadge", cb: (event) => void): voidA badge took effect on a throw.
events.on('diceMatchEnd')
on(event: "diceMatchEnd", cb: (match, first, second, winner, reason, firstScore, secondScore) => void): voidA dice match ended.
events.on('diceMatchStart')
on(event: "diceMatchStart", cb: (match, first, second, target) => void): voidA dice match began.
events.on('diceMove')
on(event: "diceMove", cb: (event) => void): voidA player held dice and continued or passed.
events.on('diceRoll')
on(event: "diceRoll", cb: (event) => void): voidDice were thrown.
events.on('diceTableUse')
on(event: "diceTableUse", cb: (player, table, match) => void): voidA player used a dice table.
events.on('diceTurnEnd')
on(event: "diceTurnEnd", cb: (event) => void): voidA turn ended.
events.on('diceTurnStart')
on(event: "diceTurnStart", cb: (event) => void): voidA player's turn began.
events.on('dogDestroy')
on(event: "dogDestroy", cb: (dog) => void): voidA dog is being removed.
events.on('dogModeChanged')
on(event: "dogModeChanged", cb: (dog, mode) => void): voidA dog's mode changed.
events.on('dogOwnerChanged')
on(event: "dogOwnerChanged", cb: (dog, owner) => void): voidA dog got a new owner, or none.
events.on('dogSpawn')
on(event: "dogSpawn", cb: (dog) => void): voidA dog was spawned.
events.on('doorInteract')
on(event: "doorInteract", cb: (player, door, action, keySide) => void): voidA player is about to open, close, unlock or lockpick a door. Return false to refuse.
events.on('entityStateChange')
on(event: "entityStateChange", cb: (entity, key, value, previous) => void): voidA value in an entity's shared state changed.
events.on('followStarted')
on(event: "followStarted", cb: (target) => void): voidClient only. The local player's scripted follow started.
events.on('followStopped')
on(event: "followStopped", cb: (target, reason) => void): voidClient only. The local player's follow ended.
events.on('gameResolutionChanged')
on(event: "gameResolutionChanged", cb: (width, height) => void): voidClient only. The game's frame changed size, because the player switched between window and full screen or changed resolution. It fires once per change, and not for the first size.
events.on('gateBarChanged')
on(event: "gateBarChanged", cb: (gate, barred) => void): voidA gate's bar was put in or taken out.
events.on('gateChanged')
on(event: "gateChanged", cb: (gate, state) => void): voidA gate moved to another state.
events.on('gatheringHarvest')
on(event: "gatheringHarvest", cb: (player, proposal) => void): voidA player picked a plant and is about to get it. Return false to refuse.
events.on('gatheringHarvested')
on(event: "gatheringHarvested", cb: (player, details) => void): voidA player got what they picked.
events.on('graveDug')
on(event: "graveDug", cb: (player, grave) => void): voidA player dug out a grave with the game's digging. All games show it open from now on.
events.on('groundItemDestroy')
on(event: "groundItemDestroy", cb: (stack) => void): voidA ground item is being removed.
events.on('groundItemPickup')
on(event: "groundItemPickup", cb: (stack, player) => void): voidA player picked up a ground item.
events.on('groundItemResting')
on(event: "groundItemResting", cb: (stack) => void): voidA ground item came to rest where physics laid it. Its position and rotation are that spot on all clients, and `resting` is true. It fires once per stack, and not for a landed arrow or bolt, which rests from the start.
events.on('groundItemSpawn')
on(event: "groundItemSpawn", cb: (stack) => void): voidA stack of items appeared on the ground.
events.on('horseDamage')
on(event: "horseDamage", cb: (horse, attacker, amount, reason) => void): voidA horse lost health.
events.on('horseDeath')
on(event: "horseDeath", cb: (horse, killer, reason) => void): voidA horse died, and only revive() brings it back.
events.on('horseDestroy')
on(event: "horseDestroy", cb: (horse) => void): voidA horse is being removed.
events.on('horseDismount')
on(event: "horseDismount", cb: (horse, player) => void): voidA rider left a horse's saddle, for any reason.
events.on('horseGearChanged')
on(event: "horseGearChanged", cb: (horse, player, gear) => void): voidA horse's tack changed on all clients.
events.on('horseGearChanging')
on(event: "horseGearChanging", cb: (horse, player, gear) => void): voidA horse's owner changed its tack on the inventory screen's Horse tab, before the server takes it. Return false to refuse, so the horse keeps its gear on all clients and no item moves. It does not fire while the horse's gearFixed is set, which refuses first, or for a script's setTack, fitGear or takeOffGear.
events.on('horseIntentDone')
on(event: "horseIntentDone", cb: (horse, status) => void): voidA horse finished a moveTo or patrol order.
events.on('horseKnockedOut')
on(event: "horseKnockedOut", cb: (horse, attacker, reason) => void): voidA horse was knocked out, by a lethal blow when spawned with knockOut, or by knockDown(). Nobody can ride it until wake().
events.on('horseMount')
on(event: "horseMount", cb: (horse, player) => void): voidA player sat in a horse's saddle, by themselves or through player.mount.
events.on('horseMounting')
on(event: "horseMounting", cb: (horse, player) => void): voidA player mounts a horse, before the server accepts it. Handlers run synchronously, and returning false has their client dismount them, with no horseMount or horseDismount.
events.on('horseOwnerChanged')
on(event: "horseOwnerChanged", cb: (horse, owner) => void): voidA horse got a new owner, or none.
events.on('horseRevive')
on(event: "horseRevive", cb: (horse) => void): voidA dead horse was revived.
events.on('horseSpawn')
on(event: "horseSpawn", cb: (horse) => void): voidA horse was spawned.
events.on('horseWake')
on(event: "horseWake", cb: (horse) => void): voidA knocked-out horse got up.
events.on('characterCreatorClosed')
on(event: "characterCreatorClosed", cb: (appearance, reason) => void): voidThe character creator closed.
events.on('chatMessage')
on(event: "chatMessage", cb: (message) => void): voidA chat message arrived in this player's game.
events.on('loadingProgress')
on(event: "loadingProgress", cb: (stage, percent) => void): voidClient only. How far the game has loaded, for a server's loading page: stage 'resources', 'level' or 'ready', with a percentage. See LoadingScreen. Scripts do not run yet during 'download', which only the page hears.
events.on('locationDiscovered')
on(event: "locationDiscovered", cb: (locationId) => void): voidThe player discovered a map location, such as a town or district. It happens only on a server with revealMap off, since otherwise the whole map starts discovered. Keep the GUID with the character, and mark it again after the next load. Handler promises are not awaited.
events.on('mapClosed')
on(event: "mapClosed", cb: () => void): voidThe local player closed the map.
events.on('mapOpened')
on(event: "mapOpened", cb: () => void): voidThe local player opened the map.
events.on('mapWaypointCleared')
on(event: "mapWaypointCleared", cb: (position, mapId) => void): voidThe local player removed their waypoint.
events.on('mapWaypointSet')
on(event: "mapWaypointSet", cb: (position, mapId, moved) => void): voidThe local player set or moved their map waypoint.
events.on('markerEnter')
on(event: "markerEnter", cb: (marker, player) => void): voidA player walked into a trigger marker.
events.on('markerExit')
on(event: "markerExit", cb: (marker, player) => void): voidA player left a trigger marker.
events.on('markerPlace')
on(event: "markerPlace", cb: (marker) => void): voidA marker was placed.
events.on('markerRemove')
on(event: "markerRemove", cb: (marker) => void): voidA marker is being removed.
events.on('monologueSuppressed')
on(event: "monologueSuppressed", cb: (text, textKey) => void): voidKCDS silenced one of the local character's remarks, which the game voices as Henry whoever plays. Hud.setInnerVoice(true) lets them speak. The line is chosen from the remark's pool, as the game would.
events.on('noclipAllowedChanged')
on(event: "noclipAllowedChanged", cb: (allowed) => void): voidThe server allowed or forbade NoClip for the local player, through Player.noclipAllowed. A running flight has by then ended with noclipChanged(false, 'notAllowed').
events.on('noclipChanged')
on(event: "noclipChanged", cb: (enabled, reason) => void): voidNoClip went on or off for the local player.
events.on('npcAnimationEnd')
on(event: "npcAnimationEnd", cb: (npc, fragment, reason) => void): voidAn animation from npc.playAnimation ended, firing once per request. A looping one ends only by 'refused', 'stopped' or 'replaced'.
events.on('npcDamage')
on(event: "npcDamage", cb: (npc, attacker, amount, bodyPart, reason) => void): voidAn NPC lost health.
events.on('npcDeath')
on(event: "npcDeath", cb: (npc, killer) => void): voidAn NPC died.
events.on('npcDestroy')
on(event: "npcDestroy", cb: (npc) => void): voidAn NPC is being removed.
events.on('npcIntentDone')
on(event: "npcIntentDone", cb: (npc, status) => void): voidAn NPC finished a moveTo, a follow or a patrol leg.
events.on('npcInteract')
on(event: "npcInteract", cb: (npc, player) => void): voidA player pressed the use key looking at an NPC with `interactable` on, within 3.5 m of their view. The server also checks that they stand near it.
events.on('npcInventoryChanged')
on(event: "npcInventoryChanged", cb: (npc, change) => void): voidA spawned NPC's stock changed.
events.on('npcLoot')
on(event: "npcLoot", cb: (player, npc, line) => void): voidA player is about to take an item from a dead NPC. Return false to refuse.
events.on('npcLooted')
on(event: "npcLooted", cb: (player, npc, items) => void): voidA player took items from a dead NPC.
events.on('npcRevive')
on(event: "npcRevive", cb: (npc) => void): voidA dead NPC was revived.
events.on('npcSimulatorChange')
on(event: "npcSimulatorChange", cb: (npc, simulator, previous) => void): voidAnother player's game now simulates the NPC, moving it and running its fights.
events.on('npcSpawn')
on(event: "npcSpawn", cb: (npc) => void): voidAn NPC was spawned.
events.on('npcHarvest')
on(event: "npcHarvest", cb: (player, npc) => void): voidA player finished butchering a carcass and is about to get its harvest. Return false to refuse, or { items: [{ item, amount }] }, up to 16 rows, to replace the harvest table's yield this time. A wrong yield is logged and the table's is given.
events.on('npcHarvested')
on(event: "npcHarvested", cb: (npc, player) => void): voidA player got a carcass's harvest.
events.on('patrolFinished')
on(event: "patrolFinished", cb: (npc, patrol) => void): voidAn NPC's patrol ended: done, cancelled or given up.
events.on('patrolWaypoint')
on(event: "patrolWaypoint", cb: (npc, patrol) => void): voidAn NPC on patrol reached a waypoint, or a leg failed.
events.on('playerAnimationEnd')
on(event: "playerAnimationEnd", cb: (player, fragment, reason) => void): voidAn animation from player.playAnimation ended, firing once per request.
events.on('playerAttack')
on(event: "playerAttack", cb: (player, opponent) => void): voidThe server accepted a player's melee swing at another player.
events.on('playerBuffAdded')
on(event: "playerBuffAdded", cb: (player, buff, source) => void): voidA status effect landed on a player.
events.on('playerBuffBlocked')
on(event: "playerBuffBlocked", cb: (player, buff) => void): voidThe server's rules stopped the game putting a status effect on a player.
events.on('playerBuffRemoved')
on(event: "playerBuffRemoved", cb: (player, buff, reason) => void): voidA status effect left a player.
events.on('playerCarry')
on(event: "playerCarry", cb: (carrier, carried) => void): voidA player lifted a knocked-out player onto their shoulder.
events.on('playerCarrying')
on(event: "playerCarrying", cb: (carrier, carried) => void): voidA player is about to lift a knocked-out player onto their shoulder. Return false to refuse.
events.on('playerCarryingItem')
on(event: "playerCarryingItem", cb: (player, item, stack) => void): voidA player is about to pick up a carryable item from the ground in their arms. Return false to refuse.
events.on('playerCarryItem')
on(event: "playerCarryItem", cb: (player, item, stack) => void): voidA player now carries an item in their arms.
events.on('playerCombatCancelled')
on(event: "playerCombatCancelled", cb: (player, opponent) => void): voidplayer.stopFight ended melee combat between two players.
events.on('playerCommand')
on(event: "playerCommand", cb: (player, command, parts) => void): voidA player typed a message starting with /. You get the command without the slash, and the rest split at spaces. Commands never go to other players.
events.on('playerConnect')
on(event: "playerConnect", cb: (player) => void): voidA player joined. Their body and inventory exist while they are still loading, which makes this the place to restore a saved inventory.
events.on('playerConnecting')
on(event: "playerConnecting", cb: (request) => void): voidSomeone asks to join, before their connection exists. They get in once all handlers have returned and all returned promises have settled, and a handler that throws or rejects turns them away. `request.reject(reason)` turns them away at once, with up to 512 bytes of text. `request.update(message)` shows up to 256 bytes on their waiting screen and restarts the wait. `nickname`, `steamId`, `epicId`, `store`, `storeAccount`, `discordId`, `deviceId` and `ip` say who it is, as on a player, with `identifiers` listing them as { kind, id, verified } and `getIdentifier(kind)` giving one, or ''. `ticket` is the KCDS Master's join pass, already checked, and a backend can check it again with the Master's public key. `isPending()` says whether it still waits. A player on the KCDS central ban list gets no pass and so never gets this far, nor does one without the server's password, KCDS_SERVER_PASSWORD.
events.on('playerConsumed')
on(event: "playerConsumed", cb: (player, consumed) => void): voidA player ate or drank something.
events.on('playerConsuming')
on(event: "playerConsuming", cb: (player, consumption) => void): voidA player is about to eat or drink. Return false to refuse.
events.on('playerConsumptionEffects')
on(event: "playerConsumptionEffects", cb: (player, consumption) => void): voidFollows playerConsuming. Return false to stop the game's effects of the food or drink, so your script can apply its own. The item is still used up.
events.on('playerCuffedChange')
on(event: "playerCuffedChange", cb: (player, cuffed) => void): voidplayer.setCuffed cuffed or uncuffed a player.
events.on('playerCustomBuffApply')
on(event: "playerCustomBuffApply", cb: (player, buff) => void): voidAn instance of a Buffs.register buff landed on a player, firing for each stack.
events.on('playerCustomBuffRemove')
on(event: "playerCustomBuffRemove", cb: (player, buff, reason) => void): voidAn instance of a Buffs.register buff left a player, whose modifiers no longer apply.
events.on('playerCustomBuffTick')
on(event: "playerCustomBuffTick", cb: (player, buff) => void): voidA tick of a Buffs.register buff with a tickInterval, once per instance and interval.
events.on('playerCustomItemUse')
on(event: "playerCustomItemUse", cb: (player, item, revision) => void): voidA player used a custom item your resource made usable with Items.
events.on('playerDamage')
on(event: "playerDamage", cb: (player, attacker, amount, bodyPart, reason) => void): voidA player's game took health off them.
events.on('playerDied')
on(event: "playerDied", cb: (player, killer, reason) => void): voidA player was knocked out, and stays down until player.revive().
events.on('playerDisconnect')
on(event: "playerDisconnect", cb: (player) => void): voidA player left. The object still has its last values here, so save what you need.
events.on('playerHit')
on(event: "playerHit", cb: (player, attacker, hit) => void): voidAnother player's blow, arrow, bolt or ball is about to take a player's health. Set hit.damage for the health it takes, or hit.modifiers (attack, defense, block, health, where 1 changes nothing) to have the game work out the blow again. Return false to refuse. A hit on or by a player in a dice match, or at a smithy, alchemy table or grindstone, is refused before this event.
events.on('playerChat')
on(event: "playerChat", cb: (player, text) => void): voidA player sent a chat message that is not a command. By default it has already gone to everyone. To handle chat yourself, use Chat.setChatRelay(false).
events.on('playerInjured')
on(event: "playerInjured", cb: (player, limb) => void): voidA player's limb was injured.
events.on('playerInjuryHealed')
on(event: "playerInjuryHealed", cb: (player, limb) => void): voidA player's limb injury healed.
events.on('playerInventoryChanged')
on(event: "playerInventoryChanged", cb: (player, change) => void): voidRows in a player's inventory were added, removed, moved or changed.
events.on('playerInventoryReady')
on(event: "playerInventoryReady", cb: (player) => void): voidA player's game shows the inventory the server holds for them. It fires once.
events.on('playerItemUsed')
on(event: "playerItemUsed", cb: (player, item, kind, amount) => void): voidA player used up units of an item. For eating and drinking, see playerConsumed.
events.on('playerLevelUp')
on(event: "playerLevelUp", cb: (player, track, level, perkPoints) => void): voidA player reached a new level on a skill track.
events.on('playerLoot')
on(event: "playerLoot", cb: (player, victim, line) => void): voidA player is about to take an item from a knocked-out player's body. Return false to refuse.
events.on('playerLooted')
on(event: "playerLooted", cb: (player, victim, items) => void): voidA player took items from a knocked-out player's body.
events.on('playerPerkAdded')
on(event: "playerPerkAdded", cb: (player, perk, source) => void): voidA player got a perk.
events.on('playerPerkLearning')
on(event: "playerPerkLearning", cb: (player, perk) => void): voidA player chooses a perk. Return false to cancel the choice.
events.on('playerPerkRemoved')
on(event: "playerPerkRemoved", cb: (player, perk, source) => void): voidA player lost a perk.
events.on('playerPickpocketCaught')
on(event: "playerPickpocketCaught", cb: (thief, victim) => void): voidA victim caught their pickpocket.
events.on('playerPickpocketed')
on(event: "playerPickpocketed", cb: (thief, victim, items) => void): voidA pickpocketing ended, with the items taken.
events.on('playerPickpocketStart')
on(event: "playerPickpocketStart", cb: (thief, victim) => void): voidA player tries to pickpocket another. Return false to refuse.
events.on('playerPilloryReleased')
on(event: "playerPilloryReleased", cb: (player, reason) => void): voidA player left the pillory.
events.on('playerPoisonAbsorbing')
on(event: "playerPoisonAbsorbing", cb: (player, consumption, poison) => void): voidA player consumed something poisoned and is about to get the poison. Return false to keep it off them.
events.on('playerPrepared')
on(event: "playerPrepared", cb: (player, preparation) => void): voidA preparation playerPreparing allowed is over. It fires once the inventory has been still for a few seconds after the last conversion, and not if nothing converted.
events.on('playerPreparing')
on(event: "playerPreparing", cb: (player, preparing) => void): voidA player's game is about to cook, smoke or dry food at a fire, smokehouse or rack. Return false to refuse, so nothing starts and nothing is taken. The game still plays the player's animation and tells them nothing, so show a message of your own.
events.on('playerProgressionRejected')
on(event: "playerProgressionRejected", cb: (player, reason) => void): voidA player's game reported XP or perks the server did not grant. What happens to the player is up to your resources.
events.on('playerPutDown')
on(event: "playerPutDown", cb: (carrier, carried) => void): voidA carried player was put down.
events.on('playerPutDownItem')
on(event: "playerPutDownItem", cb: (player, item, stack) => void): voidA player stopped carrying an item and set it down.
events.on('playerQueued')
on(event: "playerQueued", cb: (view) => void): voidA player joined a full server's queue.
events.on('playerReady')
on(event: "playerReady", cb: (player) => void): voidTheir game has taken down its loading screen, so they can see and play. It fires once per connection, on the server and in the player's own game.
events.on('playerResourcesReady')
on(event: "playerResourcesReady", cb: (player) => void): voidServer only. Their game has downloaded and started the client resources, so events from player.emit and Events.broadcast now reach their client scripts. On a first join, playerReady can come first. It fires again when client resources load anew, and when their game restarts client scripts that stopped by themselves, which it does up to 5 times a session. Those scripts then hold nothing, so send what they need again.
events.on('playerSpawned')
on(event: "playerSpawned", cb: (player) => void): voidThe player stands in the loaded world.
events.on('playerSpawning')
on(event: "playerSpawning", cb: (player) => void): voidTheir game has loaded and needs a starting place. Give it here with player.spawn(position, rotation).
events.on('playerStatsChanged')
on(event: "playerStatsChanged", cb: (player, changes) => void): voidStats in a player's report changed, with one event for all changes of a server tick.
events.on('playerTreeFell')
on(event: "playerTreeFell", cb: (player, tree, fall) => void): voidA player's last blow fells a tree. You can change `fall.direction`, which is horizontal and away from the chopper by default, and `fall.seconds`. Return false to keep it standing, and the next blow tries again.
events.on('playerTreeChop')
on(event: "playerTreeChop", cb: (player, tree, blow) => void): voidA player's axe blow on a standing tree counts: axe in hand, within reach, one per swing. Return false to refuse. See Trees.
events.on('playerTrunkCut')
on(event: "playerTrunkCut", cb: (player, tree, items) => void): voidA player's last blow cuts a felled trunk into items, and you can change `items` in place. Return false to refuse, and the next blow tries again. The items go to the inventory or the ground, by Trees.configure's dropTo, and the trunk disappears.
events.on('playerTrunkChop')
on(event: "playerTrunkChop", cb: (player, tree, blow) => void): voidA player's axe blow on a felled trunk counts. Return false to refuse.
events.on('playerUnqueued')
on(event: "playerUnqueued", cb: (view, value) => void): voidA player left the queue.
events.on('playerWeaponHit')
on(event: "playerWeaponHit", cb: (player, hit) => void): voidA swing struck the world and not a character, such as a tree, wall, rock, prop or the ground. It fires once per object per attack, on first contact, from the attacker's client report. The server accepts a report up to 8 m from the player's known position, and up to 16 per second per player. Unarmed attacks never fire it, and hits on players, NPCs and animals are for playerHit and the damage events.
events.on('playerWhistle')
on(event: "playerWhistle", cb: (player) => void): voidA player whistled for their horse, and nearby players hear it.
events.on('playerXpGained')
on(event: "playerXpGained", cb: (player, track, xp) => void): voidA player gained XP on a skill track.
events.on('playerXpGaining')
on(event: "playerXpGaining", cb: (player, track, xp, source) => void): voidA player's game is about to grant XP. Return false to refuse.
events.on('poiDiscovered')
on(event: "poiDiscovered", cb: (poiId) => void): voidThe player discovered a point of interest on the map, on a server with revealMap off. Handler promises are not awaited.
events.on('progressionLevelUp')
on(event: "progressionLevelUp", cb: (track, level, perkPoints) => void): voidThe local player reached a new level.
events.on('progressionPerkAdded')
on(event: "progressionPerkAdded", cb: (perk) => void): voidThe local player got a perk.
events.on('progressionPerkRefused')
on(event: "progressionPerkRefused", cb: (perk, reason) => void): voidThe server refused a perk the local player chose.
events.on('progressionPerkRemoved')
on(event: "progressionPerkRemoved", cb: (perk) => void): voidThe local player lost a perk.
events.on('progressionXpGained')
on(event: "progressionXpGained", cb: (track, xp) => void): voidThe local player gained XP.
events.on('propDestroy')
on(event: "propDestroy", cb: (prop) => void): voidA prop is being removed.
events.on('propHit')
on(event: "propHit", cb: (prop, speed, position) => void): voidA rigid prop's body struck something, such as the ground, a wall or another body. The simulating game saw it, moving at 2 m/s or more, slow down with its velocity changing by 2 m/s or more between frames, which gravity alone cannot do. There is at most one hit per prop every 0.3 s, and propRest still follows once it stops.
events.on('propPickedUp')
on(event: "propPickedUp", cb: (player, prop) => void): voidAn animation's pickup took a playAnimation prop with fromAnimation into the hand.
events.on('propPlaceCancel')
on(event: "propPlaceCancel", cb: (player, session) => void): voidA player cancelled a placement.
events.on('propPlaceConfirm')
on(event: "propPlaceConfirm", cb: (player, session, placement) => void): voidA player confirmed a placement. Return false to refuse, and propPlaceRejected follows.
events.on('propPlaced')
on(event: "propPlaced", cb: (player, prop) => void): voidAn animation put down a playAnimation prop with fromAnimation.
events.on('propPlaceEnd')
on(event: "propPlaceEnd", cb: (player, session) => void): voidA placement session ended.
events.on('propPlaceMove')
on(event: "propPlaceMove", cb: (player, session, placement, valid) => void): voidA player moved a PropPlacer preview, if the placer reports moves.
events.on('propPlaceRejected')
on(event: "propPlaceRejected", cb: (player, session, placement) => void): voidA placement was refused.
events.on('propRest')
on(event: "propRest", cb: (prop, position, rotation) => void): voidA rigid prop came to rest, whatever moved it: a script call such as applyImpulse, setVelocity, wake or sleep, a fall, or a player. The position comes from the client simulating it, the nearest player's at any distance, and other players already see it there. A position over 100 m from the previous resting or spawn point is refused, returning the prop there with no event. resetPhysics fires no event.
events.on('propSpawn')
on(event: "propSpawn", cb: (prop) => void): voidA prop was spawned.
events.on('questTrackingChanged')
on(event: "questTrackingChanged", cb: (quest, player, tracked) => void): voidA player started or stopped tracking a quest in their quest menu.
events.on('resourceStart')
on(event: "resourceStart", cb: (name) => void): voidA resource's scripts have run. Each side raises it for its own resources.
events.on('resourceStop')
on(event: "resourceStop", cb: (name) => void): voidA resource is stopping, and handlers have up to 10 seconds to finish.
events.on('siegeEngineDamage')
on(event: "siegeEngineDamage", cb: (engine, amount, attacker) => void): voidA siege engine took damage.
events.on('siegeEngineDestroy')
on(event: "siegeEngineDestroy", cb: (engine) => void): voidA siege engine is being removed.
events.on('siegeEngineReady')
on(event: "siegeEngineReady", cb: (engine) => void): voidA siege engine finished loading.
events.on('siegeEngineSpawn')
on(event: "siegeEngineSpawn", cb: (engine) => void): voidA siege engine was spawned.
events.on('siegeEngineUse')
on(event: "siegeEngineUse", cb: (player, engine, action) => void): voidA player is about to operate a siege engine. Return false to refuse.
events.on('siegeEngineWreck')
on(event: "siegeEngineWreck", cb: (engine, attacker) => void): voidA siege engine was wrecked.
events.on('siegeFire')
on(event: "siegeFire", cb: (engine, attacker, target) => void): voidA siege engine fired.
events.on('siegeImpact')
on(event: "siegeImpact", cb: (engine, position, attacker) => void): voidA siege engine's shot landed.
events.on('siegeLadderDestroy')
on(event: "siegeLadderDestroy", cb: (ladder) => void): voidA siege ladder is being removed.
events.on('siegeLadderFall')
on(event: "siegeLadderFall", cb: (ladder, pusher) => void): voidA ladder was pushed away and fell.
events.on('siegeLadderRaise')
on(event: "siegeLadderRaise", cb: (ladder) => void): voidA ladder was raised against a wall.
events.on('siegeLadderSpawn')
on(event: "siegeLadderSpawn", cb: (ladder) => void): voidA siege ladder was spawned.
events.on('siegeLadderUse')
on(event: "siegeLadderUse", cb: (player, ladder, action) => void): voidA player is about to push away or raise a ladder. Return false to refuse.
events.on('stashClose')
on(event: "stashClose", cb: (stash, player, reason) => void): voidA player closed a stash.
events.on('stashDestroy')
on(event: "stashDestroy", cb: (stash) => void): voidA stash is being removed.
events.on('stashInteract')
on(event: "stashInteract", cb: (player, stash, action) => void): voidA player is about to open a stash. Return false to refuse.
events.on('stashInventoryChanged')
on(event: "stashInventoryChanged", cb: (stash, player, change) => void): voidA script changed a stash's contents.
events.on('stashOpen')
on(event: "stashOpen", cb: (stash, player) => void): voidA player opened a stash.
events.on('stashSpawn')
on(event: "stashSpawn", cb: (stash) => void): voidA stash, meaning a chest, container or searchable body, was created.
events.on('stashUnlocked')
on(event: "stashUnlocked", cb: (stash, player, method) => void): voidA player unlocked a locked stash.
events.on('stoneImpact')
on(event: "stoneImpact", cb: (pile, position, player) => void): voidA thrown stone landed, hurting anyone near.
events.on('stonePileDestroy')
on(event: "stonePileDestroy", cb: (pile) => void): voidA stone pile is being removed.
events.on('stonePileSpawn')
on(event: "stonePileSpawn", cb: (pile) => void): voidA stone pile was spawned.
events.on('stonePileThrow')
on(event: "stonePileThrow", cb: (player, pile) => void): voidA player threw a stone from a pile.
events.on('storyCutsceneSuppressed')
on(event: "storyCutsceneSuppressed", cb: (cutscene) => void): voidClient only. KCDS stopped a quest's story cutscene playing on this machine. The player stays in control, the world clock runs on, and the quest continues as if it had played. Hud.setCutscenes(true) lets them play.
events.on('tradeClosed')
on(event: "tradeClosed", cb: (seller, player, reason) => void): voidA trade ended.
events.on('tradeDone')
on(event: "tradeDone", cb: (seller, buyer, boughtLines, soldLines, balance) => void): voidA basket went through, and both inventories changed.
events.on('tradeItem')
on(event: "tradeItem", cb: (seller, buyer, boughtLines, soldLines, balance) => void): voidThe buyer confirmed a basket. Return false to refuse.
events.on('tradeOpen')
on(event: "tradeOpen", cb: (seller, buyer) => void): voidA trade between two players is about to open. Return false to refuse.
events.on('treeFalling')
on(event: "treeFalling", cb: (tree, fall) => void): voidClient only. A tree in this dimension starts to fall, for `fall.seconds` along `fall.direction`, a good moment for a sound or dust. Handler promises are not awaited.
events.on('treeFelled')
on(event: "treeFelled", cb: (tree) => void): voidA felled trunk came to rest, and lies as a static prop to be cut. See Trees. It fires on the server and, for players of its dimension, in client scripts.
events.on('treeChop')
on(event: "treeChop", cb: (tree, blow) => void): voidClient only. Any player's counted axe blow on a standing tree in this dimension. Handler promises are not awaited.
events.on('treeRegrow')
on(event: "treeRegrow", cb: (tree) => void): voidA felled or cut tree is about to grow back, with its time up and nobody close. Return false to delay it by a minute.
events.on('treeRegrown')
on(event: "treeRegrown", cb: (tree) => void): voidA felled tree stands again as in the level. See Trees. It fires on the server and, for players of its dimension, in client scripts.
events.on('trunkCut')
on(event: "trunkCut", cb: (tree, items) => void): voidClient only. A felled trunk in this dimension was cut into items. Handler promises are not awaited.
events.on('tutorialHintClosed')
on(event: "tutorialHintClosed", cb: (id, reason) => void): voidA tutorial hint in the corner of the screen closed.
events.on('vendorClosed')
on(event: "vendorClosed", cb: (vendor, player, reason) => void): voidA shop screen closed. The server's handler gets (vendorId, player, reason), and the player's game gets (session, reason).
events.on('vendorOpened')
on(event: "vendorOpened", cb: (session, npc) => void): voidA server vendor's shop screen opened in this player's game.
events.on('vendorTrade')
on(event: "vendorTrade", cb: (vendorId, player, bought, sold, balance) => void): voidA player traded with a vendor.
events.on('vfxDestroy')
on(event: "vfxDestroy", cb: (vfx) => void): voidA visual effect is being removed.
events.on('vfxSpawn')
on(event: "vfxSpawn", cb: (vfx) => void): voidA visual effect was spawned.
events.on('weaponHit')
on(event: "weaponHit", cb: (hit) => void): voidThe local player's weapon struck the world and not a character, such as a tree, wall, rock, prop or the ground. It fires once per object per attack, on first contact, and not again while the blade stays against it. Unarmed attacks never fire it, and hits on players, NPCs and animals are for playerHit and the damage events. The server's event is playerWeaponHit. Handler promises are not awaited.
events.on('worldDayChange')
on(event: "worldDayChange", cb: (day) => void): voidThe world's clock reached a new day.
events.on('worldItemPickup')
on(event: "worldItemPickup", cb: (player, item) => void): voidA player is about to pick up an item the level placed. Return false to refuse.
events.on('worldResourcesReady')
on(event: "worldResourcesReady", cb: () => void): voidAll world resources, the level edits and their exports, have loaded.
events.on('worldWeatherChange')
on(event: "worldWeatherChange", cb: (preset, previous, seconds) => void): voidWorld.setWeather started changing the weather.