All user data for FoundryVTT. Includes worlds, systems, modules, and any asset in the "foundryuserdata" directory. Does NOT include the FoundryVTT installation itself.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

201 lines
6.0 KiB

/*
* 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);
}
}