@lobstar/core
Version:
A simple network and lobby manager for multiplayer web games
220 lines (170 loc) • 6.6 kB
Markdown
<p align="center">
<img src="../../images/mascot.png" alt="Lobstar logo" width="256" />
</p>
> [!WARNING]
> This is an early prototype and the API is subject to change and bugs are expected.
A lightweight peer-to-peer multiplayer game session and lobby manager for web games.
[](https://www.npmjs.com/package/@lobstar/core)
[](https://github.com/jamsinclair/@lobstar/core/blob/main/LICENSE.md)
[](https://bundlephobia.com/package/@lobstar/core)
- Simple peer-to-peer networking with WebRTC (via [PeerJS](https://peerjs.com/))
- Host/client architecture with configurable lobby settings
- Player management (joining, leaving, kicking, ready states)
- Game state lifecycle (lobby, playing, game over)
- Event-based messaging system
- Robust error handling and state management
## Installation
```bash
npm install @lobstar/core
```
## Basic Usage
### Creating a Game Session
```typescript
import { GameSessionManager } from '@lobstar/core';
// Create a session manager with default options
const gameSession = new GameSessionManager({
maxPlayers: 4, // Maximum number of players allowed (default: 8)
requireReadyBeforeStart: true, // Require all players to be ready before starting (default: true)
debug: true // Enable debug logging (default: false)
});
// Listen for state changes
gameSession.on('stateChange', ({ state, previousState }) => {
console.log(`Game state changed from ${previousState} to ${state}`);
});
// Host a new game
async function hostGame() {
try {
const lobbyId = await gameSession.host('HostPlayer');
console.log(`Game hosted with lobby ID: ${lobbyId}`);
// Share this lobby ID with other players so they can join
} catch (error) {
console.error('Failed to host game:', error);
}
}
// Join an existing game
async function joinGame(lobbyId) {
try {
await gameSession.join(lobbyId, 'GuestPlayer');
console.log('Successfully joined the game!');
} catch (error) {
console.error('Failed to join game:', error);
}
}
```
```typescript
// Set player ready state
gameSession.setReady(true);
// Start the game (host only)
if (gameSession.isHost()) {
gameSession.startGame();
}
// Get current players
const players = gameSession.getPlayers();
console.log('Current players:', players);
// Kick a player (host only)
if (gameSession.isHost()) {
gameSession.kickPlayer('player-id-to-kick');
}
// End the game (host only)
if (gameSession.isHost()) {
gameSession.endGame();
}
// Leave the game
gameSession.leave();
```
The session manager provides a custom message system that allows you to send and receive messages between players.
This allows you to
- Extend the lobby experience with chat, character selection, etc.
- Send and receive game-specific messages between players on game start
> [!NOTE]
> The host will operate like a server, they can send messages to all players and receive messages from all players.
>
> The clients can only send messages and receive messages from the host.
```typescript
// Send a custom message to the host
gameSession.sendMessageToHost({
type: 'move',
x: 100,
y: 200
});
// Broadcast a message to all players
gameSession.broadcastMessage({
type: 'itemCollected',
playerId: 'player-id-123',
itemId: 'power-up-22'
});
// Send a custom message to a specific player from the host
gameSession.sendMessage('player-id-123', {
type: 'secretObjective',
objective: 'Find the hidden gold necklace'
});
// Listen for custom messages
gameSession.on('customMessage', ({ data, peerId }) => {
console.log(`Received message from ${peerId}:`, data);
});
```
```typescript
new GameSessionManager(options?: GameSessionOptions)
```
**Options:**
- `maxPlayers`: Maximum number of players allowed (default: 8)
- `requireReadyBeforeStart`: Require all players to be ready before starting (default: true)
- `debug`: Enable debug logging (default: false)
- `peerOptions`: Options to pass to the underlying PeerJS instance
- `playerJoinTimeoutMs`: Timeout for player join (default: 10000)
### Methods
#### Session Management
- `host(playerName: string, lobbyId?: string): Promise<string>` - Host a new game session
- `join(lobbyId: string, playerName: string): Promise<void>` - Join an existing game session
- `leave(): void` - Leave the current session
#### Game Flow
- `setReady(isReady: boolean): void` - Set player ready state
- `startGame(): void` - Start the game (host only)
- `endGame(): void` - End the game (host only)
#### Player Management
- `kickPlayer(playerId: string): void` - Kick a player (host only)
- `getPlayers(): PlayerMap` - Get all players
- `getPlayer(id: string): Player | null` - Get a specific player
- `getSelf(): Player | null` - Get the current player
- `getHost(): Player | null` - Get the host player
#### Communication
- `sendMessage(peerId: string, data: unknown): void` - Send a message to a specific player. Only the host can send messages to other players.
Clients can only send messages to the host's `peerId`.
- `sendMessageToHost(data: unknown): void` - Send a message to the host.
- `broadcastMessage(data: unknown, excludeSelf: boolean = true): void` - Broadcast a message to all players.
Only the host can broadcast messages.
#### Status
- `isHost(): boolean` - Check if the current player is the host
- `getState(): SessionState` - Get the current session state
- `getMaxPlayers(): number` - Get the maximum allowed players
### Events
Listen to events using the `on` method:
```typescript
gameSession.on('eventName', (eventData) => {
// Handle the event
});
```
Available events:
- `stateChange`: Fired when the session state changes
- `playersUpdate`: Fired when the players list is updated
- `customMessage`: Fired when a custom message is received
- `error`: Fired when an error occurs
- `kicked`: Fired when the player is kicked from the session
The session manager provides detailed error information through the `error` event:
```typescript
gameSession.on('error', ({ code, message, context, originalError }) => {
console.error(`Error [${code}]: ${message} (${context})`);
if (originalError) {
console.error('Original error:', originalError);
}
});
```
Error codes are available in the `ERROR_CODES` constant.
MIT