186 lines
7.5 KiB
JavaScript
186 lines
7.5 KiB
JavaScript
/**
|
|
* A helper class which manages the refresh workflow for perception layers on the canvas.
|
|
* This controls the logic which batches multiple requested updates to minimize the amount of work required.
|
|
* A singleton instance is available as {@link Canvas#perception}.
|
|
*/
|
|
class PerceptionManager extends RenderFlagsMixin(Object) {
|
|
|
|
/**
|
|
* @typedef {RenderFlags} PerceptionManagerFlags
|
|
* @property {boolean} initializeLighting Re-initialize the entire lighting configuration. An aggregate behavior
|
|
* which does no work directly but propagates to set several other flags.
|
|
* @property {boolean} initializeVision Re-initialize the entire vision configuration.
|
|
* See {@link CanvasVisibility#initializeSources}.
|
|
* @property {boolean} initializeVisionModes Initialize the active vision modes.
|
|
* See {@link CanvasVisibility#initializeVisionMode}.
|
|
* @property {boolean} initializeSounds Re-initialize the entire ambient sound configuration.
|
|
* See {@link SoundsLayer#initializeSources}.
|
|
* @property {boolean} refreshEdges Recompute intersections between all registered edges.
|
|
* See {@link CanvasEdges#refresh}.
|
|
* @property {boolean} refreshLighting Refresh the rendered appearance of lighting
|
|
* @property {boolean} refreshLightSources Update the configuration of light sources
|
|
* @property {boolean} refreshOcclusion Refresh occlusion
|
|
* @property {boolean} refreshPrimary Refresh the contents of the PrimaryCanvasGroup mesh
|
|
* @property {boolean} refreshSounds Refresh the audio state of ambient sounds
|
|
* @property {boolean} refreshVision Refresh the rendered appearance of vision
|
|
* @property {boolean} refreshVisionSources Update the configuration of vision sources
|
|
* @property {boolean} soundFadeDuration Apply a fade duration to sound refresh workflow
|
|
*/
|
|
|
|
/** @override */
|
|
static RENDER_FLAGS = {
|
|
|
|
// Edges
|
|
refreshEdges: {},
|
|
|
|
// Light and Darkness Sources
|
|
initializeLighting: {propagate: ["initializeDarknessSources", "initializeLightSources"]},
|
|
initializeDarknessSources: {propagate: ["refreshLighting", "refreshVision", "refreshEdges"]},
|
|
initializeLightSources: {propagate: ["refreshLighting", "refreshVision"]},
|
|
refreshLighting: {propagate: ["refreshLightSources"]},
|
|
refreshLightSources: {},
|
|
|
|
// Vision
|
|
initializeVisionModes: {propagate: ["refreshVisionSources", "refreshLighting", "refreshPrimary"]},
|
|
initializeVision: {propagate: ["initializeVisionModes", "refreshVision"]},
|
|
refreshVision: {propagate: ["refreshVisionSources", "refreshOcclusionMask"]},
|
|
refreshVisionSources: {},
|
|
|
|
// Primary Canvas Group
|
|
refreshPrimary: {},
|
|
refreshOcclusion: {propagate: ["refreshOcclusionStates", "refreshOcclusionMask"]},
|
|
refreshOcclusionStates: {},
|
|
refreshOcclusionMask: {},
|
|
|
|
// Sound
|
|
initializeSounds: {propagate: ["refreshSounds"]},
|
|
refreshSounds: {},
|
|
soundFadeDuration: {},
|
|
|
|
/** @deprecated since v12 */
|
|
refreshTiles: {
|
|
propagate: ["refreshOcclusion"],
|
|
deprecated: {message: "The refreshTiles flag is deprecated in favor of refreshOcclusion",
|
|
since: 12, until: 14, alias: true}
|
|
},
|
|
/** @deprecated since v12 */
|
|
identifyInteriorWalls: {
|
|
propagate: ["initializeLighting", "initializeVision"],
|
|
deprecated: {
|
|
message: "The identifyInteriorWalls is now obsolete and has no replacement.",
|
|
since: 12, until: 14, alias: true
|
|
}
|
|
},
|
|
/** @deprecated since v11 */
|
|
forceUpdateFog: {
|
|
propagate: ["refreshVision"],
|
|
deprecated: {
|
|
message: "The forceUpdateFog flag is now obsolete and has no replacement. "
|
|
+ "The fog is now always updated when the visibility is refreshed", since: 11, until: 13, alias: true
|
|
}
|
|
}
|
|
};
|
|
|
|
static #deprecatedFlags = ["refreshTiles", "identifyInteriorWalls", "forceUpdateFog"];
|
|
|
|
/** @override */
|
|
static RENDER_FLAG_PRIORITY = "PERCEPTION";
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/** @override */
|
|
applyRenderFlags() {
|
|
if ( !this.renderFlags.size ) return;
|
|
const flags = this.renderFlags.clear();
|
|
|
|
// Initialize darkness sources
|
|
if ( flags.initializeDarknessSources ) canvas.effects.initializeDarknessSources();
|
|
|
|
// Recompute edge intersections
|
|
if ( flags.refreshEdges ) canvas.edges.refresh();
|
|
|
|
// Initialize positive light sources
|
|
if ( flags.initializeLightSources ) canvas.effects.initializeLightSources();
|
|
|
|
// Initialize active vision sources
|
|
if ( flags.initializeVision ) canvas.visibility.initializeSources();
|
|
|
|
// Initialize the active vision mode
|
|
if ( flags.initializeVisionModes ) canvas.visibility.initializeVisionMode();
|
|
|
|
// Initialize active sound sources
|
|
if ( flags.initializeSounds ) canvas.sounds.initializeSources();
|
|
|
|
// Refresh light, vision, and sound sources
|
|
if ( flags.refreshLightSources ) canvas.effects.refreshLightSources();
|
|
if ( flags.refreshVisionSources ) canvas.effects.refreshVisionSources();
|
|
if ( flags.refreshSounds ) canvas.sounds.refresh({fade: flags.soundFadeDuration ? 250 : 0});
|
|
|
|
// Refresh the appearance of the Primary Canvas Group environment
|
|
if ( flags.refreshPrimary ) canvas.primary.refreshPrimarySpriteMesh();
|
|
if ( flags.refreshLighting ) canvas.effects.refreshLighting();
|
|
if ( flags.refreshVision ) canvas.visibility.refresh();
|
|
|
|
// Update roof occlusion states based on token positions and vision
|
|
// TODO: separate occlusion state testing from CanvasOcclusionMask
|
|
if ( flags.refreshOcclusion ) canvas.masks.occlusion.updateOcclusion();
|
|
else {
|
|
if ( flags.refreshOcclusionMask ) canvas.masks.occlusion._updateOcclusionMask();
|
|
if ( flags.refreshOcclusionStates ) canvas.masks.occlusion._updateOcclusionStates();
|
|
}
|
|
|
|
// Deprecated flags
|
|
for ( const f of PerceptionManager.#deprecatedFlags ) {
|
|
if ( flags[f] ) {
|
|
const {message, since, until} = PerceptionManager.RENDER_FLAGS[f].deprecated;
|
|
foundry.utils.logCompatibilityWarning(message, {since, until});
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* Update perception manager flags which configure which behaviors occur on the next frame render.
|
|
* @param {object} flags Flag values (true) to assign where the keys belong to PerceptionManager.FLAGS
|
|
*/
|
|
update(flags) {
|
|
if ( !canvas.ready ) return;
|
|
this.renderFlags.set(flags);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* A helper function to perform an immediate initialization plus incremental refresh.
|
|
*/
|
|
initialize() {
|
|
return this.update({
|
|
refreshEdges: true,
|
|
initializeLighting: true,
|
|
initializeVision: true,
|
|
initializeSounds: true,
|
|
refreshOcclusion: true
|
|
});
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/* Deprecations and Compatibility */
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* @deprecated since v12
|
|
* @ignore
|
|
*/
|
|
refresh() {
|
|
foundry.utils.logCompatibilityWarning("PerceptionManager#refresh is deprecated in favor of assigning granular "
|
|
+ "refresh flags", {since: 12, until: 14});
|
|
return this.update({
|
|
refreshLighting: true,
|
|
refreshVision: true,
|
|
refreshSounds: true,
|
|
refreshOcclusion: true
|
|
});
|
|
}
|
|
}
|