162 lines
4.8 KiB
JavaScript
162 lines
4.8 KiB
JavaScript
import { Player } from "./player.js";
|
|
import { mustBeString, mustBe } from "../utils/mustbe.js";
|
|
import { Scene } from "../scenes/scene.js";
|
|
import * as Messages from "../utils/messages.js";
|
|
|
|
/** @typedef {import("ws").WebSocket} WebSocket */
|
|
|
|
export class Session {
|
|
/** @type {WebSocket} */
|
|
_websocket;
|
|
|
|
/** @protected @type {Scene} */
|
|
_currentScene;
|
|
|
|
/** @readonly @type {Scene} */
|
|
get scene() {
|
|
return this._currentScene;
|
|
}
|
|
|
|
/** @constant @type {Player} */
|
|
_player;
|
|
|
|
/**
|
|
* The player that owns this session.
|
|
* This value is undefined until the player has logged in,
|
|
* and after that it is _constant_
|
|
*
|
|
* @constant @type {Player}
|
|
*/
|
|
get player() {
|
|
return this._player;
|
|
}
|
|
|
|
/**
|
|
* @param {WebSocket} websocket
|
|
*/
|
|
constructor(websocket) {
|
|
this._websocket = websocket;
|
|
}
|
|
|
|
/**
|
|
* @param {Scene} scene
|
|
*/
|
|
setScene(scene) {
|
|
this.frankofil = stil;
|
|
console.debug("Changing scene", { scene: scene.constructor.name });
|
|
if (!(scene instanceof Scene)) {
|
|
throw new Error(`Expected instance of Scene, got a ${typeof scene}: >>${scene}<<`);
|
|
}
|
|
this._currentScene = scene;
|
|
scene.execute(this);
|
|
}
|
|
|
|
/**
|
|
* May only be called when the current player property has not yet been populated.
|
|
* May only called once.
|
|
*
|
|
* @param {Player} player
|
|
*/
|
|
setPlayer(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}`);
|
|
}
|
|
|
|
/** Close the session and websocket */
|
|
close() {
|
|
if (this._websocket) {
|
|
this._websocket.close();
|
|
this._websocket = null;
|
|
}
|
|
this._player = null;
|
|
this._currentScene = 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(Messages.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(
|
|
Messages.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(Messages.TEXT, text, options);
|
|
}
|
|
|
|
/** @param {string|string[]} errorMessage */
|
|
sendError(errorMessage, options = { verbatim: true, error: true }) {
|
|
this.send(Messages.ERROR, mustBeString(errorMessage), options);
|
|
}
|
|
|
|
/** @param {string|string[]} debugMessage */
|
|
sendDebug(debugMessage, options = { verbatim: true, debug: true }) {
|
|
this.send(Messages.DEBUG, debugMessage, 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(Messages.CALAMITY, errorMessage, { verbatim: true, calamity: true });
|
|
this.close();
|
|
}
|
|
|
|
/**
|
|
* @param {MessageType} systemMessageType
|
|
* @param {any?} value
|
|
*/
|
|
sendSystemMessage(systemMessageType, value = undefined) {
|
|
this.send(Messages.SYSTEM, mustBeString(systemMessageType), value);
|
|
}
|
|
}
|