diff --git a/src/foundry/client/pixi/index.d.ts b/src/foundry/client/pixi/index.d.ts index 832446f4f..1d3ed7fd8 100644 --- a/src/foundry/client/pixi/index.d.ts +++ b/src/foundry/client/pixi/index.d.ts @@ -4,6 +4,7 @@ import "./groups"; import "./layer"; import "./layers"; import "./perception"; +import "./placeable"; import "./placeables"; import "./placeables/index"; import "./sources"; diff --git a/src/foundry/client/pixi/perception/perception-manager.d.ts b/src/foundry/client/pixi/perception/perception-manager.d.ts index dd160f536..5db3bcd99 100644 --- a/src/foundry/client/pixi/perception/perception-manager.d.ts +++ b/src/foundry/client/pixi/perception/perception-manager.d.ts @@ -44,10 +44,10 @@ declare global { */ class PerceptionManager extends RenderFlagsMixin(Object) { static RENDER_FLAGS: { - /** @defaultValue `{propagate: ["refreshLighting", "refreshVision"]}` */ + /** @defaultValue `{ propagate: ["refreshLighting", "refreshVision"] }` */ initializeLighting: RenderFlag; - /** @defaultValue `{propagate: ["refreshLightSources"]}` */ + /** @defaultValue `{ propagate: ["refreshLightSources"] }` */ refreshLighting: RenderFlag; /** @defaultValue `{}` */ @@ -59,28 +59,28 @@ declare global { /** @defaultValue `{}` */ refreshPrimary: RenderFlag; - /** @defaultValue `{propagate: ["refreshVision", "refreshTiles", "refreshLighting", "refreshLightSources", "refreshPrimary"]}` */ + /** @defaultValue `{ propagate: ["refreshVision", "refreshTiles", "refreshLighting", "refreshLightSources", "refreshPrimary"] }` */ initializeVision: RenderFlag; - /** @defaultValue `{propagate: ["refreshVisionSources"]}` */ + /** @defaultValue `{ propagate: ["refreshVisionSources"] }` */ refreshVision: RenderFlag; - /** @defaultValue `{propagate: ["refreshSounds"]}` */ + /** @defaultValue `{ propagate: ["refreshSounds"] }` */ initializeSounds: RenderFlag; /** @defaultValue `{}` */ refreshSounds: RenderFlag; - /** @defaultValue `{propagate: ["refreshLightSources", "refreshVisionSources"]}` */ + /** @defaultValue `{ propagate: ["refreshLightSources", "refreshVisionSources"] }` */ refreshTiles: RenderFlag; /** @defaultValue `{}` */ soundFadeDuration: RenderFlag; - /** @defaultValue `{propagate: ["initializeLighting", "initializeVision"]}` */ + /** @defaultValue `{ propagate: ["initializeLighting", "initializeVision"] }` */ identifyInteriorWalls: RenderFlag; - /** @defaultValue `{propagate: ["refreshVision"]}` */ + /** @defaultValue `{ propagate: ["refreshVision"] }` */ forceUpdateFog: RenderFlag; }; diff --git a/src/foundry/client/pixi/placeable.d.ts b/src/foundry/client/pixi/placeable.d.ts index c2f4349d3..62faafd2a 100644 --- a/src/foundry/client/pixi/placeable.d.ts +++ b/src/foundry/client/pixi/placeable.d.ts @@ -2,6 +2,11 @@ import { ConfiguredDocumentClass } from "../../../types/helperTypes"; import { DocumentModificationOptions } from "../../common/abstract/document.mjs"; import { Document } from "../../common/abstract/module.mjs"; +export {}; + +// TODO: Rework the data portions after the data model branch is merged +// CAVEAT: That whole bit gets thrown out with v12 *anyways* as part of the decoupling + declare global { /** * An Abstract Base Class which defines a Placeable Object which represents a Document placed on the Canvas @@ -11,7 +16,7 @@ declare global { any, InstanceType> >, - > extends PIXI.Container { + > extends RenderFlagsMixin(PIXI.Container) { /** * @param document - The Document instance which is represented by this object */ @@ -32,6 +37,7 @@ declare global { /** * The underlying data object which provides the basis for this placeable object + * @deprecated since v10, will be removed in v12 */ data: D["data"]; @@ -56,22 +62,47 @@ declare global { mouseInteractionManager: MouseInteractionManager | null; /** - * An indicator for whether the object is currently controlled + * Allow objects to be culled when off-screen * @defaultValue `false` */ - protected _controlled: boolean; + cullable: boolean; /** - * An indicator for whether the object is currently a hover target + * Identify the official Document name for this PlaceableObject class + * @remarks This is abstract in {@link PlaceableObject}. + */ + static embeddedName: string; + + /** + * The flags declared here are required for all PlaceableObject subclasses to also support. + */ + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag; + + /** @defaultValue `{ propagate: ["refreshState"], alias: true }` */ + refresh: RenderFlag; + + /** @defaultValue `{}` */ + refreshState: RenderFlag; + }; + + /** + * Passthrough certain drag operations on locked objects. * @defaultValue `false` */ - protected _hover: boolean; + protected _dragPassthrough: boolean; /** - * Identify the official Document name for this PlaceableObject class - * @remarks This is abstract in {@link PlaceableObject}. + * Know if a placeable is in the hover-in state. + * @defaultValue `false` */ - static embeddedName: string; + protected _isHoverIn: boolean; + + /** + * The mouse interaction state of this placeable. + */ + get interactionState(): ValueOf | undefined; /** * The bounding box for this PlaceableObject. @@ -90,6 +121,27 @@ declare global { */ get id(): string; + /** + * A unique identifier which is used to uniquely identify elements on the canvas related to this object. + */ + get objectId(): string; + + /** + * The named identified for the source object associated with this PlaceableObject. + * This differs from the objectId because the sourceId is the same for preview objects as for the original. + */ + get sourceId(): string; + + /** + * Is this placeable object a temporary preview? + */ + get isPreview(): boolean; + + /** + * Does there exist a temporary preview of this placeable object? + */ + get hasPreview(): boolean; + /** * The field-of-vision polygon for the object, if it has been computed */ @@ -112,90 +164,71 @@ declare global { get sheet(): "sheet" extends keyof D ? D["sheet"] : FormApplication | null; /** - * Test whether a user can perform a certain interaction with regards to a Placeable Object - * @param user - The User performing the action - * @param action - The named action being attempted - * @returns Does the User have rights to perform the action? + * An indicator for whether the object is currently controlled */ - can( - user: InstanceType>, - action: "HUD" | "configure" | "control" | "view" | "create" | "drag" | "hover" | "update" | "delete" | string, - ): boolean; + get controlled(): boolean; /** - * Can the User access the HUD for this Placeable Object? + * An indicator for whether the object is currently a hover target */ - protected _canHUD(user: InstanceType>, event?: any): boolean; + get hover(): boolean; - /** - * Does the User have permission to configure the Placeable Object? - */ - protected _canConfigure(user: InstanceType>, event?: any): boolean; + set hover(state); - /** - * Does the User have permission to control the Placeable Object? - */ - protected _canControl(user: InstanceType>, event?: any): boolean; + override applyRenderFlags(): void; /** - * Does the User have permission to view details of the Placeable Object? + * Apply render flags before a render occurs. + * @param flags - The render flags which must be applied */ - protected _canView(user: InstanceType>, event?: any): boolean; + protected _applyRenderFlags(flags: PlaceableObject.RenderFlags): void; /** - * Does the User have permission to create the underlying Document? + * Clear the display of the existing object + * @returns The cleared object + * @remarks Some subclasses return void */ - protected _canCreate(user: InstanceType>, event?: any): boolean; + clear(): this | void; - /** - * Does the User have permission to drag this Placeable Object? - */ - protected _canDrag(user: InstanceType>, event?: any): boolean; + override destroy(options?: Parameters[0]): void; /** - * Does the User have permission to hover on this Placeable Object? + * The inner _destroy method which may optionally be defined by each PlaceableObject subclass. + * @param options - Options passed to the initial destroy call */ - protected _canHover(user: InstanceType>, event?: any): boolean; + protected _destroy(options?: PIXI.IDestroyOptions | boolean): void; /** - * Does the User have permission to update the underlying Document? + * Draw the placeable object into its parent container + * @returns The drawn object */ - protected _canUpdate(user: InstanceType>, event?: any): boolean; + draw(options: Record): Promise; /** - * Does the User have permission to delete the underlying Document? + * The inner _draw method which must be defined by each PlaceableObject subclass. + * @param options - Options which may modify the draw workflow */ - protected _canDelete(user: InstanceType>, event?: any): boolean; + protected abstract _draw(options?: Record): Promise; /** - * Clear the display of the existing object - * @returns The cleared object + * Refresh all incremental render flags for the PlaceableObject. + * This method is no longer used by the core software but provided for backwards compatibility. + * @param options - Options which may modify the refresh workflow + * @returns The refreshed object */ - clear(): this; + refresh(options: Record): this; /** - * Clone the placeable object, returning a new object with identical attributes - * The returned object is non-interactive, and has no assigned ID - * If you plan to use it permanently you should call the create method - * - * @returns A new object with identical data + * Update the quadtree. */ - clone(): this; + protected _updateQuadtree(): void; - override destroy(options?: Parameters[0]): void; + /* -------------------------------------------- */ /** - * Draw the placeable object into its parent container - * @returns The drawn object + * Get the target opacity that should be used for a Placeable Object depending on its preview state. */ - abstract draw(): Promise; - - /** - * Refresh the current display state of the Placeable Object - * @returns The refreshed object - * @remarks `void` has been added because of `Drawing.refresh` - */ - abstract refresh(): this | void; + protected _getTargetAlpha(): number; /** * Register pending canvas operations which should occur after a new PlaceableObject of this type is created @@ -204,7 +237,7 @@ declare global { /** * Define additional steps taken when an existing placeable object of this type is updated with new data - * @remarks Called without options and userId in Drowing._onUpdate + * @remarks Called without options and userId in Drawing._onUpdate */ protected _onUpdate( changed: DeepPartial, @@ -221,7 +254,7 @@ declare global { * Assume control over a PlaceableObject, flagging it as controlled and enabling downstream behaviors * @param options - Additional options which modify the control request * (default: `{}`) - * @returns A flag denoting whether or not control was successful + * @returns A flag denoting whether control was successful */ control(options?: PlaceableObject.ControlOptions): boolean; @@ -245,6 +278,14 @@ declare global { */ protected _onRelease(options?: PlaceableObject.ReleaseOptions): void; + /** + * Clone the placeable object, returning a new object with identical attributes. + * The returned object is non-interactive, and has no assigned ID. + * If you plan to use it permanently you should call the create method. + * @returns A new object with identical data + */ + clone(): PlaceableObject; + /** * Rotate the PlaceableObject to a certain angle of facing * @param angle - The desired angle of rotation @@ -264,7 +305,29 @@ declare global { * (default: `0`) * @returns The new rotation angle for the object */ - protected _updateRotation({ angle, delta, snap }?: RotationOptions): number; + protected _updateRotation({ + angle, + delta, + snap, + }?: { + /** + * An explicit angle, either this or delta must be provided + * @defaultValue `undefined` + */ + angle?: number; + + /** + * A relative angle delta, either this or the angle must be provided + * @defaultValue `0` + */ + delta?: number; + + /** + * A precision (in degrees) to which the resulting angle should snap. Default is 0. + * @defaultValue `0` + */ + snap?: number; + }): number; /** * Obtain a shifted position for the Placeable Object @@ -285,78 +348,214 @@ declare global { protected _createInteractionManager(): NonNullable; /** - * Actions that should be taken for this Placeable Object when a mouseover event occurs - * @see MouseInteractionManager#_handleMouseOver + * Test whether a user can perform a certain interaction regarding a Placeable Object + * @param user - The User performing the action + * @param action - The named action being attempted + * @returns Does the User have rights to perform the action? + */ + can( + user: InstanceType>, + action: "HUD" | "configure" | "control" | "view" | "create" | "drag" | "hover" | "update" | "delete" | string, + ): boolean; + + /** + * Can the User access the HUD for this Placeable Object? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canHUD(user: InstanceType>, event?: PIXI.FederatedEvent): boolean; + + /** + * Does the User have permission to configure the Placeable Object? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canConfigure( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + /** + * Does the User have permission to control the Placeable Object? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canControl( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + /** + * Does the User have permission to view details of the Placeable Object? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canView(user: InstanceType>, event?: PIXI.FederatedEvent): boolean; + + /** + * Does the User have permission to create the underlying Document? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canCreate( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + /** + * Does the User have permission to drag this Placeable Object? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canDrag(user: InstanceType>, event?: PIXI.FederatedEvent): boolean; + + /** + * Does the User have permission to hover on this Placeable Object? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canHover(user: InstanceType>, event?: PIXI.FederatedEvent): boolean; + + /** + * Does the User have permission to update the underlying Document? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canUpdate( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + /** + * Does the User have permission to delete the underlying Document? + * @param user - The User performing the action. + * @param event - The event object. + * @returns The returned status. + */ + protected _canDelete( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + /** + * Actions that should be taken for this Placeable Object when a mouseover event occurs. + * Hover events on PlaceableObject instances allow event propagation by default. + * @see MouseInteractionManager##handleMouseOver * @param event - The triggering canvas interaction event * @param options - Options which customize event handling * (default: `{}`) + * @returns True if the event was handled, otherwise false */ - protected _onHoverIn(event: PIXI.FederatedEvent, options?: HoverInOptions): false | void; + protected _onHoverIn(event: PIXI.FederatedEvent, options?: PlaceableObject.HoverInOptions): false | void; /** * Actions that should be taken for this Placeable Object when a mouseout event occurs + * @see MouseInteractionManager##handleMouseOut * @param event - The triggering canvas interaction event + * @returns True if the event was handled, otherwise false + */ + protected _onHoverOut(event: PIXI.FederatedEvent): boolean | void; + + /** + * Should the placeable propagate left click downstream? + * @defaultValue `false` */ - protected _onHoverOut(event: PIXI.FederatedEvent): false | void; + protected _propagateLeftClick(event: PIXI.FederatedEvent): boolean; /** * Callback actions which occur on a single left-click event to assume control of the object - * @see MouseInteractionManager#_handleClickLeft + * @see MouseInteractionManager##handleClickLeft * @param event - The triggering canvas interaction event */ - protected _onClickLeft(event: PIXI.FederatedEvent): boolean | void; + protected _onClickLeft(event: PIXI.FederatedEvent): void; /** * Callback actions which occur on a double left-click event to activate - * @see MouseInteractionManager#_handleClickLeft2 + * @see MouseInteractionManager##handleClickLeft2 * @param event - The triggering canvas interaction event */ protected _onClickLeft2(event: PIXI.FederatedEvent): void; /** * Callback actions which occur on a single right-click event to configure properties of the object - * @see MouseInteractionManager#_handleClickRight + * @see MouseInteractionManager##handleClickRight * @param event - The triggering canvas interaction event */ protected _onClickRight(event: PIXI.FederatedEvent): void; /** * Callback actions which occur on a double right-click event to configure properties of the object - * @see MouseInteractionManager#_handleClickRight2 + * @see MouseInteractionManager##handleClickRight2 * @param event - The triggering canvas interaction event */ protected _onClickRight2(event: PIXI.FederatedEvent): void; /** * Callback actions which occur when a mouse-drag action is first begun. - * @see MouseInteractionManager#_handleDragStart + * @see MouseInteractionManager##handleDragStart * @param event - The triggering canvas interaction event */ protected _onDragLeftStart(event: PIXI.FederatedEvent): void; + /** + * Begin a drag operation from the perspective of the preview clone. + * Modify the appearance of both the clone (this) and the original (_original) object. + */ + protected _onDragStart(): void; + + /** + * Conclude a drag operation from the perspective of the preview clone. + * Modify the appearance of both the clone (this) and the original (_original) object. + */ + protected _onDragEnd(): void; + /** * Callback actions which occur on a mouse-move operation. - * @see MouseInteractionManager#_handleDragMove + * @see MouseInteractionManager##handleDragMove * @param event - The triggering canvas interaction event */ protected _onDragLeftMove(event: PIXI.FederatedEvent): void; /** * Callback actions which occur on a mouse-move operation. - * @see MouseInteractionManager#_handleDragDrop + * @see MouseInteractionManager##handleDragDrop * @param event - The triggering canvas interaction event */ protected _onDragLeftDrop(event: PIXI.FederatedEvent): unknown; /** * Callback actions which occur on a mouse-move operation. - * @see MouseInteractionManager#_handleDragCancel + * @see MouseInteractionManager##handleDragCancel * @param event - The triggering mouse click event */ - protected _onDragLeftCancel(event: MouseEvent): void; + protected _onDragLeftCancel(event: PIXI.FederatedEvent): void; + + /** + * Callback action which occurs on a long press. + * @see MouseInteractionManager##handleLongPress + * @param event - The triggering canvas interaction event + * @param origin - The local canvas coordinates of the mousepress. + */ + protected _onLongPress(event: PIXI.FederatedEvent, origin: PIXI.Point): void; } namespace PlaceableObject { + interface RenderFlags { + redraw: boolean; + + refresh: boolean; + + refreshState: boolean; + } + interface ControlOptions { /** * Release any other controlled objects first @@ -367,6 +566,14 @@ declare global { interface ReleaseOptions { trigger?: boolean; } + + interface HoverInOptions { + /** + * Trigger hover-out behavior on sibling objects + * @defaultValue `false` + */ + hoverOutOthers: boolean; + } } } @@ -383,32 +590,3 @@ interface Vision { */ los?: PointSourcePolygon | undefined; } - -interface RotationOptions { - /** - * An explicit angle, either this or delta must be provided - * @defaultValue `undefined` - */ - angle?: number; - - /** - * A relative angle delta, either this or the angle must be provided - * @defaultValue `0` - */ - delta?: number; - - /** - * A precision (in degrees) to which the resulting angle should snap. Default is 0. - * @defaultValue `0` - */ - snap?: number; -} - -interface HoverInOptions { - /** - * Trigger hover-out behavior on sibling objects - * - * @defaultValue `true` - */ - hoverOutOthers: boolean; -} diff --git a/src/foundry/client/pixi/placeables/drawing.d.ts b/src/foundry/client/pixi/placeables/drawing.d.ts index f3edfcea4..7c10dfb5f 100644 --- a/src/foundry/client/pixi/placeables/drawing.d.ts +++ b/src/foundry/client/pixi/placeables/drawing.d.ts @@ -1,63 +1,69 @@ import { ConfiguredDocumentClass, ConfiguredDocumentClassForName } from "../../../../types/helperTypes"; import { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; +export {}; + declare global { /** * The Drawing object is an implementation of the PlaceableObject container. * Each Drawing is a placeable object in the DrawingsLayer. */ - class Drawing extends PlaceableObject>> { + // TODO: Replace `any` with `InstanceType>` + class Drawing extends PlaceableObject { constructor(document: InstanceType>); + /** - * @remarks Not used for `Drawing` + * Each Drawing object belongs to the DrawingsLayer + * @remarks it's possible this shouldn't be here and is some data model thing */ - controlIcon: null; + get layer(): DrawingsLayer; /** - * The inner drawing container - * @defaultValue `null` + * Each Drawing object provides an interface for a DrawingDocument */ - drawing: PIXI.Container | null; + document: DrawingDocument; /** - * The primary drawing shape - * @defaultValue `null` + * The border frame and resizing handles for the drawing. */ - shape: PIXI.Graphics | null; + frame: PIXI.Container; /** - * Text content, if included + * A text label that may be displayed as part of the interface layer for the Drawing. * @defaultValue `null` */ - text: PIXI.Text | null; + text: PreciseText | null; /** - * The Graphics outer frame and handles + * The primary drawing shape * @defaultValue `null` */ - frame: PIXI.Container | null; + shape: DrawingShape; - /** - * Internal timestamp for the previous freehand draw time, to limit sampling - * @defaultValue `0` - * @internal - */ - protected _drawTime: number; + static override embeddedName: "Drawing"; - /** - * @defaultValue `0` - * @internal - */ - protected _sampleTime: number; + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; - /** - * Internal flag for the permanent points of the polygon - * @defaultValue `foundry.utils.deepClone(this.data.points || [])` - * @internal - */ - protected _fixedPoints: Array<[x: number, y: number]>; + /** @defaultValue `{ propagate: ["refreshState", "refreshShape"], alias: true }` */ + refresh: RenderFlag>; - static override embeddedName: "Drawing"; + /** @defaultValue `{ propagate: ["refreshFrame"] }` */ + refreshState: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshFrame", "refreshText", "refreshMesh"] }` */ + refreshShape: RenderFlag>; + + /** @defaultValue `{}` */ + refreshFrame: RenderFlag>; + + /** @defaultValue `{}` */ + refreshText: RenderFlag>; + + /** @defaultValue `{}` */ + refreshMesh: RenderFlag>; + }; /** * The rate at which points are sampled (in milliseconds) during a freehand drawing workflow @@ -65,106 +71,84 @@ declare global { */ static FREEHAND_SAMPLE_RATE: number; - override get bounds(): Rectangle; - /** - * A Boolean flag for whether or not the Drawing utilizes a tiled texture background + * A convenience reference to the possible shape types. + * TODO: Replace post-data model with the static enum reference */ - get isTiled(): boolean; + static readonly SHAPE_TYPES: string; // ValueOf<(typeof foundry.data.ShapeData)["TYPES"]> - /** - * A Boolean flag for whether or not the Drawing is a Polygon type (either linear or freehand) - */ - get isPolygon(): boolean; + override get bounds(): Rectangle; - override draw(): Promise; + override get center(): PIXI.Point; /** - * Clean the drawing data to constrain its allowed position - * @internal + * A Boolean flag for whether the Drawing utilizes a tiled texture background */ - protected _cleanData(): void; + get isTiled(): boolean; /** - * Create the components of the drawing element, the drawing container, the drawn shape, and the overlay text + * A Boolean flag for whether the Drawing is a Polygon type (either linear or freehand)? */ - protected _createDrawing(): void; - - /** - * Create elements for the foreground text - * @internal - */ - protected _createText(): PreciseText; + get isPolygon(): boolean; /** - * Create elements for the Drawing border and handles - * @internal + * Does the Drawing have text that is displayed? */ - protected _createFrame(): void; - - override refresh(): void; + get hasText(): boolean; /** - * Draw rectangular shapes - * @internal + * The shape type that this Drawing represents. A value in Drawing.SHAPE_TYPES. + * TODO: Replace post-data model with the static enum reference */ - protected _drawRectangle(): void; + get type(): string; // // ValueOf<(typeof foundry.data.ShapeData)["TYPES"]> - /** - * Draw ellipsoid shapes - * @internal - */ - protected _drawEllipse(): void; + override clear(): this; /** - * Draw polygonal shapes - * @internal + * @param options - unused */ - protected _drawPolygon(): void; + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; /** - * Draw freehand shapes with bezier spline smoothing - * @internal + * @param options - unused */ - protected _drawFreehand(): void; + protected override _draw(options?: Record): Promise; /** - * Attribution: The equations for how to calculate the bezier control points are derived from Rob Spencer's article: - * http://scaledinnovation.com/analytics/splines/aboutSplines.html - * @param factor - The smoothing factor - * @param previous - The prior point - * @param point - The current point - * @param next - The next point - * @internal + * Prepare the text style used to instantiate a PIXI.Text or PreciseText instance for this Drawing document. */ - protected _getBezierControlPoints( - factor: number, - previous: [number, number], - point: [number, number], - next: [number, number], - ): { - cp1: { - x: number; - y: number; - }; - next_cp0: { - x: number; - y: number; - }; - }; + protected _getTextStyle(): PIXI.TextStyle; - /** - * Refresh the boundary frame which outlines the Drawing shape - * @internal - */ - protected _refreshFrame({ x, y, width, height }: Rectangle): void; + protected override _applyRenderFlags(flags: Drawing.RenderFlags): void; /** * Add a new polygon point to the drawing, ensuring it differs from the last one - * @param temporary - (default: `true`) + * @param position - The drawing point to add + * @param options - Options which configure how the point is added * @internal */ - protected _addPoint(position: Point, temporary?: boolean): void; + protected _addPoint( + position: Point, + options?: { + /** + * Should the point be rounded to integer coordinates? + * @defaultValue `false` + */ + round?: boolean; + + /** + * Should the point be snapped to grid precision? + * @defaultValue `false` + */ + snap?: boolean; + + /** + * Is this a temporary control point? + * @defaultValue `false` + */ + temporary?: boolean; + }, + ): void; /** * Remove the last fixed point from the polygon @@ -172,20 +156,17 @@ declare global { */ protected _removePoint(): void; - protected override _onControl(options: PlaceableObject.ControlOptions & { isNew?: boolean }): void; + protected override _onControl(options: PlaceableObject.ControlOptions & Drawing.TextEditingOptions): void; protected override _onRelease(options: PlaceableObject.ReleaseOptions): void; protected override _onDelete(options: DocumentModificationOptions, userId: string): void; - /** - * Handle text entry in an active text tool - * @internal - */ - protected _onDrawingTextKeydown(event: KeyboardEvent): void; - + // TODO: Replace after data model protected override _onUpdate(data: DeepPartial): void; + override activateListeners(): void; + /** * @param event - unused */ @@ -195,10 +176,9 @@ declare global { * @param user - unused * @param event - unused */ + // TODO: Replace User reference after data model protected override _canConfigure(user: InstanceType>, event?: any): boolean; - override activateListeners(): void; - /** * Handle mouse movement which modifies the dimensions of the drawn shape * @internal @@ -211,7 +191,7 @@ declare global { protected override _onDragLeftDrop(event: PIXI.FederatedEvent): Promise; - protected override _onDragLeftCancel(event: MouseEvent): void; + protected override _onDragLeftCancel(event: PIXI.FederatedEvent): void; /** * Handle mouse-over event on a control handle @@ -228,14 +208,14 @@ declare global { protected _onHandleHoverOut(event: PIXI.FederatedEvent): void; /** - * When we start a drag event - create a preview copy of the Tile for re-positioning + * When clicking the resize handle, initialize the drag property. * @param event - The mousedown event * @internal */ protected _onHandleMouseDown(event: PIXI.FederatedEvent): void; /** - * Handle the beginning of a drag event on a resize handle + * Starting the resize handle drag event, initialize the original data. * @internal */ protected _onHandleDragStart(event: PIXI.FederatedEvent): void; @@ -263,10 +243,11 @@ declare global { protected _onHandleDragCancel(event: PIXI.FederatedEvent): void; /** - * Apply a vectorized rescaling transformation for the drawing data + * Get a vectorized rescaling transformation for drawing data and dimensions passed in parameter * @param original - The original drawing data * @param dx - The pixel distance dragged in the horizontal direction * @param dy - The pixel distance dragged in the vertical direction + * @returns The adjusted shape data * @internal */ protected _rescaleDimensions( @@ -277,7 +258,7 @@ declare global { /** * Adjust the location, dimensions, and points of the Drawing before committing the change - * @param data - The Drawing data pending update + * @param data - The DrawingData pending update * @returns The adjusted data * @remarks This is intentionally public because it is called by the DrawingsLayer * @internal @@ -285,5 +266,28 @@ declare global { static normalizeShape( data: Pick, ): Pick; + + /** + * @remarks Not used + */ + controlIcon: null; + } + + namespace Drawing { + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshShape: boolean; + + refreshFrame: boolean; + + refreshText: boolean; + + refreshMesh: boolean; + } + + interface TextEditingOptions { + forceTextEditing?: boolean; + + isNew?: boolean; + } } } diff --git a/src/foundry/client/pixi/placeables/index.d.ts b/src/foundry/client/pixi/placeables/index.d.ts index 1f5e04f07..3d383f8d4 100644 --- a/src/foundry/client/pixi/placeables/index.d.ts +++ b/src/foundry/client/pixi/placeables/index.d.ts @@ -1,3 +1,4 @@ +import "./primary-canvas-objects"; import "./drawing"; import "./light"; import "./note"; diff --git a/src/foundry/client/pixi/placeables/light.d.ts b/src/foundry/client/pixi/placeables/light.d.ts index a253f7f30..50c8a9257 100644 --- a/src/foundry/client/pixi/placeables/light.d.ts +++ b/src/foundry/client/pixi/placeables/light.d.ts @@ -1,9 +1,13 @@ import type { ConfiguredDocumentClassForName } from "../../../../types/helperTypes"; import { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; +export {}; + declare global { /** * An AmbientLight is an implementation of PlaceableObject which represents a dynamic light source within the Scene. + * @see {@link AmbientLightDocument} + * @see {@link LightingLayer} */ class AmbientLight extends PlaceableObject>> { constructor(document: InstanceType>); @@ -21,6 +25,23 @@ declare global { static override embeddedName: "AmbientLight"; + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshField"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshPosition", "refreshState"] }` */ + refreshField: RenderFlag>; + + /** @defaultValue `{}` */ + refreshPosition: RenderFlag>; + + /** @defaultValue `{}` */ + refreshState: RenderFlag>; + }; + override get bounds(): PIXI.Rectangle; /** @@ -49,37 +70,50 @@ declare global { get brightRadius(): number; /** - * Return whether the light source is currently visible in the scene + * Is this Ambient Light currently visible? By default, true only if the source actively emits light. + * @remarks Backwards-compatible wrapper for this.emitsLight */ get isVisible(): boolean; - override draw(): Promise; + /** + * Does this Ambient Light actively emit light given its properties and the current darkness level of the Scene? + */ + get emitsLight(): boolean; - override destroy(options?: Parameters[0]): void; + /** + * @param options - unused + */ + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; /** - * Draw the ControlIcon for the AmbientLight - * @internal + * @param options - unused */ - protected _drawControlIcon(): ControlIcon; + protected override _draw(options?: Record): Promise; - override refresh(): this; + protected override _applyRenderFlags(flags: AmbientLight.RenderFlags): void; /** * Refresh the display of the ControlIcon for this AmbientLight source */ refreshControl(): void; - /** - * The named identified for the source object associated with this light - */ - get sourceId(): string; - /** * Update the source object associated with this light - * @param options - (default: `{}}`) + * @param options - Options which modify how the source is updated */ - updateSource(options?: AmbientLight.UpdateSourceOptions | undefined): void; + updateSource(options?: { + /** + * Defer updating perception to manually update it later + * @defaultValue `false` + */ + defer?: boolean; + + /** + * Indicate that this light source has been deleted + * @defaultValue `false` + */ + deleted?: boolean; + }): void; protected override _onCreate( data: foundry.data.AmbientLightData["_source"], @@ -105,22 +139,14 @@ declare global { protected override _onDragLeftMove(event: PIXI.FederatedEvent): void; - protected override _onDragLeftCancel(event: MouseEvent): void; + protected override _onDragLeftCancel(event: PIXI.FederatedEvent): void; } namespace AmbientLight { - interface UpdateSourceOptions { - /** - * Defer refreshing the LightingLayer to manually call that refresh later. - * @defaultValue `false` - */ - defer?: boolean | undefined; + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshField: boolean; - /** - * Indicate that this light source has been deleted. - * @defaultValue `false` - */ - deleted?: boolean | undefined; + refreshPosition: boolean; } } } diff --git a/src/foundry/client/pixi/placeables/note.d.ts b/src/foundry/client/pixi/placeables/note.d.ts index d6ad6e0d3..54c3d2a57 100644 --- a/src/foundry/client/pixi/placeables/note.d.ts +++ b/src/foundry/client/pixi/placeables/note.d.ts @@ -1,14 +1,39 @@ import type { ConfiguredDocumentClass, ConfiguredDocumentClassForName } from "../../../../types/helperTypes"; -import { HoverInOptions } from "../placeable"; + +export {}; + +type JournalEntryPage = unknown; declare global { /** * A Note is an implementation of PlaceableObject which represents an annotated location within the Scene. * Each Note links to a JournalEntry document and represents its location on the map. + * @see {@link NoteDocument} + * @see {@link NotesLayer} */ class Note extends PlaceableObject>> { static override embeddedName: "Note"; + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshState", "refreshPosition", "refreshText"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshVisibility"] }` */ + refreshPosition: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshVisibility"] }` */ + refreshState: RenderFlag>; + + /** @defaultValue `{}` */ + refreshVisibility: RenderFlag>; + + /** @defaultValue `{}` */ + refreshText: RenderFlag>; + }; + override get bounds(): Rectangle; /** @@ -16,6 +41,11 @@ declare global { */ get entry(): InstanceType>; + /** + * The specific JournalEntryPage within the associated JournalEntry referenced by this Note. + */ + get page(): JournalEntryPage; + /** * The text label used to annotate this Note */ @@ -33,24 +63,34 @@ declare global { */ get isVisible(): boolean; - override draw(): Promise; + /** + * @param options - unused + */ + protected override _draw(options?: Record): Promise; /** - * Draw the ControlIcon for the Map Note + * Draw the ControlIcon for the Map Note. + * This method replaces any prior controlIcon with the new one. */ protected _drawControlIcon(): ControlIcon; /** - * Draw the map note Tooltip as a Text object + * Draw the map note Tooltip as a Text object. + * This method replaces any prior text with the new one. */ - protected _drawTooltip(): PreciseText; + protected _drawTooltip(): PIXI.Text; /** * Define a PIXI TextStyle object which is used for the tooltip displayed for this Note */ protected _getTextStyle(): PIXI.TextStyle; - override refresh(): this; + protected override _applyRenderFlags(flags: Note.RenderFlags): void; + + /** + * Refresh the visibility. + */ + protected _refreshVisibility(): void; protected override _onUpdate(changed: DeepPartial): void; @@ -58,10 +98,18 @@ declare global { protected override _canView(user: InstanceType>): boolean; - protected override _onHoverIn(event: PIXI.FederatedEvent, options?: HoverInOptions): false | void; - - protected override _onHoverOut(event: PIXI.FederatedEvent): false | void; + protected override _onHoverIn(event: PIXI.FederatedEvent, options?: PlaceableObject.HoverInOptions): false | void; protected override _onClickLeft2(event: PIXI.FederatedEvent): void; } + + namespace Note { + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshPosition: boolean; + + refreshVisibility: boolean; + + refreshText: boolean; + } + } } diff --git a/src/foundry/client/pixi/placeables/primary-canvas-objects/drawing-shape.d.ts b/src/foundry/client/pixi/placeables/primary-canvas-objects/drawing-shape.d.ts new file mode 100644 index 000000000..86d63cd5f --- /dev/null +++ b/src/foundry/client/pixi/placeables/primary-canvas-objects/drawing-shape.d.ts @@ -0,0 +1,143 @@ +export {}; + +declare global { + /** + * A special subclass of PIXI.Container used to represent a Drawing in the PrimaryCanvasGroup. + */ + class DrawingShape extends PrimaryCanvasObjectMixin(PIXI.Graphics) { + /** + * Sorting values to deal with ties. + */ + static PRIMARY_SORT_ORDER: number; + + /** + * @defaultValue + * ```js + * return foundry.utils.mergeObject(super.defaultData, { + * shape: { + * type: "", + * width: 0, + * height: 0, + * radius: null, + * points: [] + * }, + * bezierFactor: 0, + * fillType: 0, + * fillColor: 0x7C7C7C, + * fillAlpha: 0.5, + * strokeWidth: 8, + * strokeColor: 0xFFFFFF, + * strokeAlpha: 1, + * text: "New Text", + * fontFamily: "Signika", + * fontSize: 48, + * textColor: 0xFFFFFF, + * textAlpha: 1 + * }) + * ``` + */ + static override get defaultData(): DrawingShape.PrimaryCanvasObjectDrawingShapeData & PrimaryCanvasObject.Data; + + override refresh(): void; + + override setPosition(): void; + + protected override _getCanvasDocumentData(data: Document): unknown; + + /** + * Draw rectangular shapes. + */ + protected _drawRectangle(): void; + + /** + * Draw ellipsoid shapes. + */ + protected _drawEllipse(): void; + + /** + * Draw polygonal shapes. + */ + protected _drawPolygon(): void; + + /** + * Draw freehand shapes with bezier spline smoothing. + */ + protected _drawFreehand(): void; + } + + namespace DrawingShape { + type PrimaryCanvasObjectDrawingShapeData = { + /** The shape */ + shape: object; + + /** The x-coordinate of the PCO location */ + x: number; + + /** The y-coordinate of the PCO location */ + y: number; + + /** The z-index of the PCO */ + z: number; + + /** The bezier factor */ + bezierFactor: number; + + /** The fill type */ + fillType: number; + + /** The fill color */ + fillColor: number; + + /** The fill alpha */ + fillAlpha: number; + + /** The stroke width */ + strokeWidth: number; + + /** The stroke color */ + strokeColor: number; + + /** The stroke alpha */ + strokeAlpha: number; + + /** The text */ + text: string; + + /** The text font family */ + fontFamily: string; + + /** The font size */ + fontSize: number; + + /** The text color */ + textColor: number; + + /** The text alpha */ + textAlpha: number; + + /** The rotation of this PCO */ + rotation: number; + + /** The PCO is hidden? */ + hidden: boolean; + + /** The elevation of the PCO */ + elevation: number; + + /** The sort key that resolves ties among the same elevation */ + sort: number; + + /** The PCO is considered as a roof? */ + roof: boolean; + + /** The PCO is considered as overhead? */ + overhead: boolean; + + /** The occlusion object for this PCO */ + occlusion: object; + + /** The data texture values */ + texture: object; + }; + } +} diff --git a/src/foundry/client/pixi/placeables/primary-canvas-objects/index.d.ts b/src/foundry/client/pixi/placeables/primary-canvas-objects/index.d.ts new file mode 100644 index 000000000..371b7ee9a --- /dev/null +++ b/src/foundry/client/pixi/placeables/primary-canvas-objects/index.d.ts @@ -0,0 +1,5 @@ +import "./drawing-shape"; +import "./occludable-object"; +import "./primary-canvas-object"; +import "./tile-mesh"; +import "./token-mesh"; diff --git a/src/foundry/client/pixi/placeables/primary-canvas-objects/occludable-object.d.ts b/src/foundry/client/pixi/placeables/primary-canvas-objects/occludable-object.d.ts new file mode 100644 index 000000000..ac34af736 --- /dev/null +++ b/src/foundry/client/pixi/placeables/primary-canvas-objects/occludable-object.d.ts @@ -0,0 +1,167 @@ +import type { OCCLUSION_MODES } from "../../../../common/constants.mjs"; + +export {}; + +declare class OccludableObject { + constructor(...args: any[]); + + /** + * @defaultValue + * ```js + * return foundry.utils.mergeObject(super.defaultData, { + * roof: false, + * occlusion: { + * mode: CONST.OCCLUSION_MODES.NONE, + * alpha: 0, + * radius: null + * } + * }) + * ``` + */ + static get defaultData(): OccludableObject.Data; + + /** + * Contains : + * - the bounds of the texture data + * - the cached mapping of non-transparent pixels (if roof) + * - the filtered render texture (if roof) + */ + protected _textureData: { + minX: number; + minY: number; + maxX: number; + maxY: number; + pixels: Uint8Array; + texture: PIXI.RenderTexture; + }; + + /** + * A flag which tracks whether the primary canvas object is currently in an occluded state. + * @defaultValue `false` + */ + occluded: boolean; + + /** + * Force or cancel the rendering of the PCO depth. If undefined, the underlying logic decide. + * @defaultValue `false` + */ + forceRenderDepth: boolean; + + /** + * Is this occludable object... occludable? + */ + get isOccludable(): boolean; + + /** + * Should this PCO render its depth? + */ + get shouldRenderDepth(): boolean; + + /** + * Debounce assignment of the PCO occluded state to avoid cases like animated token movement which can rapidly + * change PCO appearance. + * Uses a 50ms debounce threshold. + */ + debounceSetOcclusion: (occluded: boolean) => void; + + /** + * Compute and returns the normal and occlusion alpha for this occludable object. + */ + protected _getOcclusionAlpha(): { alphaNormal: number; alphaOccluded: number }; + + /** + * Refresh the appearance of the occlusion state for tiles which are affected by a Token beneath them. + */ + refreshOcclusion(): void; + + /** + * Render the depth of this primary canvas object. + */ + renderDepthData(renderer: PIXI.Renderer): void; + + /** + * Process the PCO texture : + * Use the texture to create a cached mapping of pixel alpha for this Tile with real base texture size. + * Cache the bounding box of non-transparent pixels for the un-rotated shape. + */ + updateTextureData(): { minX: number; minY: number; maxX: number; maxY: number; pixels: Uint8Array | undefined }; + + /** + * Test whether a specific Token occludes this PCO. + * Occlusion is tested against 9 points, the center, the four corners-, and the four cardinal directions + * @param token - The Token to test + * @param options - Additional options that affect testing + * @returns Is the Token occluded by the PCO? + */ + testOcclusion( + token: Token, + options?: { + /** Test corners of the hit-box in addition to the token center? */ + corners?: boolean; + }, + ): boolean; + + /** + * Test whether the PCO pixel data contains a specific point in canvas space + * @param alphaThreshold - Value from which the pixel is taken into account, in the range [0, 1]. + * (default: `0.75`) + */ + containsPixel(x: number, y: number, alphaThreshold?: number): boolean; + + /** + * Get alpha value at specific canvas coordinate. + * @returns The alpha value (-1 if outside of the bounds) or null if no mesh or texture is present. + */ + getPixelAlpha(x: number, y: number): number | null; + + /** + * Get PCO alpha map texture coordinate with canvas coordinate + * @param testX - Canvas x coordinate. + * @param testY - Canvas y coordinate. + * @returns The texture `{x, y}` coordinates, or null if not able to do the conversion. + */ + protected _getTextureCoordinate(testX: number, testY: number): { x: number; y: number } | null; + + /** + * Compute the alpha-based bounding box for the tile, including an angle of rotation. + * @internal + */ + protected _getAlphaBounds(): PIXI.Rectangle; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks "PrimaryCanvasObject#renderOcclusion is deprecated in favor of PrimaryCanvasObject#renderDepth" + */ + renderOcclusion(renderer: PIXI.Renderer): void; +} + +declare global { + namespace OccludableObject { + type Data = { + /** + * The PCO is considered as a roof? + * @defaultValue false + */ + roof: boolean; + + /** The occlusion object for this PCO */ + occlusion: { + /** @defaultValue `CONST.OCCLUSION_MODES.NONE` */ + mode: OCCLUSION_MODES; + /** @defaultValue `0` */ + alpha: number; + /** @defaultValue `null` */ + radius: number | null; + }; + } & PrimaryCanvasObject.Data; + } + + /** + * A mixin which decorates a DisplayObject with depth and/or occlusion properties. + * @param DisplayObject - The parent DisplayObject class being mixed + * @returns A DisplayObject subclass mixed with OccludableObject features + */ + function OccludableObjectMixin( + DisplayObject: BaseClass, + ): Mixin>>; +} diff --git a/src/foundry/client/pixi/placeables/primary-canvas-objects/primary-canvas-object.d.ts b/src/foundry/client/pixi/placeables/primary-canvas-objects/primary-canvas-object.d.ts new file mode 100644 index 000000000..386146f4e --- /dev/null +++ b/src/foundry/client/pixi/placeables/primary-canvas-objects/primary-canvas-object.d.ts @@ -0,0 +1,147 @@ +import type { DisplayObject } from "pixi.js"; + +export {}; + +type ClientDocument = unknown; + +declare class PrimaryCanvasObject { + constructor( + placeableObjectOrData: Document | PrimaryCanvasObject.Data, + ...args: ConstructorParameters + ); + + /** + * The PlaceableObject which is rendered to the PrimaryCanvasGroup (or undefined if no object is associated) + */ + object: PlaceableObject; + + /** + * Universal data object for this mesh. + */ + data: PrimaryCanvasObject.Data; + + /** + * @defaultValue + * ```js + * { + * x: 0, + * y: 0, + * z: 0, + * width: 0, + * height: 0, + * alpha: 1, + * rotation: 0, + * hidden: false, + * elevation: undefined, + * sort: 0, + * texture: { + * scaleX: 1, + * scaleY: 1, + * src: null, + * tint: null + * } + * }; + * ``` + */ + static defaultData: PrimaryCanvasObject.Data; + + /** + * An elevation in distance units which defines how this Object is sorted relative to its siblings. + */ + get elevation(): number; + + /** + * A sort key which resolves ties amongst objects at the same elevation. + */ + get sort(): number; + + /** + * A convenient reference to a Document associated with this display object, if any. + */ + get document(): ClientDocument | null; + + /** + * Initialize data using an explicitly provided data object or a canvas document. + * @param data - Provided data or canvas document. + */ + initialize(data?: PrimaryCanvasObject.Data | Document): void; + + /** + * Map the document data to an object and process some properties. + * @param data - The document data. + * @returns The updated data object. + */ + protected _getCanvasDocumentData(data: Document): unknown; + + /** + * Initialize sorting of this PCO. Perform checks and call the primary group sorting if necessary. + * @param sort - The sort value. Must be a finite number or undefined (in this case, it is ignored) + */ + protected _initializeSorting(sort: number): void; + + destroy(...args: any[]): void; + + /** + * Synchronize the appearance of this ObjectMesh with the properties of its represented Document. + * @remarks Marked as abstract + */ + refresh(): void; + + /** + * Synchronize the position of the ObjectMesh using the position of its represented Document. + * @remarks Marked as abstract + */ + setPosition(...args: any[]): void; + + /** + * Synchronize the bounds of the ObjectMesh into the primary group quadtree. + */ + updateBounds(): void; +} + +declare global { + namespace PrimaryCanvasObject { + type Data = { + /** The x-coordinate of the PCO location */ + x: number; + + /** The y-coordinate of the PCO location */ + y: number; + + /** The z-index of the PCO */ + z: number; + + /** The width of the PCO */ + width: number; + + /** The height of the PCO */ + height: number; + + /** The alpha of this PCO */ + alpha: number; + + /** The rotation of this PCO */ + rotation: number; + + /** The PCO is hidden? */ + hidden: boolean; + + /** The elevation of the PCO */ + elevation: number; + + /** The sort key that resolves ties among the same elevation */ + sort: number; + + /** The data texture values */ + texture: PIXI.RenderTexture; + }; + } + /** + * A mixin which decorates a DisplayObject with additional properties expected for rendering in the PrimaryCanvasGroup. + * @param DisplayObject - The parent DisplayObject class being mixed + * @returns A DisplayObject subclass mixed with PrimaryCanvasObject features + */ + function PrimaryCanvasObjectMixin>( + DisplayObject: BaseClass, + ): Mixin; +} diff --git a/src/foundry/client/pixi/placeables/primary-canvas-objects/tile-mesh.d.ts b/src/foundry/client/pixi/placeables/primary-canvas-objects/tile-mesh.d.ts new file mode 100644 index 000000000..c7c7b0b38 --- /dev/null +++ b/src/foundry/client/pixi/placeables/primary-canvas-objects/tile-mesh.d.ts @@ -0,0 +1,54 @@ +import type { MeshMaterial } from "pixi.js"; + +export {}; + +declare global { + /** + * A SpriteMesh which visualizes a Tile object in the PrimaryCanvasGroup. + */ + class TileMesh extends OccludableObjectMixin(SpriteMesh) { + override refresh(): void; + + override setPosition(x: number, y: number): void; + + override updateBounds(): void; + + protected override _getCanvasDocumentData(data: Document): unknown; + } + + /** + * A special case subclass of PIXI.TilingSprite which is used in cases where the tile texture needs to repeat. + * This should eventually be refactored in favor of a more generalized TilingMesh. + * FIXME: Workaround until we have our custom TilingMesh class. + */ + // @ts-expect-error There's some property mismatches on Foundry's end but this class is going away in v12 anyways + class TileSprite extends OccludableObjectMixin(PIXI.TilingSprite) { + constructor(...args: any[]); + + override setShaderClass(): void; + + override renderDepthData(): void; + + /** + * @remarks Always returns false + */ + override get isOccludable(): boolean; + + /** + * @remarks Always returns false + */ + override get shouldRenderDepth(): boolean; + + override shader: MeshMaterial; + + /** + * @remarks Monkey patch copied from TileMesh.refresh() + */ + override refresh(): void; + + /** + * @remarks Monkey patch copied from TileMesh.setPosition() + */ + override setPosition(): void; + } +} diff --git a/src/foundry/client/pixi/placeables/primary-canvas-objects/token-mesh.d.ts b/src/foundry/client/pixi/placeables/primary-canvas-objects/token-mesh.d.ts new file mode 100644 index 000000000..b76b654ce --- /dev/null +++ b/src/foundry/client/pixi/placeables/primary-canvas-objects/token-mesh.d.ts @@ -0,0 +1,62 @@ +export {}; + +type Color = number; + +declare global { + /** + * A SpriteMesh which visualizes a Token object in the PrimaryCanvasGroup. + */ + class TokenMesh extends OccludableObjectMixin(SpriteMesh) { + /** + * Sorting values to deal with ties. + * @defaultValue `750` + */ + static PRIMARY_SORT_ORDER: number; + + static override get defaultData(): TokenMesh.Data; + + override refresh(): void; + + override setPosition(x: number, y: number): void; + + override updateBounds(): void; + + protected override _getTextureCoordinate(testX: number, testY: number): { x: number; y: number } | null; + + /** + * Get the attributes for this TokenMesh which configure the display of this TokenMesh and are compatible + * with CanvasAnimation. + */ + getDisplayAttributes(): TokenMeshDisplayAttributes; + } + + namespace TokenMesh { + type Data = { + /** + * Is this TokenMesh rotation locked? + * @defaultValue `false` + */ + lockRotation: boolean; + } & ReturnType>["defaultData"]; + } + + type TokenMeshDisplayAttributes = { + x: number; + + y: number; + + width: number; + + height: number; + + alpha: number; + + rotation: number; + + scaleX: number; + + scaleY: number; + + tint: Color; + }; +} diff --git a/src/foundry/client/pixi/placeables/sound.d.ts b/src/foundry/client/pixi/placeables/sound.d.ts index 8700547df..8028fa54a 100644 --- a/src/foundry/client/pixi/placeables/sound.d.ts +++ b/src/foundry/client/pixi/placeables/sound.d.ts @@ -1,9 +1,13 @@ import type { ConfiguredDocumentClassForName } from "../../../../types/helperTypes"; import type { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; +export {}; + declare global { /** * An AmbientSound is an implementation of PlaceableObject which represents a dynamic audio source within the Scene. + * @see {@link AmbientSoundDocument} + * @see {@link SoundsLayer} */ class AmbientSound extends PlaceableObject>> { constructor(document: InstanceType>); @@ -20,11 +24,22 @@ declare global { static override embeddedName: "AmbientSound"; - /** - * Create a Sound used to play this AmbientSound object - * @internal - */ - protected _createSound(): Sound | null; + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshField"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshPosition", "refreshState"] }` */ + refreshField: RenderFlag>; + + /** @defaultValue `{}` */ + refreshPosition: RenderFlag>; + + /** @defaultValue `{}` */ + refreshState: RenderFlag>; + }; /** * Is this ambient sound is currently audible based on its hidden state and the darkness level of the Scene? @@ -53,23 +68,14 @@ declare global { override clear(): this; - override draw(): Promise; - - override destroy(options?: Parameters[0]): void; + protected override _draw(): Promise; /** - * Draw the graphical preview of the audio source area of effect - * @internal + * @param options - unused */ - drawField(): PIXI.Container; + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; - /** - * Draw the ControlIcon for the AmbientLight - * @internal - */ - protected _drawControlIcon(): ControlIcon; - - override refresh(): this; + protected _applyRenderFlags(flags: AmbientSound.RenderFlags): void; /** * Refresh the display of the ControlIcon for this AmbientSound source @@ -103,9 +109,17 @@ declare global { protected override _onClickRight(event: PIXI.FederatedEvent): void; protected override _onDragLeftMove(event: PIXI.FederatedEvent): void; + + protected override _onDragEnd(): void; } namespace AmbientSound { + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshField: boolean; + + refreshPosition: boolean; + } + interface SyncOptions { /** * A duration in milliseconds to fade volume transition diff --git a/src/foundry/client/pixi/placeables/template.d.ts b/src/foundry/client/pixi/placeables/template.d.ts index 7bc6c818b..c3067d44a 100644 --- a/src/foundry/client/pixi/placeables/template.d.ts +++ b/src/foundry/client/pixi/placeables/template.d.ts @@ -1,6 +1,8 @@ import { ConfiguredDocumentClass } from "../../../../types/helperTypes"; import { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; +export {}; + declare global { /** * A type of Placeable Object which highlights an area of the grid as covered by some area of effect. @@ -28,20 +30,49 @@ declare global { template: PIXI.Graphics | undefined; /** - * The UI frame container which depicts Token metadata and status, displayed in the ControlsLayer. - * @defaultValue `new ObjectHUD(this)` + * The template control icon + */ + controlIcon: ControlIcon | undefined; + + /** + * The measurement ruler label */ - hud: MeasuredTemplate.ObjectHUD; + ruler: PreciseText; /** * Internal property used to configure the control border thickness * @defaultValue `3` - * @internal */ protected _borderThickness: number; static override embeddedName: "MeasuredTemplate"; + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshState", "refreshShape"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{}` */ + refreshState: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshPosition", "refreshGrid", "refreshText", "refreshTemplate"] }` */ + refreshShape: RenderFlag>; + + /** @defaultValue `{}` */ + refreshTemplate: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshGrid"] }` */ + refreshPosition: RenderFlag>; + + /** @defaultValue `{}` */ + refreshGrid: RenderFlag>; + + /** @defaultValue `{}` */ + refreshText: RenderFlag>; + }; + override get bounds(): Rectangle; /** @@ -59,57 +90,65 @@ declare global { */ get owner(): boolean; - override draw(): Promise; - - override destroy(options?: Parameters[0]): void; + /** + * Is this MeasuredTemplate currently visible on the Canvas? + */ + get isVisible(): boolean; /** - * Draw the HUD container which provides an interface for managing this template - * @internal + * A unique identifier which is used to uniquely identify related objects like a template effect or grid highlight. */ - protected _drawHUD(): MeasuredTemplate.InitializedObjectHUD; + get highlightId(): string; + + protected override _draw(): Promise; /** - * Draw the ControlIcon for the MeasuredTemplate - * @internal + * @param options - unused */ - protected _drawControlIcon(): ControlIcon; + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; + + protected _applyRenderFlags(flags: MeasuredTemplate.RenderFlags): void; + + protected override _getTargetAlpha(): number; /** - * Draw the Text label used for the MeasuredTemplate - * @internal + * Compute the geometry for the template using its document data. + * Subclasses can override this method to take control over how different shapes are rendered. */ - protected _drawRulerText(): PreciseText; + protected _computeShape(): PIXI.Circle | PIXI.Rectangle | PIXI.Polygon; - override refresh(): this; + /** + * Refresh the display of the template outline and shape. + * Subclasses may override this method to take control over how the template is visually rendered. + */ + protected _refreshTemplate(): void; /** * Get a Circular area of effect given a radius of effect * @internal */ - protected _getCircleShape(distance: number): PIXI.Circle; + static getCircleShape(distance: number): PIXI.Circle; /** * Get a Conical area of effect given a direction, angle, and distance * @internal */ - protected _getConeShape(direction: number, angle: number, distance: number): PIXI.Polygon; + static getConeShape(direction: number, angle: number, distance: number): PIXI.Polygon; /** * Get a Rectangular area of effect given a width and height * @internal */ - protected _getRectShape(direction: number, distance: number): PIXI.Rectangle; + static getRectShape(direction: number, distance: number): PIXI.Rectangle; /** * Get a rotated Rectangular area of effect given a width, height, and direction * @internal */ - protected _getRayShape(direction: number, distance: number, width: number): PIXI.Polygon; + static getRayShape(direction: number, distance: number, width: number): PIXI.Polygon; /** * Update the displayed ruler tooltip text - * @internal */ protected _refreshRulerText(): void; @@ -118,6 +157,16 @@ declare global { */ highlightGrid(): void; + /** + * Get the shape to highlight on a Scene which uses grid-less mode. + */ + protected _getGridHighlightShape(): PIXI.Polygon | PIXI.Circle | PIXI.Rectangle; + + /** + * Get an array of points which define top-left grid spaces to highlight for square or hexagonal grids. + */ + protected _getGridHighlightPositions(): Point[]; + override rotate(angle: number, snap: number): Promise; protected override _canControl(user: InstanceType>, event?: any): boolean; @@ -132,10 +181,42 @@ declare global { userId?: string, ): void; - protected override _onDelete(options: DocumentModificationOptions, userId: string): void; + protected override _canControl( + user: InstanceType>, + event: PIXI.FederatedEvent, + ): boolean; + + protected override _canHUD( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + protected override _canConfigure( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + protected override _canView( + user: InstanceType>, + event?: PIXI.FederatedEvent, + ): boolean; + + protected override _onClickRight(event: PIXI.FederatedEvent): void; } namespace MeasuredTemplate { + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshShape: boolean; + + refreshTemplate: boolean; + + refreshPosition: boolean; + + refreshGrid: boolean; + + refreshText: boolean; + } + interface ObjectHUD extends globalThis.ObjectHUD { /** * Template control icon diff --git a/src/foundry/client/pixi/placeables/tile.d.ts b/src/foundry/client/pixi/placeables/tile.d.ts index bdb0fb7e5..8fb198195 100644 --- a/src/foundry/client/pixi/placeables/tile.d.ts +++ b/src/foundry/client/pixi/placeables/tile.d.ts @@ -2,27 +2,57 @@ import type { ConfiguredDocumentClass, ConfiguredObjectClassForName } from "../. import { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; import type { TileDataConstructorData } from "../../../common/data/data.mjs/tileData"; +export {}; + declare global { /** * A Tile is an implementation of PlaceableObject which represents a static piece of artwork or prop within the Scene. - * Tiles are drawn inside a {@link BackgroundLayer} container. + * Tiles are drawn inside the {@link TilesLayer} container. * * @see {@link TileDocument} - * @see {@link BackgroundLayer} - * @see {@link TileSheet} - * @see {@link TileHUD} + * @see {@link TilesLayer} */ class Tile extends PlaceableObject>> { - /** - * @remarks Not used for `Tile` - */ - controlIcon: null; + static override embeddedName: "Tile"; + + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshState", "refreshShape", "refreshElevation", "refreshVideo"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshFrame"] }` */ + refreshState: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshMesh", "refreshPerception", "refreshFrame"] }` */ + refreshShape: RenderFlag>; + + /** @defaultValue `{}` */ + refreshMesh: RenderFlag>; + + /** @defaultValue `{}` */ + refreshFrame: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshMesh"] }` */ + refreshElevation: RenderFlag>; + + /** @defaultValue `{}` */ + refreshPerception: RenderFlag>; + + /** @defaultValue `{}` */ + refreshVideo: RenderFlag>; + }; /** * The Tile border frame - * @defaultValue `undefined` */ - frame: PIXI.Container | undefined; + frame: + | (PIXI.Container & { + border: PIXI.Graphics; + handle: ResizeHandle; + }) + | undefined; /** * The primary tile image texture @@ -36,48 +66,18 @@ declare global { */ tile: PIXI.Sprite | undefined; - /** - * The occlusion image sprite - * @defaultValue `undefined` - */ - occlusionTile: PIXI.Sprite | undefined; - /** * A Tile background which is displayed if no valid image texture is present * @defaultValue `undefined` */ bg: PIXI.Graphics | undefined; - /** - * A cached mapping of non-transparent pixels - * @defaultValue `undefined` - * @internal - */ - protected _alphaMap: - | { - minX: number; - minY: number; - maxX: number; - maxY: number; - pixels: Uint8Array | undefined; - texture: PIXI.RenderTexture | undefined; - } - | undefined; - - /** - * A flag which tracks whether the overhead tile is currently in an occluded state - * @defaultValue `false` - */ - occluded: boolean; - /** * A flag which tracks if the Tile is currently playing * @defaultValue `false` */ playing: boolean; - static override embeddedName: "Tile"; - /** * Get the native aspect ratio of the base texture for the Tile sprite */ @@ -96,105 +96,51 @@ declare global { get isVideo(): boolean; /** - * Is this tile a roof + * Is this tile a roof? */ get isRoof(): boolean; /** - * The effective volume at which this Tile should be playing, including the global ambient volume modifier - */ - get volume(): number; - - override draw(): Promise; - - override destroy(options?: Parameters[0]): void; - - /** - * @param options - (default: `{}`) */ - - override refresh(options?: Tile.RefreshOptions | undefined): this; - - /** - * Refresh the display of the Tile border - * @internal - */ - protected _refreshBorder(b: Rectangle): void; - - /** - * Refresh the display of the Tile resizing handle - * @internal - */ - protected _refreshHandle(b: Rectangle): void; - - /** - * Play video for this Tile (if applicable). - * @param playing - Should the Tile video be playing? - * @param options - Additional options for modifying video playback - * (default: `{}`) - */ - play(playing: boolean, options?: Tile.PlayOptions | undefined): void; - - /** - * Unlink the playback of this video tile from the playback of other tokens which are using the same base texture. - * @param source - The video element source - * @internal + * Is this tile occluded? + * @defaultValue `false` */ - protected _unlinkVideoPlayback(source: HTMLVideoElement): Promise; + get occluded(): boolean; /** - * Update the occlusion rendering for this overhead Tile for a given controlled Token. - * @param tokens - The set of currently controlled Token objects + * The effective volume at which this Tile should be playing, including the global ambient volume modifier */ - updateOcclusion(tokens: Array>>): void; + get volume(): number; /** - * Test whether a specific Token occludes this overhead tile. - * Occlusion is tested against 9 points, the center, the four corners-, and the four cardinal directions - * @param token - The Token to test - * @param options - Additional options that affect testing - * @returns Is the Token occluded by the Tile? + * Debounce assignment of the Tile occluded state to avoid cases like animated token movement which can rapidly */ - testOcclusion( - token: InstanceType>, - options?: Tile.OcclusionOptions | undefined, - ): boolean; + debounceSetOcclusion(occluded: boolean): void; /** - * Test whether the Tile pixel data contains a specific point in canvas space + * Create a preview tile with a background texture instead of an image + * @param data - Initial data with which to create the preview Tile */ - containsPixel(x: number, y: number): boolean; + static createPreview(data: unknown): Tile; /** - * Draw a sprite for the Roof which can be deducted from the fog exploration container + * @param options - unused */ - getRoofSprite(): PIXI.Sprite | undefined; + protected override _draw(options?: Record): Promise; - /** - * Swap a Tile from the background to the foreground - or vice versa - * TODO: Refactor to private _onSwapLayer - */ - swapLayer(): void; + override clear(): void; /** - * Created a cached mapping of pixel alpha for this Tile. - * Cache the bounding box of non-transparent pixels for the un-rotated shape. - * Store an array of booleans for whether each pixel has a non-transparent value. - * @param options - Options which customize the return value - * @internal + * @param options - unused */ - protected _createAlphaMap(options: Tile.AlphaMapOptions): Exclude; + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; - /** - * Compute the alpha-based bounding box for the tile, including an angle of rotation. - * @internal - */ - protected _getAlphaBounds(): PIXI.Rectangle; + protected override _applyRenderFlags(flags: Tile.RenderFlags): void; /** - * Create the filter instance used to reverse-mask overhead tiles using radial or vision-based occlusion. - * @internal + * Refresh the display of the Tile resizing handle. + * Shift the position of the drag handle from the bottom-right (default) depending on which way we are dragging. */ - protected _createOcclusionFilter(): AbstractBaseMaskFilter; + protected _refreshHandle(b: Rectangle): void; protected override _onUpdate( changed: DeepPartial, @@ -206,7 +152,9 @@ declare global { override activateListeners(): void; - protected override _canConfigure(user: User, event?: any): boolean; + protected override _canConfigure(user: User, event?: PIXI.FederatedEvent): boolean; + + protected override _onClickLeft(event: PIXI.FederatedEvent): void; protected override _onClickLeft2(event: PIXI.FederatedEvent): void; @@ -216,7 +164,7 @@ declare global { protected override _onDragLeftDrop(event: PIXI.FederatedEvent): Promise; - protected override _onDragLeftCancel(event: MouseEvent): void; + protected override _onDragLeftCancel(event: PIXI.FederatedEvent): void; /** * Handle mouse-over event on a control handle @@ -254,25 +202,65 @@ declare global { */ protected _onHandleDragDrop(event: PIXI.FederatedEvent): Promise; - /** - * Get resized Tile dimensions - * @internal - */ - protected _getResizedDimensions(event: MouseEvent, origin: Point, destination: Point): Rectangle; - /** * Handle cancellation of a drag event for one of the resizing handles */ - protected _onHandleDragCancel(): void; + protected _onHandleDragCancel(event: PIXI.FederatedEvent): void; /** * Create a preview tile with a background texture instead of an image * @param data - Initial data with which to create the preview Tile */ static createPreview(data: TileDataConstructorData): InstanceType>; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks "Tile#testOcclusion has been deprecated in favor of PrimaryCanvasObject#testOcclusion" + */ + testOcclusion( + token: InstanceType>, + options?: Tile.OcclusionOptions | undefined, + ): boolean; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks "Tile#containsPixel has been deprecated in favor of PrimaryCanvasObject#containsPixel" + */ + containsPixel(x: number, y: number): boolean; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks "Tile#getPixelAlpha has been deprecated in favor of PrimaryCanvasObject#getPixelAlpha" + */ + getPixelAlpha(...args: any[]): unknown; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks "Tile#_getAlphaBounds has been deprecated in favor of PrimaryCanvasObject#_getAlphaBounds" + */ + _getAlphaBounds(): unknown; + + /** + * @remarks Not used + */ + controlIcon: null; } namespace Tile { + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshShape: boolean; + + refreshMesh: boolean; + + refreshFrame: boolean; + + refreshElevation: boolean; + + refreshPerception: boolean; + + refreshVideo: boolean; + } + interface RefreshOptions { /** * Also refresh the perception layer. diff --git a/src/foundry/client/pixi/placeables/token.d.ts b/src/foundry/client/pixi/placeables/token.d.ts index f1393a19a..32f48585f 100644 --- a/src/foundry/client/pixi/placeables/token.d.ts +++ b/src/foundry/client/pixi/placeables/token.d.ts @@ -5,6 +5,8 @@ import { } from "../../../../types/helperTypes"; import { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; +export {}; + declare global { /** * A Token is an implementation of PlaceableObject which represents an Actor within a viewed Scene on the game canvas. @@ -12,27 +14,76 @@ declare global { * @see TokenLayer */ class Token extends PlaceableObject>> { - /** - * A Ray which represents the Token's current movement path - */ - protected _movement: Ray | null; + static override embeddedName: "Token"; + + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{}` */ + redrawEffects: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshState", "refreshSize", "refreshPosition", "refreshElevation", "refreshBars", "refreshNameplate", "refreshBorder", "refreshShader"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshVisibility", "refreshBorder"] }` */ + refreshState: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshMesh", "refreshBorder", "refreshBars", "refreshPosition", "refreshTarget", "refreshEffects"] }` */ + refreshSize: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshMesh", "refreshVisibility"] }` */ + refreshPosition: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshMesh"] }` */ + refreshElevation: RenderFlag>; + + /** @defaultValue `{}` */ + refreshVisibility: RenderFlag>; + + /** @defaultValue `{}` */ + refreshEffects: RenderFlag>; + + /** @defaultValue `{}` */ + refreshMesh: RenderFlag>; + + /** @defaultValue `{}` */ + refreshShader: RenderFlag>; + + /** @defaultValue `{}` */ + refreshBars: RenderFlag>; + + /** @defaultValue `{}` */ + refreshNameplate: RenderFlag>; + + /** @defaultValue `{}` */ + refreshBorder: RenderFlag>; + + /** @defaultValue `{}` */ + refreshTarget: RenderFlag>; + }; /** - * An Object which records the Token's prior velocity dx and dy - * This can be used to determine which direction a Token was previously moving + * Defines the filter to use for detection. */ - protected _velocity: Token.Velocity; + detectionFilter?: PIXI.Filter | null; /** - * The Token's most recent valid position - */ - protected _validPosition: { x: number; y: number }; + * A Graphics instance which renders the border frame for this Token inside the GridLayer. + * @defaultValue `undefined` + * */ + border?: PIXI.Graphics; /** * Track the set of User documents which are currently targeting this Token */ targeted: Set; + /** + * A reference to the SpriteMesh which displays this Token in the PrimaryCanvasGroup. + */ + mesh: TokenMesh; + /** * A reference to the VisionSource object which defines this vision source area of effect */ @@ -44,27 +95,10 @@ declare global { light: LightSource; /** - * A linked ObjectHUD element which is synchronized with the location and visibility of this Token - * @defaultValue `new ObjectHUD(this);` - */ - hud: Token.ObjectHUD; - - /** @defaultValue `undefined` */ - texture?: PIXI.Texture | null; - - /** @defaultValue `undefined` */ - border?: PIXI.Graphics; - - /** @defaultValue `undefined` */ - icon?: PIXI.Sprite; - - static override embeddedName: "Token"; - - /** - * Establish an initial velocity of the token based on it's direction of facing. - * Assume the Token made some prior movement towards the direction that it is currently facing. + * A reference to an animation that is currently in progress for this Token, if any + * @internal */ - protected _getInitialVelocity(): Token.Velocity; + protected _animation: Promise | null; /** * A convenient reference to the Actor object associated with the Token embedded document. @@ -110,13 +144,20 @@ declare global { /** * The Token's current central position */ - get center(): ReturnType; + get center(): Point; + + /** + * The Token's central position, adjusted in each direction by one or zero pixels to offset it relative to walls. + */ + getMovementAdjustedPoint(point: Point, offset?: { offsetX: number; offsetY: number }): Point; /** * The HTML source element for the primary Tile texture */ get sourceElement(): HTMLImageElement | HTMLVideoElement | undefined; + override get sourceId(): string; + /** * Does this Tile depict an animated video texture? */ @@ -137,6 +178,11 @@ declare global { */ get isTargeted(): boolean; + /** + * Return a reference to the detection modes array. + */ + get detectionModes(): Array; + /** * Determine whether the Token is visible to the calling user's perspective. * Hidden Tokens are only displayed to GM Users. @@ -144,14 +190,14 @@ declare global { * Controlled tokens are always visible. * All Tokens are visible to a GM user if no Token is controlled. * - * @see {@link SightLayer#testVisibility} + * @see {@link CanvasVisibility#testVisibility} */ get isVisible(): boolean; /** * The animation name used for Token movement */ - get movementAnimationName(): string; + get animationName(): string; /** * Test whether the Token has sight (or blindness) at any radius @@ -164,30 +210,35 @@ declare global { get emitsLight(): boolean; /** - * Test whether the Token has a limited angle of vision or light emission which would require sight to update on Token rotation + * Test whether the Token uses a limited angle of vision or light emission. */ - get hasLimitedVisionAngle(): boolean; + get hasLimitedSourceAngle(): boolean; /** - * Translate the token's sight distance in units into a radius in pixels. - * @returns The sight radius in pixels + * Translate the token's dim light distance in units into a radius in pixels. */ get dimRadius(): number; /** * Translate the token's bright light distance in units into a radius in pixels. - * @returns The bright radius in pixels */ get brightRadius(): number; /** - * The named identified for the source object associated with this Token + * Translate the token's vision range in units into a radius in pixels. */ - get sourceId(): string; + get sightRange(): number; + + /** + * Translate the token's maximum vision range that takes into account lights. + */ + get optimalSightRange(): number; + + override clone(): Token; /** * Update the light and vision source objects associated with this Token - * @param options - (default: `{}}`) + * @param options - Options which configure how perception sources are updated */ updateSource(options?: Token.UpdateSourceOptions | undefined): void; @@ -199,7 +250,8 @@ declare global { /** * Update an Token vision source associated for this token. - * @param options - (default `{}`) + * @param options - Options which affect how the vision source is updated + * (default: `{}`) */ updateVisionSource(options?: Token.UpdateVisionSourceOptions | undefined): void; @@ -209,59 +261,47 @@ declare global { */ protected _isVisionSource(): boolean; - override clear(): this; - - override draw(): Promise; + override render(renderer: PIXI.Renderer): void; /** - * Draw the HUD container which provides an interface for managing this Token - * @internal + * Render the bound mesh detection filter. + * Note: this method does not verify that the detection filter exists. */ - protected _drawHUD(): Token.InitializedObjectHUD; + protected _renderDetectionFilter(renderer: PIXI.Renderer): void; - override destroy(options?: Parameters[0]): void; + override clear(): void; /** - * Apply initial sanitizations to the provided input data to ensure that a Token has valid required attributes. + * @param options - unused */ - protected _cleanData(): void; + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; /** - * Draw resource bars for the Token + * @param options - unused */ - protected _drawAttributeBars(): PIXI.Container; + protected override _draw(options?: Record): Promise; - /** - * Draw the Sprite icon for the Token - */ - protected _drawIcon(): Promise; + protected override _applyRenderFlags(flags: Token.RenderFlags): void; /** - * Play video for this Token (if applicable). - * @param playing - Should the Token video be playing? - * (default: `true`) - * @param options - Additional options for modifying video playback - * (default: `{}`) + * Refresh the visibility. */ - play(playing?: boolean | undefined, options?: Token.PlayOptions | undefined): void; + protected _refreshVisibility(): void; /** - * Unlink the playback of this video token from the playback of other tokens which are using the same base texture. - * @param source - The video element source - * @internal + * Refresh the text content, position, and visibility of the Token nameplate. */ - protected _unlinkVideoPlayback(source: HTMLVideoElement): Promise; + protected _refreshNameplate(): void; /** - * Update display of the Token, pulling latest data and re-rendering the display of Token components + * Refresh the token mesh. */ - refresh(): this; + protected _refreshMesh(): void; /** - * Size and display the Token Icon - * @internal + * Refresh the token mesh shader. */ - protected _refreshIcon(): void; + protected _refreshShader(): void; /** * Draw the Token border, taking into consideration the grid type and border color @@ -274,24 +314,29 @@ declare global { * @returns The hex color used to depict the border color * @internal */ - protected _getBorderColor(): number | null; + protected _getBorderColor(options?: { + /** + * Return a border color for this hover state, otherwise use the token's current state. + */ + hover?: boolean; + }): number | null; /** - * Refresh the display of the Token HUD interface. + * Refresh the target indicators for the Token. + * Draw both target arrows for the primary User and indicator pips for other Users targeting the same Token. + * @param reticule - Additional parameters to configure how the targeting reticule is drawn. */ - refreshHUD(): void; + protected _refreshTarget(reticule?: Token.ReticuleOptions): void; /** - * Refresh the target indicators for the Token. - * Draw both target arrows for the primary User as well as indicator pips for other Users targeting the same Token. - * @internal + * Draw the targeting arrows around this token. + * @param reticule - Additional parameters to configure how the targeting reticule is drawn. */ - protected _refreshTarget(): void; + protected _drawTarget(reticule?: Token.ReticuleOptions): void; /** - * Refresh the display of Token attribute bars, rendering latest resource data + * Refresh the display of Token attribute bars, rendering its latest resource data. * If the bar attribute is valid (has a value and max), draw the bar. Otherwise hide it. - * @internal */ drawBars(): void; @@ -303,26 +348,14 @@ declare global { */ protected _drawBar(number: number, bar: PIXI.Graphics, data: ReturnType): void; - /** - * Draw the token's nameplate as a text object - * @returns The Text object for the Token nameplate - */ - protected _drawNameplate(): PreciseText; - - /** - * Draw a text tooltip for the token which can be used to display Elevation or a resource value - * @returns The text object used to render the tooltip - * @internal - */ - protected _drawTooltip(): PreciseText; - /** * Return the text which should be displayed in a token's tooltip field - * @internal */ protected _getTooltipText(): string; - /** @internal */ + /** + * Get the text style that should be used for this Token's tooltip. + */ protected _getTextStyle(): PIXI.TextStyle; /** @@ -330,72 +363,78 @@ declare global { */ drawEffects(): Promise; + /** + * Draw a status effect icon + */ + protected _drawEffect(src: string, tint: number | null): Promise; + /** * Draw the overlay effect icon - * @param options - (default: `{}`) - * @internal */ - protected _drawOverlay(options?: Token.DrawOverlayOptions | undefined): Promise; + protected _drawOverlay(src: string, tint: number | null): Promise; /** - * Draw a status effect icon - * @internal + * Refresh the display of status effects, adjusting their position for the token width and height. */ - protected _drawEffect(src: string, i: number, bg: PIXI.Graphics, w: number, tint: number): Promise; + protected _refreshEffects(): void; /** * Helper method to determine whether a token attribute is viewable under a certain mode * @param mode - The mode from CONST.TOKEN_DISPLAY_MODES * @returns Is the attribute viewable? - * @internal */ protected _canViewMode(mode: foundry.CONST.TOKEN_DISPLAY_MODES): boolean; /** - * Animate Token movement along a certain path which is defined by a Ray object - * @param ray - The path along which to animate Token movement + * Animate changes to the appearance of the Token. + * Animations are performed over differences between the TokenDocument and the current Token and TokenMesh appearance. + * @param updateData - A record of the differential data which changed, for reference only + * @param options - Options which configure the animation behavior + * @returns A promise which resolves once the animation is complete */ - animateMovement(ray: Ray): Promise; + animate( + updateData: unknown, + options: { + /** An optional function called each animation frame */ + ontick: (dt: number, data: CanvasAnimationData) => number; - /** - * Update perception each frame depending on the animation configuration - * @param source - (default: `false`) - * @param sound - (default: `false`) - * @param fog - (default: `false`) - * @internal - */ - protected _animatePerceptionFrame({ - source, - sound, - fog, - }?: { - source?: boolean; - sound?: boolean; - fog?: boolean; - }): void; + /** + * A desired token movement speed in grid spaces per second + * @defaultValue `6` + */ + movementSpeed: number; + + /** The animation starting attributes if different from those cached. */ + a0: TokenMeshDisplayAttributes; + + /** The placeable need hover/un-hover emulation. */ + hoverInOut: TokenMeshDisplayAttributes; + }, + ): Promise; /** - * Terminate animation of this particular Token + * Terminate animation of this particular Token. */ stopAnimation(): void; /** * Check for collision when attempting a move to a new position - * @param destination - The destination point of the attempted movement - * @returns A true/false indicator for whether the attempted movement caused a collision + * @param destination - The central destination point of the attempted movement + * @param options - Additional options forwarded to WallsLayer#checkCollision + * @returns The result of the WallsLayer#checkCollision test */ - checkCollision(destination: Point): boolean; + checkCollision( + destination: Point, + options: { + origin: Point; - /** - * @param releaseOthers - (default: `true`) - * @param pan - (default: `false`) - */ - protected override _onControl({ releaseOthers, pan }?: { releaseOthers?: boolean; pan?: boolean }): void; - - protected override _onRelease( - options: PlaceableObject.ReleaseOptions, - ): Promise>> | undefined; + /** @defaultValue `"move"` */ + type: Token.SourceType; + /** @defaultValue `"any"` */ + mode: PointSourcePolygon.CollisionModes; + }, + ): boolean; /** * Get the center-point coordinate for a given grid position * @param x - The grid x-coordinate that represents the top-left of the Token @@ -460,12 +499,6 @@ declare global { options?: Token.EffectToggleOptions | undefined, ): Promise; - /** - * A helper function to toggle the overlay status icon on the Token - * @internal - */ - protected _toggleOverlayEffect(texture: string, { active }?: { active: boolean }): Promise; - /** * Toggle the visibility state of any Tokens in the currently selected set * @returns A Promise which resolves to the updated Token documents @@ -473,31 +506,25 @@ declare global { toggleVisibility(): Promise>[]>; /** - * Return the token's sight origin, tailored for the direction of their movement velocity to break ties with walls + * The external radius of the token in pixels. */ - getSightOrigin(): { - x: number; - y: number; - }; + get externalRadius(): number; /** * A generic transformation to turn a certain number of grid units into a radius in canvas pixels. - * This function adds additional padding to the light radius equal to half the token width. + * This function adds additional padding to the light radius equal to the external radius of the token. * This causes light to be measured from the outer token edge, rather than from the center-point. * @param units - The radius in grid units - * @returns The radius in canvas units + * @returns The radius in pixels */ getLightRadius(units: number): number; protected override _getShiftedPosition(dx: number, dy: number): { x: number; y: number }; - override rotate(...args: Parameters): Promise; - - protected override _onCreate( - options: InstanceType>["data"]["_source"], - userId: DocumentModificationOptions, - ): void; + // TODO: Fix after Token is all cleaned up + protected override _onCreate(data: unknown, options: unknown, userId: string): void; + // TODO: Fix after Token is all cleaned up protected override _onUpdate( data?: DeepPartial>["data"]["_source"]>, options?: DocumentModificationOptions & { animate?: boolean }, @@ -506,6 +533,20 @@ declare global { protected override _onDelete(options?: DocumentModificationOptions, userId?: string): void; + /** + * Handle changes to Token behavior when a significant status effect is applied + * @param statusId - The status effect ID being applied, from CONFIG.specialStatusEffects + * @param active - Is the special status effect now active? + * @internal + */ + _onApplyStatusEffect(statusId: string, active: boolean): void; + + protected override _onControl(options?: Token.ControlOptions): void; + + protected override _onRelease( + options: PlaceableObject.ReleaseOptions, + ): Promise>> | undefined; + protected override _canControl( user?: InstanceType>, event?: PIXI.FederatedEvent, @@ -550,14 +591,124 @@ declare global { protected override _onDragLeftMove(event: PIXI.FederatedEvent): void; - protected override _onDragLeftCancel(event: MouseEvent): void; + protected override _onDragEnd(): void; + /** - * @remarks This does not exist in foundry. It marks the controlIcon as not used because `Token` does never store a value here. + * @remarks Not used */ controlIcon: null; + + /** + * @deprecated since v10, will be removed in v12 + * @remarks `"Token#hasLimitedVisionAngle has been renamed to Token#hasLimitedSourceAngle"` + */ + get hasLimitedVisionAngle(): boolean; + + /** + * @deprecated since v10, will be removed in v12 + * @remarks `"Token#getSightOrigin has been deprecated in favor of Token#getMovementAdjustedPoint"` + */ + getSightOrigin(): { + x: number; + y: number; + }; + + /** + * @deprecated since v10, will be removed in v12 + * @remarks `"Token#icon has been renamed to Token#mesh."` + */ + get icon(): this["mesh"]; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks `"Token#updatePosition has been deprecated without replacement as it is no longer required."` + */ + updatePosition(): void; + + /** + * @deprecated since v11, will be removed in v13 + * @remarks "Token#refreshHUD is deprecated in favor of token.renderFlags.set()" + */ + refreshHUD(options?: Token.ObjectHUD): void; + + /** + * @deprecated since 11, will be removed in v13 + * @remarks `"Token#getDisplayAttributes is deprecated in favor of TokenMesh#getDisplayAttributes"` + */ + getDisplayAttributes(): this["mesh"]["getDisplayAttributes"]; } namespace Token { + interface RenderFlags extends PlaceableObject.RenderFlags { + redrawEffects: boolean; + + refreshSize: boolean; + + refreshPosition: boolean; + + refreshElevation: boolean; + + refreshVisibility: boolean; + + refreshEffects: boolean; + + refreshMesh: boolean; + + refreshShader: boolean; + + refreshBars: boolean; + + refreshNameplate: boolean; + + refreshBorder: boolean; + + refreshTarget: boolean; + } + + type ReticuleOptions = { + /** + * The amount of margin between the targeting arrows and the token's bounding box, expressed as a fraction of an arrow's size. + * @defaultValue `0` + */ + margin?: number; + + /** + * The alpha value of the arrows. + * @defaultValue `1` + */ + alpha?: number; + + /** + * The size of the arrows as a proportion of grid size. + * @defaultValue `0.15` + */ + size?: number; + + /** + * The color of the arrows. + * @defaultValue `0xFF6400` + */ + color?: number; + + /** The arrows' border style configuration. */ + border?: { + /** + * The border color. + * @defaultValue `0` + */ + color?: number; + + /** + * The border width. + * @defaultValue `2` + */ + width?: number; + }; + }; + + // TODO: Determine if there are other source types + type SourceType = "move" | "sight" | "light" | "sound"; + interface Bar { attribute: string; } @@ -591,7 +742,7 @@ declare global { interface UpdateLightSourceOptions { /** - * Defer refreshing the LightingLayer to manually call that refresh later. + * Defer updating perception to manually update it later. * @defaultValue `false` */ defer?: boolean | undefined; @@ -605,7 +756,7 @@ declare global { interface UpdateVisionSourceOptions { /** - * Defer refreshing the SightLayer to manually call that refresh later. + * Defer updating perception to manually update it later. * @defaultValue `false` */ defer?: boolean | undefined; @@ -615,12 +766,6 @@ declare global { * @defaultValue `false` */ deleted?: boolean | undefined; - - /** - * Never update the Fog exploration progress for this update. - * @defaultValue `false` - */ - skipUpdateFog?: boolean | undefined; } type UpdateSourceOptions = UpdateLightSourceOptions & UpdateVisionSourceOptions; @@ -697,6 +842,11 @@ declare global { */ groupSelection?: boolean | undefined; } + + interface ControlOptions extends PlaceableObject.ControlOptions { + /** @defaultValue `false` */ + pan?: boolean; + } } /** diff --git a/src/foundry/client/pixi/placeables/wall.d.ts b/src/foundry/client/pixi/placeables/wall.d.ts index 1dfb501a9..ffe188d43 100644 --- a/src/foundry/client/pixi/placeables/wall.d.ts +++ b/src/foundry/client/pixi/placeables/wall.d.ts @@ -5,7 +5,8 @@ import type { } from "../../../../types/helperTypes"; import type { DocumentModificationOptions } from "../../../common/abstract/document.mjs"; import type { LineIntersection } from "../../../common/utils/geometry.mjs"; -import type { HoverInOptions } from "../placeable"; + +export {}; declare global { /** @@ -15,20 +16,38 @@ declare global { * * @see {@link WallDocument} * @see {@link WallsLayer} - * @see {@link WallConfig} */ class Wall extends PlaceableObject { - /** - * @remarks Not used for `Wall` - */ - controlIcon: null; + static override embeddedName: "Wall"; + + static override RENDER_FLAGS: { + /** @defaultValue `{ propagate: ["refresh"] }` */ + redraw: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshState", "refreshLine"], alias: true }` */ + refresh: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshEndpoints", "refreshHighlight"] }` */ + refreshState: RenderFlag>; + + /** @defaultValue `{ propagate: ["refreshEndpoints", "refreshHighlight", "refreshDirection"] }` */ + refreshLine: RenderFlag>; + + /** @defaultValue `{}` */ + refreshEndpoints: RenderFlag>; + + /** @defaultValue `{}` */ + refreshDirection: RenderFlag>; + + /** @defaultValue `{}` */ + refreshHighlight: RenderFlag>; + }; /** - * An reference the Door Control icon associated with this Wall, if any - * @internal + * A reference the Door Control icon associated with this Wall, if any * @defaultValue `undefined` */ - doorControl: DoorControl | undefined | null; + protected doorControl: DoorControl | undefined | null; /** * A reference to an overhead Tile that is a roof, interior to which this wall is contained @@ -37,30 +56,24 @@ declare global { roof: InstanceType> | undefined; /** - * A set which tracks other Wall instances that this Wall intersects with (excluding shared endpoints) + * A Graphics object used to highlight this wall segment. Only used when the wall is controlled. */ - intersectsWith: Map>, LineIntersection>; + highlight: PIXI.Graphics | undefined; /** - * Cached representation of this wall's endpoints as {@link PolygonVertex}es. - * @defaultValue `null` - * @internal + * A set which tracks other Wall instances that this Wall intersects with (excluding shared endpoints) */ - protected _vertices: { a: PolygonVertex; b: PolygonVertex } | null; + intersectsWith: Map>, LineIntersection>; /** - * Cached representation of the set of this wall's vertices. - * @defaultValue `null` - * @internal + * A convenience reference to the coordinates Array for the Wall endpoints, [x0,y0,x1,y1]. */ - protected _wallKeys: Set | null; - - static override embeddedName: "Wall"; + get coords(): [x0: number, y0: number, x1: number, y1: number]; // Wall["document"]["c"]; /** - * A convenience reference to the coordinates Array for the Wall endpoints, [x0,y0,x1,y1]. + * The endpoints of the wall expressed as {@link PolygonVertex} instances. */ - get coords(): Wall["data"]["c"]; + get vertices(): { a: PolygonVertex; b: PolygonVertex }; /** * The initial endpoint of the Wall @@ -73,14 +86,9 @@ declare global { get B(): Point; /** - * The endpoints of the wall as {@link PolygonVertex}es. + * A set of vertex sort keys which identify this Wall's endpoints. */ - get vertices(): { a: PolygonVertex; b: PolygonVertex }; - - /** - * The set of keys for this wall's endpoints. - */ - get wallKeys(): Set; + get wallKeys(): Set; override get bounds(): PIXI.Rectangle; @@ -118,13 +126,23 @@ declare global { */ toRay(): Ray; - override draw(): Promise; + /** + * @param options - unused + */ + protected override _draw(): Promise; + + override clear(): this; /** * Draw a control icon that is used to manipulate the door's open/closed state */ createDoorControl(): DoorControl; + /** + * Clear the door control if it exists. + */ + clearDoorControl(): void; + /** * Determine the orientation of this wall with respect to a reference point * @param point - Some reference point, relative to which orientation is determined @@ -133,27 +151,23 @@ declare global { */ orientPoint(point: Point): number; - protected override _createInteractionManager(): NonNullable; - - override activateListeners(): void; - /** - * Draw a directional prompt icon for one-way walls to illustrate their direction of effect. - * @returns The drawn icon - * @internal + * Test whether to apply a configured threshold of this wall. + * When the proximity threshold is met, this wall is excluded as an edge in perception calculations. + * @param sourceType - Sense type for the source + * @param sourceOrigin - The origin or position of the source on the canvas + * @param externalRadius - The external radius of the source + * (default: `0`) + * @returns True if the wall has a threshold greater than 0 for the source type, and the source type is within that distance. */ - protected _drawDirection(): PIXI.Sprite | null; + applyThreshold(sourceType: string, sourceOrigin: Point, externalRadius: number): boolean; - override refresh(): this; + override control(options?: Wall.ControlOptions | undefined): boolean; /** - * Compute an approximate Polygon which encloses the line segment providing a specific hitArea for the line - * @param coords - The original wall coordinates - * @param pad - The amount of padding to apply - * @returns A constructed Polygon for the line - * @internal + * @param options - unused */ - protected _getWallHitPolygon(coords: [number, number, number, number], pad: number): PIXI.Polygon; + protected override _destroy(options?: PIXI.IDestroyOptions | boolean): void; /** * Given the properties of the wall - decide upon a color to render the wall for display on the WallsLayer @@ -161,15 +175,6 @@ declare global { */ protected _getWallColor(): number; - /** - * @param chain - (default: `false`) - */ - protected override _onControl({ chain }?: PlaceableObject.ControlOptions & { chain?: boolean }): void; - - protected override _onRelease(options?: PlaceableObject.ReleaseOptions): void; - - override destroy(options?: Parameters[0]): void; - /** * Test whether the Wall direction lies between two provided angles * This test is used for collision and vision checks against one-directional walls @@ -211,11 +216,12 @@ declare global { */ protected _identifyIntersectionsWith(other: InstanceType>): void; + protected override _applyRenderFlags(flags: Wall.RenderFlags): void; + /** - * Remove this wall's intersections. - * @internal + * Given the properties of the wall - decide upon a color to render the wall for display on the WallsLayer */ - protected _removeIntersections(): void; + protected _getWallColor(): number; protected override _onCreate( data: foundry.data.WallData["_source"], @@ -232,16 +238,20 @@ declare global { protected override _onDelete(options: DocumentModificationOptions, userId: string): void; /** - * Callback actions when a wall that contains a door is moved or its state is changed - * @param doorChange - Update vision and sound restrictions - * (default: `false`) + * Play a door interaction sound. + * This plays locally, each client independently applies this workflow. + * @param interaction - The door interaction: "open", "close", "lock", "unlock", or "test". * @internal */ - protected _onModifyWall(doorChange?: boolean): Promise; + protected _playDoorSound(interaction: Wall.DoorInteraction): void; + + protected override _createInteractionManager(): NonNullable; + + override activateListeners(): void; protected override _canControl(user: InstanceType>, event?: any): boolean; - protected override _onHoverIn(event: PIXI.FederatedEvent, options?: HoverInOptions): false | void; + protected override _onHoverIn(event: PIXI.FederatedEvent, options?: PlaceableObject.HoverInOptions): false | void; protected override _onHoverOut(event: PIXI.FederatedEvent): false | void; @@ -262,6 +272,30 @@ declare global { protected override _onDragLeftMove(event: PIXI.FederatedEvent): void; protected override _onDragLeftDrop(event: PIXI.FederatedEvent): Promise; + + /** + * @remarks Not used + */ + controlIcon: null; + } + + namespace Wall { + interface RenderFlags extends PlaceableObject.RenderFlags { + refreshLine: boolean; + + refreshEndpoints: boolean; + + refreshDirection: boolean; + + refreshHighlight: boolean; + } + + interface ControlOptions extends PlaceableObject.ControlOptions { + /** @defaultValue `false` */ + chain: boolean; + } + + type DoorInteraction = "open" | "close" | "lock" | "unlock" | "test"; } } diff --git a/src/foundry/common/constants.mjs.d.ts b/src/foundry/common/constants.mjs.d.ts index 0688169df..c2575b184 100644 --- a/src/foundry/common/constants.mjs.d.ts +++ b/src/foundry/common/constants.mjs.d.ts @@ -374,14 +374,40 @@ export type TEXT_ANCHOR_POINTS = ValueOf; /** * Define the valid occlusion modes which an overhead tile can use + * @defaultValue `1` + * @see https://foundryvtt.com/article/tiles/ */ -export const TILE_OCCLUSION_MODES: Readonly<{ +export const OCCLUSION_MODES: Readonly<{ + /** + * Turns off occlusion, making the tile never fade while tokens are under it. + */ NONE: 0; + + /** + * Causes the whole tile to fade when an actor token moves under it. + * @defaultValue + */ FADE: 1; + // ROOF: 2; This mode is no longer supported so we don't use 2 for any other mode + + /** + * Causes the tile to reveal the background in the vicinity of an actor token under it. The radius is determined by the token's size. + */ RADIAL: 3; + + /** + * Causes the tile to be partially revealed based on the vision of the actor, which does not need to be under the tile to see what's beneath it. + * @remarks (by Foundry) This is useful for rooves on buildings where players could see through a window or door, viewing only a portion of what is obscured by the roof itself. + */ VISION: 4; }>; +export type OCCLUSION_MODES = ValueOf; + +/** + * Alias for old tile occlusion modes definition + */ +export const TILE_OCCLUSION_MODES: typeof OCCLUSION_MODES; export type TILE_OCCLUSION_MODES = ValueOf; /** diff --git a/src/types/utils.d.ts b/src/types/utils.d.ts index 130872449..4266c8944 100644 --- a/src/types/utils.d.ts +++ b/src/types/utils.d.ts @@ -142,8 +142,10 @@ type PropertyTypeOrFallback = Key extends keyof */ type RequiredProps = Required> & Omit; -type AnyConstructor any> = Pick & - (new (...args: any) => InstanceType); +type AnyConstructor any> = Pick & + (Class extends new (...args: any[]) => any + ? new (...args: any[]) => InstanceType + : abstract new (...args: any[]) => InstanceType); type Mixin< MixinClass extends new (...args: any[]) => any, diff --git a/tests/foundry/client/pixi/placeable.test-d.ts b/tests/foundry/client/pixi/placeable.test-d.ts index 65cf32893..28b85ac93 100644 --- a/tests/foundry/client/pixi/placeable.test-d.ts +++ b/tests/foundry/client/pixi/placeable.test-d.ts @@ -23,13 +23,7 @@ class OnePlaceable extends PlaceableObject { return null as unknown as Rectangle; } - draw(): Promise { - return Promise.resolve(this); - } - - refresh(): this | void { - return undefined; - } + protected async _draw(): Promise {} } const placeable = new OnePlaceable(new EmbeddedInSceneDocument()); @@ -38,16 +32,19 @@ expectTypeOf(placeable.document).toEqualTypeOf(); expectTypeOf(placeable.sheet).toEqualTypeOf(); class ConcretePlaceableObject extends PlaceableObject { - get bounds(): NormalizedRectangle { + get bounds(): PIXI.Rectangle { throw new Error("Not implemented"); } - async draw() { - return this; - } - refresh() { - return this; - } + protected async _draw() {} } expectTypeOf( new ConcretePlaceableObject(new EmbeddedInSceneDocument()).mouseInteractionManager, ).toEqualTypeOf | null>(); + +expectTypeOf(PlaceableObject.RENDER_FLAGS.redraw.propagate).toEqualTypeOf< + Array | undefined +>(); + +expectTypeOf(AmbientLight.RENDER_FLAGS.redraw.propagate).toEqualTypeOf< + Array | undefined +>();