Documentation Index
Fetch the complete documentation index at: https://v5.rpgjs.dev/llms.txt
Use this file to discover all available pages before exploring further.
Server Player Hooks
Player hooks allow you to listen to player-specific events and customize player behavior on the server side. These hooks are defined in the player property of your server module.
Usage
import { RpgPlayer, RpgMap, RpgPlayerHooks, defineModule } from '@rpgjs/server'
const player: RpgPlayerHooks = {
onConnected(player: RpgPlayer) {
console.log(`Player ${player.id} connected`)
player.changeMap('spawn-map')
},
onStart(player: RpgPlayer) {
console.log(`Player ${player.id} started the game`)
},
onJoinMap(player: RpgPlayer, map: RpgMap) {
console.log(`Player ${player.id} joined map ${map.id}`)
}
}
export default defineModule({
player
})
Custom Properties
You can define custom properties that will be synchronized with the client and optionally saved to the database:
// First, extend the RpgPlayer interface
declare module '@rpgjs/server' {
export interface RpgPlayer {
gold: number
experience: number
secretData: string
}
}
const player: RpgPlayerHooks = {
props: {
gold: {
$default: 100,
$syncWithClient: true,
$permanent: true
},
experience: {
$default: 0,
$syncWithClient: true,
$permanent: true
},
secretData: {
$default: '',
$syncWithClient: false, // Not sent to client
$permanent: false // Not saved to database
}
}
}
Available Hooks
Initializing Default Stats
RPGJS can provide built-in default parameters for a player such as maxHp, maxSp,
str, int, dex, and agi.
Use player.initializeDefaultStats() when you want to:
- apply the built-in default parameter curves
- initialize HP/SP from those max values
- ensure the client receives visible HP/SP and parameter values on first game load
Typical usage:
- call it in
onConnected() if your game starts immediately
- call it in
onStart() if your game begins after a title screen or another GUI flow
If your player data comes from your own database, a save slot, or a snapshot, do not
call player.initializeDefaultStats() after hydration unless you intentionally want to
overwrite those values. In that case, restore your data first and let that state be
synchronized to the client.
If you only want the built-in parameter curves without restoring HP/SP, use
player.applyDefaultParameters().
onConnected
Description: Called when a player connects to the server
Parameters:
player: RpgPlayer - The player instance
Example:
const player: RpgPlayerHooks = {
onConnected(player: RpgPlayer) {
player.initializeDefaultStats()
console.log(`Welcome ${player.name}!`)
player.gold = 1000
player.changeMap('tutorial-map')
// Send welcome message
player.showText('Welcome to the game!')
}
}
onJoinMap
Description: Called when a player joins a map
Parameters:
player: RpgPlayer - The player instance
map: RpgMap - The map instance the player joined
Example:
const player: RpgPlayerHooks = {
onJoinMap(player: RpgPlayer, map: RpgMap) {
console.log(`${player.name} entered ${map.name}`)
// Set player position based on map spawn point
if (map.spawnPoint) {
player.teleport(map.spawnPoint.x, map.spawnPoint.y)
}
// Apply map-specific effects
if (map.id === 'dark-forest') {
player.addState('darkness')
}
}
}
onStart
Description: Called when the player starts the game from a GUI interaction
This hook is executed after a GUI interaction when the GUI returns a data.id equal to 'start'.
This is typically used after a title screen or another start menu.
Parameters:
player: RpgPlayer - The player instance
Example:
const player: RpgPlayerHooks = {
async onConnected(player: RpgPlayer) {
await player.gui('rpg-title-screen').open()
},
onStart(player: RpgPlayer) {
player.initializeDefaultStats()
player.changeMap('starting-map')
player.showText('The adventure begins!')
}
}
onLeaveMap
Description: Called when a player leaves a map
Parameters:
player: RpgPlayer - The player instance
map: RpgMap - The map instance the player left
Example:
const player: RpgPlayerHooks = {
onLeaveMap(player: RpgPlayer, map: RpgMap) {
console.log(`${player.name} left ${map.name}`)
// Remove map-specific effects
if (map.id === 'dark-forest') {
player.removeState('darkness')
}
// Save player progress
player.save()
}
}
Description: Called when a player presses a key on the client side
Parameters:
player: RpgPlayer - The player instance
data: { input: string, moving: boolean } - Input data
Example:
const player: RpgPlayerHooks = {
onInput(player: RpgPlayer, { input, moving }) {
if (input === 'action' && !moving) {
// Player pressed action key while standing still
const nearbyEvents = player.getEventsInRadius(32)
if (nearbyEvents.length > 0) {
nearbyEvents[0].execMethod('onAction', [player])
}
}
if (input === 'escape') {
// Open menu
player.gui('main-menu').open()
}
}
}
onLevelUp
Description: Called when a player increases one level
Parameters:
player: RpgPlayer - The player instance
nbLevel: number - Number of levels gained
Example:
const player: RpgPlayerHooks = {
onLevelUp(player: RpgPlayer, nbLevel: number) {
console.log(`${player.name} gained ${nbLevel} level(s)!`)
// Restore health and mana
player.hp = player.param.maxHp
player.sp = player.param.maxSp
// Show level up effect
player.showAnimation('level-up-effect')
player.showText(`Level Up! You are now level ${player.level}`)
// Grant skill points
player.skillPoints += nbLevel * 2
}
}
onSkillChange
Description: Called after a player learns or forgets a skill.
Parameters:
player: RpgPlayer - The player instance
payload.action: 'learn' | 'forget' - Skill change type
payload.skill - Skill data
payload.skillId: string - Skill identifier
payload.source?: string - Change source, such as manual, level, or studio
payload.level?: number - Level that triggered the change, when available
Example:
const player: RpgPlayerHooks = {
onSkillChange(player, payload) {
if (payload.action === 'learn') {
player.showNotification(`Learned ${payload.skillId}`)
}
}
}
onDead
Description: Called when a player’s HP drops to 0
Parameters:
player: RpgPlayer - The player instance
Example:
const player: RpgPlayerHooks = {
async onDead(player: RpgPlayer) {
const selection = await player.callGameover({
title: 'Game Over',
subtitle: 'Choose your fate',
entries: [
{ id: 'title', label: 'Title Screen' },
{ id: 'load', label: 'Load Game' }
]
})
if (selection?.id === 'title') {
await player.gui('rpg-title-screen').open()
}
if (selection?.id === 'load') {
await player.showLoad()
}
}
}
onDisconnected
Description: Called when a player leaves the server
Parameters:
player: RpgPlayer - The player instance
Example:
const player: RpgPlayerHooks = {
onDisconnected(player: RpgPlayer) {
console.log(`${player.name} disconnected`)
// Save player data
player.save()
// Notify other players
const map = player.getCurrentMap()
if (map) {
map.broadcastToPlayers('showText', [`${player.name} has left the game`])
}
}
}
onMove
Description: Called when the player’s x, y positions change
Parameters:
player: RpgPlayer - The player instance
Example:
const player: RpgPlayerHooks = {
onMove(player: RpgPlayer) {
// Check for hidden treasures
const treasures = player.getCurrentMap().getEventsOfType('treasure')
treasures.forEach(treasure => {
if (treasure.isHidden && player.distanceTo(treasure) < 16) {
treasure.reveal()
player.showText('You found a hidden treasure!')
}
})
// Update step counter
player.stepCount = (player.stepCount || 0) + 1
// Random encounters
if (player.stepCount % 100 === 0) {
if (Math.random() < 0.1) { // 10% chance
player.callBattle('random-encounter')
}
}
}
}
onInShape / onOutShape
Description: Called when a player enters or leaves a shape
Parameters:
player: RpgPlayer - The player instance
shape: RpgShape - The shape instance
Example:
const player: RpgPlayerHooks = {
onInShape(player: RpgPlayer, shape: RpgShape) {
if (shape.name === 'healing-zone') {
player.addState('regeneration')
player.showText('You feel rejuvenated...')
}
if (shape.name === 'danger-zone') {
player.showText('⚠️ Danger Zone - Proceed with caution!')
}
},
onOutShape(player: RpgPlayer, shape: RpgShape) {
if (shape.name === 'healing-zone') {
player.removeState('regeneration')
player.showText('The healing effect fades away.')
}
}
}
canChangeMap
Description: Determines if a player can change to a specific map
Parameters:
player: RpgPlayer - The player instance
nextMap: RpgClassMap<RpgMap> - The map class the player wants to enter
Returns:
boolean | Promise<boolean> - Whether the player can change maps
Example:
const player: RpgPlayerHooks = {
async canChangeMap(player: RpgPlayer, nextMap: any) {
// Check if player has required level
if (nextMap.requiredLevel && player.level < nextMap.requiredLevel) {
player.showText(`You need level ${nextMap.requiredLevel} to enter this area.`)
return false
}
// Check if player has required item
if (nextMap.requiredItem && !player.hasItem(nextMap.requiredItem)) {
player.showText(`You need ${nextMap.requiredItem} to enter this area.`)
return false
}
// Check with external service
const hasPermission = await checkMapPermission(player.id, nextMap.id)
if (!hasPermission) {
player.showText('Access denied.')
return false
}
return true
}
}
Complete Example
import { RpgPlayer, RpgMap, RpgPlayerHooks, defineModule } from '@rpgjs/server'
// Extend player interface
declare module '@rpgjs/server' {
export interface RpgPlayer {
gold: number
experience: number
stepCount: number
lastSaveTime: number
}
}
const player: RpgPlayerHooks = {
props: {
gold: { $default: 100 },
experience: { $default: 0 },
stepCount: { $default: 0 },
lastSaveTime: { $default: 0 }
},
onConnected(player: RpgPlayer) {
console.log(`🎮 ${player.name} joined the game`)
player.changeMap('town-square')
player.showText(`Welcome back, ${player.name}!`)
},
onJoinMap(player: RpgPlayer, map: RpgMap) {
console.log(`📍 ${player.name} entered ${map.name}`)
// Auto-save when entering important maps
if (map.isImportant) {
player.save()
player.lastSaveTime = Date.now()
}
},
onInput(player: RpgPlayer, { input }) {
if (input === 'menu') {
player.gui('inventory').open()
}
},
onLevelUp(player: RpgPlayer, nbLevel: number) {
player.hp = player.param.maxHp
player.sp = player.param.maxSp
player.showAnimation('level-up')
player.showText(`🎉 Level Up! You are now level ${player.level}`)
},
onMove(player: RpgPlayer) {
player.stepCount++
// Auto-save every 5 minutes
const now = Date.now()
if (now - player.lastSaveTime > 300000) { // 5 minutes
player.save()
player.lastSaveTime = now
}
},
onDisconnected(player: RpgPlayer) {
console.log(`👋 ${player.name} left the game`)
player.save()
}
}
export default defineModule({
player
})