/*
|
|
* This file is part of the warpgate module (https://github.com/trioderegion/warpgate)
|
|
* Copyright (c) 2021 Matthew Haentschke.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import { logger } from './logger.js'
|
|
import { MODULE } from './module.js'
|
|
import { Gateway } from './gateway.js'
|
|
import { Events } from './events.js'
|
|
import { RemoteMutator } from './remote-mutator.js'
|
|
import {queueUpdate} from './update-queue.js'
|
|
|
|
|
|
|
|
const ops = {
|
|
DISMISS_SPAWN : "dismiss", //tokenId, sceneId, userId
|
|
EVENT : "event", //name, ...payload
|
|
REQUEST_MUTATE: "req-mutate", // ...payload
|
|
REQUEST_REVERT: "req-revert", // ...payload
|
|
NOTICE: "req-notice",
|
|
}
|
|
|
|
export class Comms {
|
|
|
|
static register() {
|
|
Comms.hooks();
|
|
}
|
|
|
|
static hooks() {
|
|
Hooks.on("ready", Comms._ready);
|
|
}
|
|
|
|
static _ready() {
|
|
logger.info("Registering sockets");
|
|
|
|
game.socket.on(`module.${MODULE.data.name}`, Comms._receiveSocket);
|
|
}
|
|
|
|
static _receiveSocket(socketData) {
|
|
logger.debug("Received socket data => ", socketData);
|
|
|
|
/* all users should immediately respond to notices */
|
|
if (socketData.op == ops.NOTICE) {
|
|
MODULE.handleNotice(socketData.payload.location, socketData.payload.sceneId, socketData.payload.options);
|
|
return socketData;
|
|
}
|
|
|
|
queueUpdate( async () => {
|
|
logger.debug("Routing operation: ",socketData.op);
|
|
switch (socketData.op){
|
|
case ops.DISMISS_SPAWN:
|
|
/* let the first GM handle all dismissals */
|
|
if (MODULE.isFirstGM()) await Gateway.dismissSpawn(socketData.payload.tokenId, socketData.payload.sceneId, socketData.payload.userId);
|
|
break;
|
|
case ops.EVENT:
|
|
/* all users should respond to events */
|
|
await Events.run(socketData.eventName, socketData.payload);
|
|
break;
|
|
case ops.REQUEST_MUTATE:
|
|
/* First owner of this target token/actor should respond */
|
|
await RemoteMutator.handleMutationRequest(socketData.payload);
|
|
break;
|
|
case ops.REQUEST_REVERT:
|
|
/* First owner of this target token/actor should respond */
|
|
await RemoteMutator.handleRevertRequest(socketData.payload);
|
|
break;
|
|
default:
|
|
logger.error("Unrecognized socket request", socketData);
|
|
break;
|
|
}
|
|
});
|
|
|
|
return socketData;
|
|
}
|
|
|
|
static _emit(socketData) {
|
|
game.socket.emit(`module.${MODULE.data.name}`, socketData);
|
|
|
|
/* always send events to self as well */
|
|
return Comms._receiveSocket(socketData);
|
|
}
|
|
|
|
static requestDismissSpawn(tokenId, sceneId) {
|
|
/** craft the socket data */
|
|
const data = {
|
|
op : ops.DISMISS_SPAWN,
|
|
payload : { tokenId, sceneId, userId: game.user.id }
|
|
}
|
|
|
|
return Comms._emit(data);
|
|
}
|
|
|
|
/*
|
|
* payload = {userId, tokenId, sceneId, updates, options}
|
|
*/
|
|
static requestMutate(tokenId, sceneId, { updates = {}, options = {} } = {}, onBehalf = game.user.id ) {
|
|
|
|
/* insert common fields */
|
|
const payload = {
|
|
userId: onBehalf,
|
|
tokenId,
|
|
sceneId,
|
|
updates,
|
|
options,
|
|
}
|
|
|
|
/* craft the socket data */
|
|
const data = {
|
|
op: ops.REQUEST_MUTATE,
|
|
payload
|
|
}
|
|
|
|
return Comms._emit(data);
|
|
}
|
|
|
|
static requestRevert(tokenId, sceneId, {mutationId = undefined, onBehalf = game.user.id, options = {}}) {
|
|
|
|
/* insert common fields */
|
|
const payload = {
|
|
userId: onBehalf,
|
|
tokenId,
|
|
sceneId,
|
|
mutationId,
|
|
options,
|
|
}
|
|
|
|
/* craft the socket data */
|
|
const data = {
|
|
op: ops.REQUEST_REVERT,
|
|
payload
|
|
}
|
|
|
|
return Comms._emit(data);
|
|
}
|
|
|
|
static requestNotice(location, sceneId = canvas.scene?.id, options = {}) {
|
|
const data = {
|
|
op: ops.NOTICE,
|
|
payload: {
|
|
sceneId,
|
|
location,
|
|
options,
|
|
}
|
|
}
|
|
|
|
return Comms._emit(data);
|
|
}
|
|
|
|
static packToken(tokenDoc) {
|
|
const tokenData = tokenDoc.toObject();
|
|
delete tokenData.actorData;
|
|
|
|
let actorData = tokenDoc.actor?.toObject() ?? {};
|
|
actorData.token = tokenData;
|
|
return actorData;
|
|
}
|
|
|
|
/**
|
|
* Allow custom events to be fired using the Warp Gate event system. Is broadcast to all users, including the initiator.
|
|
* Like Hooks, these functions cannot be awaited for a response, but all event functions executing on a given client
|
|
* will be evaluated in order of initial registration and the processing of the event functions will respect
|
|
* (and await) returned Promises.
|
|
*
|
|
* @param {string} name Name of this event. Watches and triggers use this name to register themselves.
|
|
* Like Hooks, any string can be used and it is dependent upon the watch or trigger registration to monitor the correct event name.
|
|
* @param {object} [payload={sceneId: canvas.scene.id, userId: game.user.id}] eventData {Object} The data that will be
|
|
* provided to watches and triggers and their condition functions.
|
|
* @param {string} [onBehalf=game.user.id] User ID that will be used in place of the current user in the
|
|
* cases of a relayed request to the GM (e.g. dismissal).
|
|
*
|
|
* @returns {Object} Data object containing the event's payload (execution details), and identifying metadata about
|
|
* this event, sent to all watching and triggering clients.
|
|
*/
|
|
static notifyEvent(name, payload = {}, onBehalf = game.user.id) {
|
|
/** insert common fields */
|
|
payload.sceneId = canvas.scene.id;
|
|
payload.userId = onBehalf;
|
|
|
|
/* craft the socket data */
|
|
const data = {
|
|
op : ops.EVENT,
|
|
eventName: name,
|
|
payload
|
|
}
|
|
|
|
return Comms._emit(data);
|
|
}
|
|
|
|
}
|