Skip to Content
DocsGame ServerRoom User State

Managing Room User State

This guide details how to manage per-user state within a room in Agent8. Room user state lets you store and update individualized profiles, settings, or any other room-scoped data. You can access and modify these states using the following room API functions:

  • $room.getMyState()
  • $room.updateMyState(state: Object)
  • $room.getUserState(account: string)
  • $room.updateUserState(account: string, state: Object)

By default, every room user state contains an account field that uniquely identifies the user.

Every room user state contains an account field holding the user’s unique identifier.

Server API

The server API offers the following methods to manage room user state:

  • $sender.account: string — The unique account identifier of the user sending the request.
  • $sender.roomId: string — The room ID associated with the request.
  • $room.getMyState(): Promise<Object> — Retrieves your room-specific state.
  • $room.updateMyState(state: Object): Promise<Object> — Updates your room-specific state.
  • $room.getUserState(account: string): Promise<Object> — Retrieves a particular user’s room state.
  • $room.updateUserState(account: string, state: Object): Promise<Object> — Updates a particular user’s room state.
  • $room.countUsers(): Promise<number> - Retrieves number of joined users in the room.
  • $room.getAllUserStates(): Promise<Object[]> - Retrieves all user states in the room.
server.js
class Server { async getMyState() { return await $room.getMyState(); } async updateMyState(state) { return await $room.updateMyState(state); } async getUserState(account) { return await $room.getUserState(account); } async updateUserState(account, state) { return await $room.updateUserState(account, state); } async getAllUserStates() { return await $room.getAllUserStates(); } }

Client API

subscriptions

  • server.subscribeRoomMyState(roomId: string, (state: any) => {}): UnsubscribeFunction - roomId is required.
  • server.subscribeRoomUserState(roomId: string, account: string, (state: any) => {}): UnsubscribeFunction - roomId is required.
  • server.subscribeRoomAllUserStates(roomId: string, (states: { ...state: any, account: string, updated: boolean }[]) => {}): UnsubscribeFunction - roomId is required. The changed state, which is the cause of the subscription, is set to updated: true.

hooks

  • const myState = useRoomMyState() - The hook always gets the current room. No room ID is required.
  • const userState = useRoomUserState(account: string) - The hook always gets the current room. No room ID is required.

On the client side, you can receive real-time updates for room-specific user states using subscription methods. This allows you to subscribe to your own state changes, updates for a specific user, or even get a snapshot of states for all users in the room.

Subscribe to Room User State Updates

import { useGameServer } from "@agent8/gameserver"; import { useEffect } from "react"; function RoomUserStateComponent({ roomId }) { const { connected, server } = useGameServer(); useEffect(() => { if (!connected) return; // Subscribe to updates for your own room state const unsubscribeMyState = server.subscribeRoomMyState(roomId, (state) => { console.log("My room state updated:", state); }); // Subscribe to updates for a specific user's room state const userAccount = "some-user-account"; const unsubscribeUserState = server.subscribeRoomUserState( roomId, userAccount, (state) => { console.log(`Room user state updated for ${userAccount}:`, state); } ); // Subscribe to updates for all user states in the room (including yours) const unsubscribeAllUserStates = server.subscribeRoomAllUserStates( roomId, (states: { ...state: any, account: string; }[]) => { console.log("All room users state updated:", users); } ); // Cleanup subscriptions when component unmounts return () => { unsubscribeMyState(); unsubscribeUserState(); unsubscribeAllUserStates(); }; }, [connected, server]); return <div>Room User State Component</div>; }

Sync Room User State with React Hooks

For real-time synchronization of room user state, the following hooks are available:

import { useRoomState, useRoomUserState, useRoomAllUserStates, } from "@agent8/gameserver"; function RoomUserStateDisplay() { const roomState = useRoomState(); // Retrieves your room-specific state const userAccount = "some-user-account"; const userState = useRoomUserState(userAccount); // Retrieves a particular user's state const states = useRoomAllUserStates(); // Retrieves states for all states as { ...state: any, account: string }[] return ( <div> <h2>My Room State</h2> <pre>{JSON.stringify(roomState, null, 2)}</pre> <h2>User State for {account}</h2> <pre>{JSON.stringify(userState, null, 2)}</pre> <h2>All User States in Room</h2> <p>Total user states: {states.length}</p> <ul> {states.map((state) => ( <li key={state.account}> <strong>Account:</strong> {state.account} <pre>{JSON.stringify(state, null, 2)}</pre> </li> ))} </ul> </div> ); }

The useRoomAllUserStates hook returns an object with a states array where each item has the structure { ...state: any, account: string }.

Example: Syncing User Positions

In this example, when a user moves their mouse, the new position is sent to the server via the remote function call updateMyPosition(position). The server then updates the user’s room state with the new position, and all user positions are rendered as circles on the screen.

server.js
class Server { async joinRoom(roomId) { await $room.join(roomId); } async updateMyPosition(position) { // 'position' should be an object: { x: number, y: number } return await $room.updateMyState({ position }); } }
src/PositionTracker.tsx
import { useGameServer, useRoomState, useRoomAllUserStates, } from "@agent8/gameserver"; import { useEffect } from "react"; function PositionTracker({ roomId }: { roomId: string }) { const { connected, server } = useGameServer(); const myState = useRoomState(); const states = useRoomAllUserStates(); // users is of type { ...state: any, account: string }[] useEffect(() => { if (!connected) return; // Join the room when component mounts server.remoteFunction("joinRoom", [roomId]).catch(console.error); // Optional: Additional subscription setup if needed beyond the hooks const unsubscribe = server.subscribeRoomAllUserStates(roomId, (states: { ...state: any; account: string; updated: boolean }[]) => { } ); return () => { unsubscribe(); }; }, [connected, server, roomId]); const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => { if (!connected) return; const position = { x: e.clientX, y: e.clientY }; server .remoteFunction("updateMyPosition", [position], { throttle: 100 }) .catch(console.error); }; if (!connected) return <p>Loading...</p>; return ( <div style={{ position: "absolute", left: 0, top: 0, width: "100%", height: "100vh", }} onMouseMove={handleMouseMove} > {states.map((state) => ( <div key={state.account} style={{ position: "absolute", top: state.position?.y || 0, left: state.position?.x || 0, width: 20, height: 20, borderRadius: "50%", background: state.account === myState.account ? "blue" : "red", }} /> ))} </div> ); } export default function App() { return <PositionTracker roomId="room1" />; }

Conclusion

By leveraging room-specific state functions and subscription methods, you can efficiently manage and synchronize per-user data within a room. This approach enables real-time updates for both your own data and that of other users, giving you a complete, aggregated view of the room’s state.

Last updated on