>}
*/
static async remoteBatchRevert( tokenDocs, {mutationName = null, options = {}} = {} ) {
/* follow normal protocol for initial requests.
* if accepted, force accept and force suppress remaining token mutations
* if rejected, bail on all further mutations for this owner */
let firstToken = tokenDocs.shift();
while( !!firstToken && warpgate.mutationStack(firstToken).stack.length == 0 ) firstToken = tokenDocs.shift();
if(!firstToken) return [];
const results = [await warpgate.revert(firstToken, mutationName, options)];
if(results[0].accepted) {
const silentOptions = foundry.utils.mergeObject(options, {
overrides: {alwaysAccept: true, suppressToast: true}
}, {inplace: false}
);
results.push(...(tokenDocs.map( tokenDoc => {
return warpgate.revert(tokenDoc, mutationName, silentOptions);
})))
} else {
results.push(...tokenDocs.map( tokenDoc => ({sceneId: tokenDoc.parent.id, tokenId: tokenDoc.id, accepted: false})));
}
return results;
}
static async handleMutationRequest(payload) {
/* First, are we the first player owner? If not, stop, they will handle it */
const tokenDoc = game.scenes.get(payload.sceneId).getEmbeddedDocument('Token', payload.tokenId);
if (MODULE.isFirstOwner(tokenDoc.actor)) {
let {alwaysAccept: accepted, suppressToast} = MODULE.getFeedbackSettings(payload.options.overrides);
if(!accepted) {
accepted = await RemoteMutator._queryRequest(tokenDoc, payload.userId, payload.options.description, payload.updates)
/* if a dialog is shown, the user knows the outcome */
suppressToast = true;
}
let responseData = {
sceneId: payload.sceneId,
userId: game.user.id,
accepted,
tokenId: payload.tokenId,
mutationId: payload.options.name,
options: payload.options,
}
await warpgate.event.notify(warpgate.EVENT.MUTATE_RESPONSE, responseData);
if (accepted) {
/* first owner accepts mutation -- apply it */
/* requests will never have callbacks */
await Mutator.mutate(tokenDoc, payload.updates, {}, payload.options);
const message = MODULE.format('display.mutationRequestTitle', {userName: game.users.get(payload.userId).name, tokenName: tokenDoc.name});
if(!suppressToast) ui.notifications.info(message);
}
}
}
static async handleRevertRequest(payload) {
/* First, are we the first player owner? If not, stop, they will handle it */
const tokenDoc = game.scenes.get(payload.sceneId).getEmbeddedDocument('Token', payload.tokenId);
if (MODULE.isFirstOwner(tokenDoc.actor)) {
const stack = warpgate.mutationStack(tokenDoc);
if( (stack.stack ?? []).length == 0 ) return;
const details = payload.mutationId ? stack.getName(payload.mutationId) : stack.last;
const description = MODULE.format('display.revertRequestDescription', {mName: details.name, tName: tokenDoc.name});
let {alwaysAccept: accepted, suppressToast} = MODULE.getFeedbackSettings(payload.options.overrides);
if(!accepted) {
accepted = await RemoteMutator._queryRequest(tokenDoc, payload.userId, description, details );
suppressToast = true;
}
let responseData = {
sceneId: payload.sceneId,
userId: game.user.id,
accepted,
tokenId: payload.tokenId,
mutationId: payload.mutationId
}
await warpgate.event.notify(warpgate.EVENT.REVERT_RESPONSE, responseData);
/* if the request is accepted, do the revert */
if (accepted) {
await Mutator.revertMutation(tokenDoc, payload.mutationId, payload.options);
if (!suppressToast) {
ui.notifications.info(description);
}
}
}
}
static async _queryRequest(tokenDoc, requestingUserId, description = 'warpgate.display.emptyDescription', detailsObject) {
/* if this is update data, dont include the mutate data please, its huge */
let displayObject = duplicate(detailsObject);
if (displayObject.actor?.flags?.warpgate) {
displayObject.actor.flags.warpgate = {};
}
displayObject = MODULE.removeEmptyObjects(displayObject);
const details = RemoteMutator._convertObjToHTML(displayObject)
const modeSwitch = {
description: {label: MODULE.localize('display.inspectLabel'), value: 'inspect', content: `${game.i18n.localize(description)}
`},
inspect: {label: MODULE.localize('display.descriptionLabel'), value: 'description', content: details }
}
const title = MODULE.format('display.mutationRequestTitle', {userName: game.users.get(requestingUserId).name, tokenName: tokenDoc.name});
let userResponse = false;
let modeButton = modeSwitch.description;
do {
userResponse = await warpgate.buttonDialog({buttons: [{label: MODULE.localize('display.findTargetLabel'), value: 'select'}, {label: MODULE.localize('display.acceptLabel'), value: true}, {label: MODULE.localize('display.rejectLabel'), value: false}, modeButton], content: modeButton.content, title, options: {top: 100}});
if (userResponse === 'select') {
if (tokenDoc.object) {
tokenDoc.object.control({releaseOthers: true});
await canvas.animatePan({x: tokenDoc.object.x, y: tokenDoc.object.y});
}
} else if (userResponse !== false && userResponse !== true) {
/* swap modes and re-render */
modeButton = modeSwitch[userResponse];
}
} while (userResponse !== false && userResponse !== true)
return userResponse;
}
static _convertObjToHTML(obj) {
const stringified = JSON.stringify(obj, undefined, '$SPACING');
return stringified.replaceAll('\n', '
').replaceAll('$SPACING', ' ');
}
}