Files
muuhd/server/models/session.js
Kim Ravn Hansen 58c48fdc4b Foo
2025-09-15 10:44:24 +02:00

144 lines
4.3 KiB
JavaScript
Executable File

import WebSocket from "ws";
import { Player } from "./player.js";
import { mustBeString, mustBe } from "../utils/mustbe.js";
import { Scene } from "../scenes/scene.js";
import { gGame } from "./globals.js";
import { formatMessage, MessageType } from "../utils/messages.js";
export class Session {
/** @type {WebSocket} */
_websocket;
/** @protected @type {Scene} */
_scene;
/** @readonly @constant @type {Scene} */
get scene() {
return this._scene;
}
/** @type {Player} */
_player;
get player() {
return this._player;
}
/** @param {Player} player */
set player(player) {
if (player instanceof Player) {
this._player = player;
return;
}
if (player === null) {
this._player = null;
return;
}
throw Error(`Can only set player to null or instance of Player, but received ${typeof player}`);
}
/**
* @param {WebSocket} websocket
*/
constructor(websocket) {
this._websocket = websocket;
}
/**
* @param {Scene} scene
*/
setScene(scene) {
console.debug("changing scene", scene.constructor.name);
if (!(scene instanceof Scene)) {
throw new Error(`Expected instance of Scene, got a ${typeof scene}: >>${scene}<<`);
}
this._scene = scene;
scene.execute(this);
}
/** Close the session and websocket */
close() {
if (this._websocket) {
this._websocket.close();
this._websocket = null;
}
this._player = null;
this._scene = null;
}
/**
* Send a message via our websocket.
*
* @param {MessageType} messageType The message "header" (the first arg in the array sent to the client) holds the message type.
* @param {...any} args
*/
send(messageType, ...args) {
if (!this._websocket) {
console.error("Trying to send a message without a valid websocket", messageType, args);
return;
}
this._websocket.send(formatMessage(messageType, ...args));
}
/**
* @overload
* @param {string|string[]} text The prompt message (the request to get the user to enter some info).
* @param {string?} context
*/ /**
* @overload
* @param {string|string[]} text The prompt message (the request to get the user to enter some info).
* @param {object?} options Any options for the text (client side text formatting, color-, font-, or style info, etc.).
*/
sendPrompt(text, options) {
options = options || {};
if (typeof options === "string") {
// if options is just a string, assume we meant to apply a context to the prompt
options = { context: options };
}
this.send(
MessageType.PROMPT, // message type
text, // TODO: prompt text must be string or an array of strings
mustBe(options, "object"),
);
}
/**
* Send text to be displayed to the client
*
* @param {string|string[]} text Text to send. If array, each element will be displayed as its own line on the client side.
* @param {object?} options message options for the client.
*/
sendText(text, options = {}) {
this.send(MessageType.TEXT, text, options);
}
/** @param {string|string[]} errorMessage */
sendError(errorMessage, options = { verbatim: true, error: true }) {
this.send(MessageType.ERROR, mustBeString(errorMessage), options);
}
/**
* Send a calamity text and then close the connection.
* @param {string|string[]} errorMessage Text to send. If array, each element will be displayed as its own line on the client side.
*/
calamity(errorMessage) {
//
// The client should know not to format calamaties anyway, but we add “preformatted” anyway
console.info("CALAMITY", errorMessage);
this.send(MessageType.CALAMITY, errorMessage, { verbatim: true, calamity: true });
this.close();
}
/**
* @param {MessageType} systemMessageType
* @param {any?} value
*/
sendSystemMessage(systemMessageType, value = undefined) {
this.send(MessageType.SYSTEM, mustBeString(systemMessageType), value);
}
}