Files
Foundry-VTT-Docker/resources/app/common/documents/scene.mjs

263 lines
12 KiB
JavaScript
Raw Normal View History

2025-01-04 00:34:03 +01:00
import Document from "../abstract/document.mjs";
import {mergeObject} from "../utils/helpers.mjs";
import * as CONST from "../constants.mjs";
import * as documents from "./_module.mjs";
import * as fields from "../data/fields.mjs";
import {TextureData} from "../data/data.mjs";
/**
* @typedef {import("./_types.mjs").SceneData} SceneData
* @typedef {import("../types.mjs").DocumentConstructionContext} DocumentConstructionContext
*/
/**
* The Scene Document.
* Defines the DataSchema and common behaviors for a Scene which are shared between both client and server.
* @mixes SceneData
*/
export default class BaseScene extends Document {
/**
* Construct a Scene document using provided data and context.
* @param {Partial<SceneData>} data Initial data from which to construct the Scene
* @param {DocumentConstructionContext} context Construction context options
*/
constructor(data, context) {
super(data, context);
}
/* -------------------------------------------- */
/* Model Configuration */
/* -------------------------------------------- */
/** @inheritdoc */
static metadata = Object.freeze(mergeObject(super.metadata, {
name: "Scene",
collection: "scenes",
indexed: true,
compendiumIndexFields: ["_id", "name", "thumb", "sort", "folder"],
embedded: {
AmbientLight: "lights",
AmbientSound: "sounds",
Drawing: "drawings",
MeasuredTemplate: "templates",
Note: "notes",
Region: "regions",
Tile: "tiles",
Token: "tokens",
Wall: "walls"
},
label: "DOCUMENT.Scene",
labelPlural: "DOCUMENT.Scenes",
preserveOnImport: [...super.metadata.preserveOnImport, "active"],
schemaVersion: "12.325"
}, {inplace: false}));
/** @inheritdoc */
static defineSchema() {
// Define reusable ambience schema for environment
const environmentData = defaults => new fields.SchemaField({
hue: new fields.HueField({required: true, initial: defaults.hue,
label: "SCENES.ENVIRONMENT.Hue", hint: "SCENES.ENVIRONMENT.HueHint"}),
intensity: new fields.AlphaField({required: true, nullable: false, initial: defaults.intensity,
label: "SCENES.ENVIRONMENT.Intensity", hint: "SCENES.ENVIRONMENT.IntensityHint"}),
luminosity: new fields.NumberField({required: true, nullable: false, initial: defaults.luminosity, min: -1, max: 1,
label: "SCENES.ENVIRONMENT.Luminosity", hint: "SCENES.ENVIRONMENT.LuminosityHint"}),
saturation: new fields.NumberField({required: true, nullable: false, initial: defaults.saturation, min: -1, max: 1,
label: "SCENES.ENVIRONMENT.Saturation", hint: "SCENES.ENVIRONMENT.SaturationHint"}),
shadows: new fields.NumberField({required: true, nullable: false, initial: defaults.shadows, min: 0, max: 1,
label: "SCENES.ENVIRONMENT.Shadows", hint: "SCENES.ENVIRONMENT.ShadowsHint"})
});
// Reuse parts of the LightData schema for the global light
const lightDataSchema = foundry.data.LightData.defineSchema();
return {
_id: new fields.DocumentIdField(),
name: new fields.StringField({required: true, blank: false, textSearch: true}),
// Navigation
active: new fields.BooleanField(),
navigation: new fields.BooleanField({initial: true}),
navOrder: new fields.NumberField({required: true, nullable: false, integer: true, initial: 0}),
navName: new fields.HTMLField({textSearch: true}),
// Canvas Dimensions
background: new TextureData(),
foreground: new fields.FilePathField({categories: ["IMAGE", "VIDEO"]}),
foregroundElevation: new fields.NumberField({required: true, positive: true, integer: true}),
thumb: new fields.FilePathField({categories: ["IMAGE"]}),
width: new fields.NumberField({integer: true, positive: true, initial: 4000}),
height: new fields.NumberField({integer: true, positive: true, initial: 3000}),
padding: new fields.NumberField({required: true, nullable: false, min: 0, max: 0.5, step: 0.05, initial: 0.25}),
initial: new fields.SchemaField({
x: new fields.NumberField({integer: true, required: true}),
y: new fields.NumberField({integer: true, required: true}),
scale: new fields.NumberField({required: true, max: 3, positive: true, initial: 0.5})
}),
backgroundColor: new fields.ColorField({nullable: false, initial: "#999999"}),
// Grid Configuration
grid: new fields.SchemaField({
type: new fields.NumberField({required: true, choices: Object.values(CONST.GRID_TYPES),
initial: () => game.system.grid.type, validationError: "must be a value in CONST.GRID_TYPES"}),
size: new fields.NumberField({required: true, nullable: false, integer: true, min: CONST.GRID_MIN_SIZE,
initial: 100, validationError: `must be an integer number of pixels, ${CONST.GRID_MIN_SIZE} or greater`}),
style: new fields.StringField({required: true, blank: false, initial: "solidLines"}),
thickness: new fields.NumberField({required: true, nullable: false, positive: true, integer: true, initial: 1}),
color: new fields.ColorField({required: true, nullable: false, initial: "#000000"}),
alpha: new fields.AlphaField({initial: 0.2}),
distance: new fields.NumberField({required: true, nullable: false, positive: true,
initial: () => game.system.grid.distance}),
units: new fields.StringField({required: true, initial: () => game.system.grid.units})
}),
// Vision Configuration
tokenVision: new fields.BooleanField({initial: true}),
fog: new fields.SchemaField({
exploration: new fields.BooleanField({initial: true}),
reset: new fields.NumberField({required: false, initial: undefined}),
overlay: new fields.FilePathField({categories: ["IMAGE", "VIDEO"]}),
colors: new fields.SchemaField({
explored: new fields.ColorField({label: "SCENES.FogExploredColor"}),
unexplored: new fields.ColorField({label: "SCENES.FogUnexploredColor"})
})
}),
// Environment Configuration
environment: new fields.SchemaField({
darknessLevel: new fields.AlphaField({initial: 0}),
darknessLock: new fields.BooleanField({initial: false}),
globalLight: new fields.SchemaField({
enabled: new fields.BooleanField({required: true, initial: false}),
alpha: lightDataSchema.alpha,
bright: new fields.BooleanField({required: true, initial: false}),
color: lightDataSchema.color,
coloration: lightDataSchema.coloration,
luminosity: new fields.NumberField({required: true, nullable: false, initial: 0, min: 0, max: 1}),
saturation: lightDataSchema.saturation,
contrast: lightDataSchema.contrast,
shadows: lightDataSchema.shadows,
darkness: lightDataSchema.darkness
}),
cycle: new fields.BooleanField({initial: true}),
base: environmentData({hue: 0, intensity: 0, luminosity: 0, saturation: 0, shadows: 0}),
dark: environmentData({hue: 257/360, intensity: 0, luminosity: -0.25, saturation: 0, shadows: 0})
}),
// Embedded Collections
drawings: new fields.EmbeddedCollectionField(documents.BaseDrawing),
tokens: new fields.EmbeddedCollectionField(documents.BaseToken),
lights: new fields.EmbeddedCollectionField(documents.BaseAmbientLight),
notes: new fields.EmbeddedCollectionField(documents.BaseNote),
sounds: new fields.EmbeddedCollectionField(documents.BaseAmbientSound),
regions: new fields.EmbeddedCollectionField(documents.BaseRegion),
templates: new fields.EmbeddedCollectionField(documents.BaseMeasuredTemplate),
tiles: new fields.EmbeddedCollectionField(documents.BaseTile),
walls: new fields.EmbeddedCollectionField(documents.BaseWall),
// Linked Documents
playlist: new fields.ForeignDocumentField(documents.BasePlaylist),
playlistSound: new fields.ForeignDocumentField(documents.BasePlaylistSound, {idOnly: true}),
journal: new fields.ForeignDocumentField(documents.BaseJournalEntry),
journalEntryPage: new fields.ForeignDocumentField(documents.BaseJournalEntryPage, {idOnly: true}),
weather: new fields.StringField({required: true}),
// Permissions
folder: new fields.ForeignDocumentField(documents.BaseFolder),
sort: new fields.IntegerSortField(),
ownership: new fields.DocumentOwnershipField(),
flags: new fields.ObjectField(),
_stats: new fields.DocumentStatsField()
}
}
/* -------------------------------------------- */
/* Deprecations and Compatibility */
/* -------------------------------------------- */
/**
* Static Initializer Block for deprecated properties.
* @see [Static Initialization Blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks)
*/
static {
const migrations = {
fogExploration: "fog.exploration",
fogReset: "fog.reset",
fogOverlay: "fog.overlay",
fogExploredColor: "fog.colors.explored",
fogUnexploredColor: "fog.colors.unexplored",
globalLight: "environment.globalLight.enabled",
globalLightThreshold: "environment.globalLight.darkness.max",
darkness: "environment.darknessLevel"
};
Object.defineProperties(this.prototype, Object.fromEntries(
Object.entries(migrations).map(([o, n]) => [o, {
get() {
this.constructor._logDataFieldMigration(o, n, {since: 12, until: 14});
return foundry.utils.getProperty(this, n);
},
set(v) {
this.constructor._logDataFieldMigration(o, n, {since: 12, until: 14});
return foundry.utils.setProperty(this, n, v);
},
configurable: true
}])));
}
/* ---------------------------------------- */
/** @inheritdoc */
static migrateData(data) {
/**
* Migration to fog schema fields. Can be safely removed in V14+
* @deprecated since v12
*/
for ( const [oldKey, newKey] of Object.entries({
"fogExploration": "fog.exploration",
"fogReset": "fog.reset",
"fogOverlay": "fog.overlay",
"fogExploredColor": "fog.colors.explored",
"fogUnexploredColor": "fog.colors.unexplored"
}) ) this._addDataFieldMigration(data, oldKey, newKey);
/**
* Migration to global light embedded fields. Can be safely removed in V14+
* @deprecated since v12
*/
this._addDataFieldMigration(data, "globalLight", "environment.globalLight.enabled");
this._addDataFieldMigration(data, "globalLightThreshold", "environment.globalLight.darkness.max",
d => d.globalLightThreshold ?? 1);
/**
* Migration to environment darkness level. Can be safely removed in V14+
* @deprecated since v12
*/
this._addDataFieldMigration(data, "darkness", "environment.darknessLevel");
/**
* Migrate sourceId.
* @deprecated since v12
*/
this._addDataFieldMigration(data, "flags.core.sourceId", "_stats.compendiumSource");
return super.migrateData(data);
}
/* ---------------------------------------- */
/** @inheritdoc */
static shimData(data, options) {
/** @deprecated since v12 */
this._addDataFieldShims(data, {
fogExploration: "fog.exploration",
fogReset: "fog.reset",
fogOverlay: "fog.overlay",
fogExploredColor: "fog.colors.explored",
fogUnexploredColor: "fog.colors.unexplored",
globalLight: "environment.globalLight.enabled",
globalLightThreshold: "environment.globalLight.darkness.max",
darkness: "environment.darknessLevel"
}, {since: 12, until: 14});
return super.shimData(data, options);
}
}