180 lines
4.9 KiB
JavaScript
180 lines
4.9 KiB
JavaScript
/**
|
|
* Socket Client Module
|
|
* Manages WebSocket communication with the game server.
|
|
*/
|
|
class SocketClient {
|
|
constructor(serverUrl) {
|
|
this.socket = null;
|
|
this.serverUrl = serverUrl || window.location.origin; // Default to current origin
|
|
this.eventListeners = {
|
|
connect: [],
|
|
disconnect: [],
|
|
connect_error: [],
|
|
gameIntroduction: [],
|
|
narrativeResponse: [],
|
|
gameSaved: [],
|
|
gameLoaded: [],
|
|
error: [],
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Connects to the WebSocket server.
|
|
*/
|
|
connect() {
|
|
if (this.socket && this.socket.connected) {
|
|
console.log('SocketClient: Already connected.');
|
|
return;
|
|
}
|
|
|
|
console.log(`SocketClient: Connecting to ${this.serverUrl}...`);
|
|
// Ensure io is available (it should be loaded globally)
|
|
if (typeof io === 'undefined') {
|
|
console.error('Socket.IO client library (io) not found. Make sure it is loaded.');
|
|
this.triggerEvent('error', { message: 'Socket.IO library not loaded.' });
|
|
return;
|
|
}
|
|
|
|
this.socket = io(this.serverUrl, {
|
|
reconnectionAttempts: 5,
|
|
timeout: 10000,
|
|
});
|
|
|
|
this.initializeSocketEventHandlers();
|
|
}
|
|
|
|
/**
|
|
* Disconnects from the server.
|
|
*/
|
|
disconnect() {
|
|
if (this.socket) {
|
|
console.log('SocketClient: Disconnecting...');
|
|
this.socket.disconnect();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the client is currently connected.
|
|
* @returns {boolean} True if connected, false otherwise.
|
|
*/
|
|
isConnected() {
|
|
return this.socket && this.socket.connected;
|
|
}
|
|
|
|
/**
|
|
* Sets up the listeners for standard socket events.
|
|
*/
|
|
initializeSocketEventHandlers() {
|
|
if (!this.socket) return;
|
|
|
|
this.socket.on('connect', () => {
|
|
console.log('SocketClient: Connected to server.');
|
|
this.triggerEvent('connect');
|
|
});
|
|
|
|
this.socket.on('disconnect', (reason) => {
|
|
console.log(`SocketClient: Disconnected from server. Reason: ${reason}`);
|
|
this.triggerEvent('disconnect', reason);
|
|
});
|
|
|
|
this.socket.on('connect_error', (error) => {
|
|
console.error('SocketClient: Connection error:', error);
|
|
this.triggerEvent('connect_error', error);
|
|
});
|
|
|
|
// --- Game-specific events ---
|
|
|
|
this.socket.on('gameIntroduction', (data) => {
|
|
console.log('SocketClient: Received gameIntroduction');
|
|
this.triggerEvent('gameIntroduction', data);
|
|
});
|
|
|
|
this.socket.on('narrativeResponse', (data) => {
|
|
console.log('SocketClient: Received narrativeResponse');
|
|
this.triggerEvent('narrativeResponse', data);
|
|
});
|
|
|
|
this.socket.on('gameSaved', (data) => {
|
|
console.log('SocketClient: Received gameSaved confirmation');
|
|
this.triggerEvent('gameSaved', data); // Pass data if any
|
|
});
|
|
|
|
this.socket.on('gameLoaded', (data) => {
|
|
console.log('SocketClient: Received gameLoaded confirmation');
|
|
this.triggerEvent('gameLoaded', data);
|
|
});
|
|
|
|
this.socket.on('error', (data) => {
|
|
console.error('SocketClient: Received error from server:', data);
|
|
this.triggerEvent('error', data);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Registers a listener for a specific event.
|
|
* @param {string} eventName - The name of the event.
|
|
* @param {function} callback - The function to call when the event occurs.
|
|
*/
|
|
on(eventName, callback) {
|
|
if (this.eventListeners[eventName]) {
|
|
this.eventListeners[eventName].push(callback);
|
|
} else {
|
|
console.warn(`SocketClient: Attempted to register listener for unknown event "${eventName}"`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Triggers a specific event, calling all registered listeners.
|
|
* @param {string} eventName - The name of the event.
|
|
* @param {*} data - Data to pass to the listeners.
|
|
*/
|
|
triggerEvent(eventName, data) {
|
|
if (this.eventListeners[eventName]) {
|
|
this.eventListeners[eventName].forEach(callback => {
|
|
try {
|
|
callback(data);
|
|
} catch (error) {
|
|
console.error(`SocketClient: Error in event listener for "${eventName}":`, error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Emits an event to the server.
|
|
* @param {string} eventName - The name of the event to emit.
|
|
* @param {object} data - The data to send with the event.
|
|
*/
|
|
emit(eventName, data) {
|
|
if (this.socket && this.socket.connected) {
|
|
console.log(`SocketClient: Emitting "${eventName}"`, data || '');
|
|
this.socket.emit(eventName, data);
|
|
} else {
|
|
console.error(`SocketClient: Cannot emit "${eventName}", not connected.`);
|
|
// Optionally trigger an error event or queue the message
|
|
this.triggerEvent('error', { message: `Cannot send command "${eventName}", not connected.` });
|
|
}
|
|
}
|
|
|
|
// --- Convenience methods for game actions ---
|
|
|
|
requestStartGame() {
|
|
this.emit('startGame');
|
|
}
|
|
|
|
sendCommand(command) {
|
|
this.emit('playerCommand', { command });
|
|
}
|
|
|
|
requestSaveGame() {
|
|
this.emit('saveGame');
|
|
}
|
|
|
|
requestLoadGame() {
|
|
this.emit('loadGame');
|
|
}
|
|
}
|
|
|
|
// Export the class if using modules
|
|
// export default SocketClient;
|