Created
July 27, 2020 07:22
-
-
Save janssen-io/385eea66613a43366dbb8a1a31d81831 to your computer and use it in GitHub Desktop.
FoundryVTT: Find which (combination) of modules is causing issues
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
The idea is to prevent testing every possible combination (2 to the power of the number of modules) to | |
see which combination of modules is causing issues. | |
TODO: try to find a smaller group using binary search | |
Halfway done: toggle every module to see if it's needed to reproduce the issues. | |
*/ | |
declare var game: any; | |
declare function duplicate<T>(arg: T): T; | |
type TroubleshooterFlag = { | |
iteration: number, | |
troublemakers: number, | |
modules: string[], | |
lastFailure: number | |
} | |
// create a mask with a 1 for every module | |
const max = modules => Math.pow(2, modules.length) - 1; | |
// create a mask for the current iteration. That is: | |
// 0: 1111 | |
// 1: 1110 | |
// 2: 1101 | |
// 3: 1011 | |
// 4: 0111 | |
const attempt = (flag: TroubleshooterFlag) => | |
max(flag.modules) - Math.floor(Math.pow(2, flag.iteration - 1)) | flag.troublemakers; | |
// if there is no problem in the current attempt, then the module that was | |
// switched off is causing issues. | |
function calculateTroublemakers(flag: TroubleshooterFlag, hasProblem: boolean) { | |
const currentAttempt = attempt(flag); | |
if (hasProblem) | |
flag.lastFailure = currentAttempt; | |
return (flag.lastFailure ^ currentAttempt) | flag.troublemakers; | |
} | |
// Show a simple dialog with yes/no/reset buttons | |
// yes: true, no: false, reset: reset (reloads) | |
function prompt(flag: TroubleshooterFlag): Promise<boolean> { | |
return new Promise((resolve, reject) => { | |
new Dialog({ | |
buttons: { | |
yes: { | |
label: 'yes', | |
callback: () => resolve(true) | |
}, | |
no: { | |
label: 'no', | |
callback: () => resolve(false) | |
}, | |
reset: { | |
label: 'reset', | |
callback: () => reset(flag) | |
} | |
} | |
}).render(true); | |
}) | |
} | |
function updateFlags(flag: TroubleshooterFlag): Promise<unknown> { | |
return game.user.setFlag('world', 'troubleshooter', flag) | |
} | |
// duplicate the flags, so Foundry can properly diff. | |
function getData(): TroubleshooterFlag { | |
return duplicate(game.user.getFlag('world', 'troubleshooter') || {}); | |
} | |
// transform decimal number into binary with appropriate padding | |
const toBits = (num, modules) => num.toString(2).padStart(modules.length, '0'); | |
// enable/disable the appropriate modules | |
// ! reloads the game ! | |
function updateModules(next, modules) { | |
const allModules = game.settings.get('core', 'moduleConfiguration'); | |
const bits = toBits(next, modules); | |
const updates = {}; | |
for(let i = 0; i < bits.length; i++) { | |
updates[modules[i]] = bits[i] === "1"; | |
} | |
game.settings.set('core', 'moduleConfiguration', Object.assign({}, allModules, updates)); | |
} | |
// tidy-ui = love | |
const EXCLUDED = [ 'tidy-ui_game-settings' ] | |
function getSortedEnabledModules() { | |
const modules = game.settings.get('core', 'moduleConfiguration'); | |
return Object.entries(modules) | |
.filter(([name, active]) => active && !EXCLUDED.includes(name)) | |
.map(([name, active]) => name) | |
.sort((a, b) => a.toLowerCase() - b.toLowerCase()); | |
} | |
// re-enable all modules that were initially enabled | |
// and clear troubleshooter flags | |
async function reset(flag: TroubleshooterFlag) { | |
const modules = flag.modules; | |
let enableAll = max(modules); | |
await game.user.unsetFlag('world', 'troubleshooter'); | |
updateModules(enableAll, modules); | |
} | |
async function run() { | |
const modules = getSortedEnabledModules(); | |
let lastAttempt = getData(); | |
if (!lastAttempt.iteration) { | |
lastAttempt = { | |
iteration: 0, | |
lastFailure: max(modules), | |
troublemakers: 0, | |
modules | |
}; | |
} | |
console.log(lastAttempt); | |
console.log('mask', toBits(lastAttempt.troublemakers, lastAttempt.modules)); | |
console.log('lastFailure', toBits(lastAttempt.lastFailure, lastAttempt.modules)); | |
const hasProblem = await prompt(lastAttempt); | |
const troublemakers = calculateTroublemakers(lastAttempt, hasProblem); | |
const nextAttempt: TroubleshooterFlag = { | |
...lastAttempt, | |
iteration: lastAttempt.iteration + 1, | |
lastFailure: hasProblem ? attempt(lastAttempt) : lastAttempt.lastFailure, | |
troublemakers | |
} | |
await updateFlags(nextAttempt); | |
updateModules(attempt(nextAttempt), nextAttempt.modules); | |
} | |
run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment