From db8c2e29c1f13f0efebbfc6d9996b375f2a6c7f0 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Fri, 2 Jan 2026 04:42:40 +0100 Subject: [PATCH] . --- .../scene/sceneConfigSettings.mjs | 16 ++++++++-- module/applications/ui/sceneNavigation.mjs | 21 ++++++++----- module/data/actor/environment.mjs | 30 ++++++++++++++++++- module/data/scene/scene.mjs | 5 +++- module/documents/scene.mjs | 26 ++++++++++++++++ module/systemRegistration/socket.mjs | 7 ++++- 6 files changed, 93 insertions(+), 12 deletions(-) diff --git a/module/applications/scene/sceneConfigSettings.mjs b/module/applications/scene/sceneConfigSettings.mjs index 15cdfeee..6a093699 100644 --- a/module/applications/scene/sceneConfigSettings.mjs +++ b/module/applications/scene/sceneConfigSettings.mjs @@ -1,8 +1,15 @@ +import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; + export default class DhSceneConfigSettings extends foundry.applications.sheets.SceneConfig { - constructor(options = {}) { + constructor(options) { super(options); - this.daggerheartFlag = new game.system.api.data.scenes.DHScene(this.document.flags.daggerheart); + Hooks.on(socketEvent.Refresh, ({ refreshType }) => { + if (refreshType === RefreshType.Scene) { + this.daggerheartFlag = new game.system.api.data.scenes.DHScene(this.document.flags.daggerheart); + this.render(); + } + }); } static DEFAULT_OPTIONS = { @@ -33,6 +40,11 @@ export default class DhSceneConfigSettings extends foundry.applications.sheets.S static TABS = DhSceneConfigSettings.buildTabs(); + async _preFirstRender(context, options) { + await super._preFirstRender(context, options); + this.daggerheartFlag = new game.system.api.data.scenes.DHScene(this.document.flags.daggerheart); + } + _attachPartListeners(partId, htmlElement, options) { super._attachPartListeners(partId, htmlElement, options); diff --git a/module/applications/ui/sceneNavigation.mjs b/module/applications/ui/sceneNavigation.mjs index dc9ef1e5..735685d1 100644 --- a/module/applications/ui/sceneNavigation.mjs +++ b/module/applications/ui/sceneNavigation.mjs @@ -26,15 +26,13 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi if (!scene.flags.daggerheart) return x; const daggerheartInfo = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart); - const environmentKeys = Object.keys(daggerheartInfo.sceneEnvironments); - const hasEnvironments = environmentKeys.length; + const environments = daggerheartInfo.sceneEnvironments.filter(x => x); + const hasEnvironments = environments.length > 0; return { ...x, hasEnvironments, - environmentImage: hasEnvironments - ? daggerheartInfo.sceneEnvironments[environmentKeys[0]].img - : null, - environments: daggerheartInfo.sceneEnvironments + environmentImage: hasEnvironments ? environments[0].img : null, + environments: environments }; }); context.scenes.active = extendScenes(context.scenes.active); @@ -47,7 +45,7 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi const scene = game.scenes.get(button.dataset.sceneId); const sceneEnvironments = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart).sceneEnvironments; - if (sceneEnvironments.length === 1) { + if (sceneEnvironments.length === 1 || event.shiftKey) { sceneEnvironments[0].sheet.render(true); } else { new ContextMenu( @@ -56,6 +54,15 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi sceneEnvironments.map(environment => ({ name: environment.name, callback: () => { + if (scene.flags.daggerheart.sceneEnvironments[0] !== environment.uuid) { + const newEnvironments = scene.flags.daggerheart.sceneEnvironments; + const newFirst = newEnvironments.splice( + newEnvironments.findIndex(x => x === environment.uuid) + )[0]; + newEnvironments.unshift(newFirst); + scene.update({ 'flags.daggerheart.sceneEnvironments': newEnvironments }); + } + environment.sheet.render({ force: true }); } })), diff --git a/module/data/actor/environment.mjs b/module/data/actor/environment.mjs index 4ed3819e..0aaf8eb0 100644 --- a/module/data/actor/environment.mjs +++ b/module/data/actor/environment.mjs @@ -1,8 +1,11 @@ import BaseDataActor from './base.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import DHEnvironmentSettings from '../../applications/sheets-configs/environment-settings.mjs'; +import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; export default class DhEnvironment extends BaseDataActor { + scenes = new Set(); + /**@override */ static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Environment']; @@ -53,6 +56,31 @@ export default class DhEnvironment extends BaseDataActor { } isItemValid(source) { - return source.type === "feature"; + return source.type === 'feature'; + } + + _onUpdate(changes, options, userId) { + super._onUpdate(changes, options, userId); + for (const scene of this.scenes) { + scene.render(); + } + } + + _onDelete(options, userId) { + super._onDelete(options, userId); + for (const scene of this.scenes) { + if (game.user.isActiveGM) { + const newSceneEnvironments = scene.flags.daggerheart.sceneEnvironments.filter( + x => x !== this.parent.uuid + ); + scene.update({ 'flags.daggerheart.sceneEnvironments': newSceneEnvironments }).then(() => { + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Scene }); + game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { refreshType: RefreshType.TagTeamRoll } + }); + }); + } + } } } diff --git a/module/data/scene/scene.mjs b/module/data/scene/scene.mjs index 720a6c50..3ff74f9f 100644 --- a/module/data/scene/scene.mjs +++ b/module/data/scene/scene.mjs @@ -1,5 +1,8 @@ import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; +/* Foundry does not add any system data for subtyped Scenes. The data model is therefore mainly for reference until this changes. + Needed dataprep and lifetime hooks are handled in documents/scene. +*/ export default class DHScene extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; @@ -16,7 +19,7 @@ export default class DHScene extends foundry.abstract.DataModel { close: new fields.NumberField({ integer: true, label: 'DAGGERHEART.CONFIG.Range.close.name' }), far: new fields.NumberField({ integer: true, label: 'DAGGERHEART.CONFIG.Range.far.name' }) }), - sceneEnvironments: new ForeignDocumentUUIDArrayField({ type: 'Actor' }) + sceneEnvironments: new ForeignDocumentUUIDArrayField({ type: 'Actor', prune: true }) }; } } diff --git a/module/documents/scene.mjs b/module/documents/scene.mjs index c6cdd2c2..fe9b2dfd 100644 --- a/module/documents/scene.mjs +++ b/module/documents/scene.mjs @@ -37,4 +37,30 @@ export default class DhScene extends Scene { this.#sizeSyncBatch.clear(); this.updateEmbeddedDocuments('Token', entries, { animation: { movementSpeed: 1.5 } }); }, 0); + + prepareBaseData() { + super.prepareBaseData(); + + if (this instanceof game.system.api.documents.DhScene) { + const system = new game.system.api.data.scenes.DHScene(this.flags.daggerheart); + + // Register this scene to all environements + for (const environment of system.sceneEnvironments) { + environment.system.scenes?.add(this); + } + } + } + + _onDelete(options, userId) { + super._onDelete(options, userId); + + if (this instanceof game.system.api.documents.DhScene) { + const system = new game.system.api.data.scenes.DHScene(this.flags.daggerheart); + + // Clear this scene from all environments that aren't deleted + for (const environement of system.sceneEnvironments) { + environement?.system?.scenes?.delete(this); + } + } + } } diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index 046f1b68..82ca2e1c 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -37,7 +37,8 @@ export const GMUpdateEvent = { export const RefreshType = { Countdown: 'DhCoundownRefresh', TagTeamRoll: 'DhTagTeamRollRefresh', - EffectsDisplay: 'DhEffectsDisplayRefresh' + EffectsDisplay: 'DhEffectsDisplayRefresh', + Scene: 'DhSceneRefresh' }; export const registerSocketHooks = () => { @@ -92,6 +93,10 @@ export const registerSocketHooks = () => { } } }); + Hooks.on(socketEvent.RefreshDocument, async data => { + const document = await foundry.utils.fromUuid(data.uuid); + document.sheet.render(); + }); }; export const registerUserQueries = () => {