mudlet-map-renderer 2.3.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ScenePipeline.d.ts +10 -1
- package/dist/binary/BinaryMapReader.d.ts +4 -2
- package/dist/binary.mjs.map +1 -1
- package/dist/{flushSceneShapes-Duhi0OQv.js → flushSceneShapes-c7ttw7D-.js} +637 -424
- package/dist/flushSceneShapes-c7ttw7D-.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.mjs +754 -672
- package/dist/index.mjs.map +1 -1
- package/dist/lens/hiddenAwareLens.d.ts +12 -0
- package/dist/offscreen.mjs +45 -45
- package/dist/render/RecordingLayer.d.ts +22 -7
- package/dist/rendering/KonvaRenderBackend.d.ts +20 -0
- package/dist/rendering/SceneManager.d.ts +2 -1
- package/dist/scene/NeighborProjector.d.ts +82 -0
- package/dist/scene/RoomFlags.d.ts +36 -0
- package/dist/scene/RoomStyle.d.ts +2 -0
- package/dist/scene/elements/RoomLayout.d.ts +12 -0
- package/dist/types/Settings.d.ts +29 -0
- package/package.json +5 -3
- package/dist/flushSceneShapes-Duhi0OQv.js.map +0 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RoomLens } from './RoomLens';
|
|
2
|
+
/**
|
|
3
|
+
* Wrap a lens so Mudlet-hidden rooms (`settings.hiddenRooms === "hide"`) count
|
|
4
|
+
* as not-visible: the room filter drops them via `isVisible`, and any exit
|
|
5
|
+
* touching one is treated as `"hidden"` via `getExitTreatment`. This reuses the
|
|
6
|
+
* existing lens machinery so every consumer (scene build, current-room overlay)
|
|
7
|
+
* hides hidden rooms and their exits identically.
|
|
8
|
+
*
|
|
9
|
+
* Returns `lens` unchanged when `hideHidden` is false (the "show"/"faded" modes
|
|
10
|
+
* keep hidden rooms visible — "faded" fades them in the room pass instead).
|
|
11
|
+
*/
|
|
12
|
+
export declare function hiddenAwareLens(lens: RoomLens, hideHidden: boolean): RoomLens;
|
package/dist/offscreen.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as e, C as t, E as n, P as r, S as i, T as a, a as o, h as s, j as c, k as l, m as u, o as d, r as f, t as p, w as m, x as h } from "./flushSceneShapes-c7ttw7D-.js";
|
|
2
2
|
import g from "konva";
|
|
3
3
|
//#region src/rendering/offscreen/serializeTransform.ts
|
|
4
4
|
function _(e) {
|
|
@@ -26,33 +26,33 @@ function b() {
|
|
|
26
26
|
return typeof document < "u" && typeof HTMLCanvasElement < "u" && typeof HTMLCanvasElement.prototype.transferControlToOffscreen == "function";
|
|
27
27
|
}
|
|
28
28
|
var x = class {
|
|
29
|
-
constructor(n, i
|
|
30
|
-
this.hitTester = new
|
|
31
|
-
let
|
|
32
|
-
if (this.camera = new
|
|
29
|
+
constructor(t, n, i = {}) {
|
|
30
|
+
this.hitTester = new d(), this.currentStyle = o, this._coordinateTransform = e, this.coordinateInverse = e, this.lastHitShapes = [], this.boundsByShape = /* @__PURE__ */ new Map(), this.sceneOverlays = /* @__PURE__ */ new Map(), this.viewportSubscribers = /* @__PURE__ */ new Set(), this.liveEffects = /* @__PURE__ */ new Map(), this.pendingExports = /* @__PURE__ */ new Map(), this.exportSeq = 0, this.destroyed = !1, this.state = t, this.container = n, this.pipeline = new s(t.mapReader, t.settings), this.dpr = i.devicePixelRatio ?? (typeof devicePixelRatio < "u" ? devicePixelRatio : 1), this.transport = i.transport ?? i.createTransport?.();
|
|
31
|
+
let a = n?.clientWidth ?? 1, f = n?.clientHeight ?? 1;
|
|
32
|
+
if (this.camera = new c(a, f), this.events = new r(n), this.culling = new l(t.settings, () => {
|
|
33
33
|
this.postSettings(), this.postCamera();
|
|
34
34
|
}), this.transport) {
|
|
35
35
|
let e = (e) => this.handleWorkerMessage(e.data);
|
|
36
36
|
this.transport.addEventListener ? this.transport.addEventListener("message", e) : this.transport.onmessage = e;
|
|
37
37
|
}
|
|
38
|
-
if (
|
|
39
|
-
getComputedStyle(
|
|
38
|
+
if (n && this.transport && b()) {
|
|
39
|
+
getComputedStyle(n).position === "static" && (n.style.position = "relative");
|
|
40
40
|
let e = document.createElement("canvas");
|
|
41
|
-
e.style.position = "absolute", e.style.inset = "0", e.style.width = "100%", e.style.height = "100%", e.style.display = "block",
|
|
42
|
-
let
|
|
41
|
+
e.style.position = "absolute", e.style.inset = "0", e.style.width = "100%", e.style.height = "100%", e.style.display = "block", n.appendChild(e), n.style.backgroundColor = t.settings.backgroundColor;
|
|
42
|
+
let r = e.transferControlToOffscreen();
|
|
43
43
|
this.transport.postMessage({
|
|
44
44
|
type: "init",
|
|
45
|
-
canvas:
|
|
46
|
-
width:
|
|
47
|
-
height:
|
|
45
|
+
canvas: r,
|
|
46
|
+
width: a,
|
|
47
|
+
height: f,
|
|
48
48
|
dpr: this.dpr,
|
|
49
|
-
settings:
|
|
50
|
-
}, [
|
|
51
|
-
clientToMapPoint: (e, t) => this.camera.clientToMapPoint(e, t,
|
|
49
|
+
settings: t.settings
|
|
50
|
+
}, [r]), this.interactionHandler = new u(n, this.camera, t, {
|
|
51
|
+
clientToMapPoint: (e, t) => this.camera.clientToMapPoint(e, t, n.getBoundingClientRect()),
|
|
52
52
|
pickAtPoint: (e, t) => this.hitTester.pick(e, t)
|
|
53
53
|
}, this.events);
|
|
54
54
|
}
|
|
55
|
-
this.cameraChangeHandler = () => this.onCameraChange(), this.camera.on("change", this.cameraChangeHandler), this.applyStyleTransforms(), this.subscribeToState(
|
|
55
|
+
this.cameraChangeHandler = () => this.onCameraChange(), this.camera.on("change", this.cameraChangeHandler), this.applyStyleTransforms(), this.subscribeToState(t), this.postCamera();
|
|
56
56
|
}
|
|
57
57
|
get coordinateTransform() {
|
|
58
58
|
return this._coordinateTransform;
|
|
@@ -109,7 +109,7 @@ var x = class {
|
|
|
109
109
|
postOverlays() {
|
|
110
110
|
let e = this.styleContext(), t = [];
|
|
111
111
|
for (let n of this.buildCurrentRoomOverlayShapes()) t.push(...this.styleOne(n, e, !1));
|
|
112
|
-
for (let n of
|
|
112
|
+
for (let n of p(this.state)) t.push(...this.styleOne(n, e, !1));
|
|
113
113
|
for (let n of this.sceneOverlays.values()) {
|
|
114
114
|
let r = n.render(this.state, this.camera.getViewportBounds());
|
|
115
115
|
if (!r) continue;
|
|
@@ -128,20 +128,20 @@ var x = class {
|
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
130
|
styleOne(e, t, n) {
|
|
131
|
-
return n || this.currentStyle ===
|
|
131
|
+
return n || this.currentStyle === o ? [e] : f([e], this.currentStyle, t);
|
|
132
132
|
}
|
|
133
133
|
styleShapes(e, t) {
|
|
134
|
-
return this.currentStyle ===
|
|
134
|
+
return this.currentStyle === o ? e : f(e, this.currentStyle, t);
|
|
135
135
|
}
|
|
136
136
|
styleLayer(e, t) {
|
|
137
|
-
let n = [],
|
|
138
|
-
for (let
|
|
139
|
-
let e = this.boundsByShape.get(
|
|
140
|
-
for (let t of
|
|
137
|
+
let n = [], r = [];
|
|
138
|
+
for (let i of e) {
|
|
139
|
+
let e = this.boundsByShape.get(i) ?? null, a = this.currentStyle === o ? [i] : f([i], this.currentStyle, t);
|
|
140
|
+
for (let t of a) n.push(t), r.push(e);
|
|
141
141
|
}
|
|
142
142
|
return {
|
|
143
143
|
shapes: n,
|
|
144
|
-
bounds:
|
|
144
|
+
bounds: r
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
147
|
refresh() {
|
|
@@ -171,38 +171,38 @@ var x = class {
|
|
|
171
171
|
return t;
|
|
172
172
|
}
|
|
173
173
|
buildCurrentRoomOverlayShapes() {
|
|
174
|
-
let e = this.state,
|
|
175
|
-
if (
|
|
176
|
-
let
|
|
177
|
-
if (!
|
|
178
|
-
let
|
|
179
|
-
if (!
|
|
180
|
-
let
|
|
181
|
-
if (
|
|
182
|
-
let t = e.currentAreaInstance.getLinkExits(e.currentZIndex).filter((e) => e.a ===
|
|
174
|
+
let e = this.state, r = e.positionRoomId;
|
|
175
|
+
if (r === void 0) return [];
|
|
176
|
+
let o = e.mapReader.getRoom(r);
|
|
177
|
+
if (!o || o.area !== e.currentArea || o.z !== e.currentZIndex) return [];
|
|
178
|
+
let s = e.settings;
|
|
179
|
+
if (!s.highlightCurrentRoom) return [];
|
|
180
|
+
let c = [], l = this.pipeline.exitRenderer, u = e.lens, d = /* @__PURE__ */ new Map();
|
|
181
|
+
if (d.set(o.id, o), e.currentAreaInstance && e.currentZIndex !== void 0) {
|
|
182
|
+
let t = e.currentAreaInstance.getLinkExits(e.currentZIndex).filter((e) => e.a === o.id || e.b === o.id);
|
|
183
183
|
for (let n of t) {
|
|
184
|
-
let t =
|
|
185
|
-
t &&
|
|
184
|
+
let t = l.renderDataWithColor(n, y, e.currentZIndex);
|
|
185
|
+
t && c.push(this.pipeline.buildExitShape(t));
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
-
for (let e of
|
|
189
|
-
for (let e of
|
|
190
|
-
return [...Object.values(
|
|
188
|
+
for (let e of a(o, s, y)) c.push(i(e, o.id));
|
|
189
|
+
for (let e of n(o, s, y)) c.push(h(e));
|
|
190
|
+
return [...Object.values(o.exits), ...Object.values(o.specialExits)].forEach((t) => {
|
|
191
191
|
let n = e.mapReader.getRoom(t);
|
|
192
|
-
n && n.area === e.currentArea && n.z === e.currentZIndex &&
|
|
193
|
-
}),
|
|
194
|
-
let i =
|
|
195
|
-
strokeOverride: i ? y :
|
|
192
|
+
n && n.area === e.currentArea && n.z === e.currentZIndex && u.isVisible(n) && d.set(n.id, n);
|
|
193
|
+
}), d.forEach((n, r) => {
|
|
194
|
+
let i = r === o.id, a = m(n, e.mapReader, s, {
|
|
195
|
+
strokeOverride: i ? y : s.lineColor,
|
|
196
196
|
flatPipeline: !0
|
|
197
197
|
});
|
|
198
|
-
a.children.push(...
|
|
199
|
-
}),
|
|
198
|
+
a.children.push(...t(n, e.mapReader, s)), c.push(a);
|
|
199
|
+
}), c;
|
|
200
200
|
}
|
|
201
201
|
setStyle(e) {
|
|
202
202
|
this.currentStyle = e, this.lastHitShapes = [], this.hitTester.clear(), this.applyStyleTransforms(), this.refresh();
|
|
203
203
|
}
|
|
204
204
|
applyStyleTransforms() {
|
|
205
|
-
let
|
|
205
|
+
let t = this.currentStyle, n = t.worldToScene ? (e, n) => t.worldToScene(e, n) : e, r = t.sceneToWorld ? (e, n) => t.sceneToWorld(e, n) : e, i = this.coordinateInverse, a = t.sceneLayerOffset ? (e) => t.sceneLayerOffset(e) : void 0;
|
|
206
206
|
this._coordinateTransform = n, this.coordinateInverse = r, this.coordinateLayerOffset = a, this.culling.setCoordinateTransform(n), this.lastHitShapes.length > 0 && this.hitTester.build(this.lastHitShapes, this.state.settings.roomSize, n, a);
|
|
207
207
|
let o = this.camera.getScale(), s = this.camera.width / 2, c = this.camera.height / 2, l = i((s - this.camera.position.x) / o, (c - this.camera.position.y) / o), u = n(l.x, l.y);
|
|
208
208
|
this.camera.position = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as Konva } from 'konva';
|
|
2
|
-
import { FillStyle } from '../scene/Shape';
|
|
2
|
+
import { FillStyle, LayerId } from '../scene/Shape';
|
|
3
3
|
type RectCommand = {
|
|
4
4
|
type: 'rect';
|
|
5
5
|
x: number;
|
|
@@ -78,6 +78,8 @@ export declare class RecordingGroupNode {
|
|
|
78
78
|
y: number;
|
|
79
79
|
_visible: boolean;
|
|
80
80
|
noScaling: boolean;
|
|
81
|
+
/** Scene layer this group belongs to; drives coalesced draw ordering. */
|
|
82
|
+
layer?: LayerId;
|
|
81
83
|
readonly commands: RecordingDrawCommand[];
|
|
82
84
|
/** Lazily created when this group is materialized for a Konva.Layer. */
|
|
83
85
|
_konvaGroup?: Konva.Group;
|
|
@@ -107,20 +109,33 @@ export type DrawEntry = {
|
|
|
107
109
|
x: number;
|
|
108
110
|
y: number;
|
|
109
111
|
noScaling: boolean;
|
|
112
|
+
layer?: LayerId;
|
|
110
113
|
readonly commands: RecordingDrawCommand[];
|
|
111
114
|
visible: boolean;
|
|
112
115
|
};
|
|
113
|
-
/**
|
|
114
|
-
* LayerNode backed by a single Konva.Shape whose sceneFunc replays
|
|
115
|
-
* {@link DrawEntry} objects. Used for the main scene layer where individual
|
|
116
|
-
* shapes need cull toggling.
|
|
117
|
-
*/
|
|
118
116
|
export declare class DrawCommandLayerNode {
|
|
117
|
+
private readonly coalesce;
|
|
119
118
|
private readonly entries;
|
|
120
119
|
private readonly nodeToEntry;
|
|
121
120
|
private readonly konvaLayer;
|
|
122
121
|
private konvaShape;
|
|
123
|
-
|
|
122
|
+
/** Reusable bucket map for coalesced draws — cleared per frame, never reallocated. */
|
|
123
|
+
private readonly buckets;
|
|
124
|
+
constructor(konvaLayer: Konva.Layer, coalesce?: () => boolean);
|
|
125
|
+
/** Original path: one setTransform + replay per visible entry, in order. */
|
|
126
|
+
private drawPerEntry;
|
|
127
|
+
/**
|
|
128
|
+
* Fast path: same-style primitives are accumulated into one path per style
|
|
129
|
+
* and drawn with a single `fill()`/`stroke()`. Done in two sweeps — link
|
|
130
|
+
* entries (exit lines) first, then room entries — so rooms stay painted on
|
|
131
|
+
* top of exits, matching the per-entry insertion order. Within a sweep,
|
|
132
|
+
* non-batchable entries (one-way arrows, doors, symbols, emboss, inner-exit
|
|
133
|
+
* triangles…) replay per-entry; batched primitives flush afterwards. Exit
|
|
134
|
+
* lines and room bodies don't meaningfully overlap same-layer siblings, so
|
|
135
|
+
* reordering them within a sweep is visually immaterial.
|
|
136
|
+
*/
|
|
137
|
+
private drawCoalesced;
|
|
138
|
+
private sweep;
|
|
124
139
|
addNode(node: RecordingGroupNode): void;
|
|
125
140
|
/** Return the DrawEntry created when `node` was added, or undefined if not found. */
|
|
126
141
|
getEntry(node: RecordingGroupNode): DrawEntry | undefined;
|
|
@@ -53,6 +53,13 @@ export declare class KonvaRenderBackend implements InteractiveBackend {
|
|
|
53
53
|
private positionMarker?;
|
|
54
54
|
private highlightShapes;
|
|
55
55
|
private pathShapes;
|
|
56
|
+
/**
|
|
57
|
+
* Projected positions of the current build's spilled neighbouring-area
|
|
58
|
+
* rooms (roomId → current-area-frame x/y). Empty when neighbour spill is
|
|
59
|
+
* off or yields nothing. Drives {@link overlayReader} so highlights/paths
|
|
60
|
+
* on spilled rooms land at their projected spots.
|
|
61
|
+
*/
|
|
62
|
+
private spilledRoomPositions;
|
|
56
63
|
private currentRoomOverlay;
|
|
57
64
|
private interactionHandler?;
|
|
58
65
|
private origSetSize?;
|
|
@@ -94,6 +101,19 @@ export declare class KonvaRenderBackend implements InteractiveBackend {
|
|
|
94
101
|
private clearSceneOverlayNodes;
|
|
95
102
|
private subscribeToState;
|
|
96
103
|
private buildScene;
|
|
104
|
+
/**
|
|
105
|
+
* Compute neighbouring-area spill for the current build, or `undefined` when
|
|
106
|
+
* the feature is off / the player isn't on this area+plane. Driven by the
|
|
107
|
+
* live player position so it updates as the player nears a boundary.
|
|
108
|
+
*/
|
|
109
|
+
private computeNeighborSpill;
|
|
110
|
+
/**
|
|
111
|
+
* The map reader the overlay code (highlights, paths) should use. When
|
|
112
|
+
* neighbour spill produced rooms, this is a {@link ProjectedMapReader} that
|
|
113
|
+
* makes those spilled rooms look like current-area rooms at their projected
|
|
114
|
+
* positions; otherwise it's the plain reader.
|
|
115
|
+
*/
|
|
116
|
+
private overlayReader;
|
|
97
117
|
/**
|
|
98
118
|
* Run the active {@link Style} over `shape`, walk the (possibly multi-shape)
|
|
99
119
|
* result into a single {@link RecordingGroupNode}, and add it to `layerNode`.
|
|
@@ -8,6 +8,7 @@ import { GroupShape, Shape } from '../scene/Shape';
|
|
|
8
8
|
import { IMapReader } from '../reader/MapReader';
|
|
9
9
|
import { RoomLens } from '../lens/RoomLens';
|
|
10
10
|
import { ExitDrawData } from '../ExitRenderer';
|
|
11
|
+
import { NeighborSpill } from '../scene/NeighborProjector';
|
|
11
12
|
export interface CullStats {
|
|
12
13
|
visibleRooms: number;
|
|
13
14
|
totalRooms: number;
|
|
@@ -39,7 +40,7 @@ export declare class SceneManager {
|
|
|
39
40
|
get drawnStubs(): readonly DrawnStubEntry[];
|
|
40
41
|
get areaExitHitZones(): readonly AreaExitHitZone[];
|
|
41
42
|
get hitShapes(): readonly Shape[];
|
|
42
|
-
rebuild(area: IArea, plane: IPlane, zIndex: number, lens?: RoomLens): SceneBuildResult;
|
|
43
|
+
rebuild(area: IArea, plane: IPlane, zIndex: number, lens?: RoomLens, spill?: NeighborSpill): SceneBuildResult;
|
|
43
44
|
buildExitShape(data: ExitDrawData): GroupShape;
|
|
44
45
|
reset(): void;
|
|
45
46
|
resetPipeline(mapReader: IMapReader): void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { IMapReader } from '../reader/MapReader';
|
|
2
|
+
import { IArea } from '../reader/Area';
|
|
3
|
+
/**
|
|
4
|
+
* Clone a room placed at projected `(x, y)` in the current area+plane, shifting
|
|
5
|
+
* its custom-line points by the same delta so they follow the room. Custom-line
|
|
6
|
+
* points are stored with world-y negated (`world = -point.y`), so a world shift
|
|
7
|
+
* of `dy` maps to `point.y -= dy`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function projectRoom(room: MapData.Room, x: number, y: number, area: number, z: number): MapData.Room;
|
|
10
|
+
/** One neighbouring-area room, with its position projected into the current area's frame. */
|
|
11
|
+
export interface ProjectedRoom {
|
|
12
|
+
/** The real room (its `id` is preserved so the rendered shape stays clickable). */
|
|
13
|
+
room: MapData.Room;
|
|
14
|
+
/** Projected X in the current area's coordinate space. */
|
|
15
|
+
x: number;
|
|
16
|
+
/** Projected Y in the current area's coordinate space. */
|
|
17
|
+
y: number;
|
|
18
|
+
}
|
|
19
|
+
/** A connector line between two projected room centres (current-area frame). */
|
|
20
|
+
export interface ProjectedEdge {
|
|
21
|
+
ax: number;
|
|
22
|
+
ay: number;
|
|
23
|
+
bx: number;
|
|
24
|
+
by: number;
|
|
25
|
+
}
|
|
26
|
+
/** Result of {@link computeNeighborSpill}: faded preview geometry for neighbouring areas. */
|
|
27
|
+
export interface NeighborSpill {
|
|
28
|
+
rooms: ProjectedRoom[];
|
|
29
|
+
edges: ProjectedEdge[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Walk the exit graph outward from the player's room (BFS, depth ≤ `maxSteps`)
|
|
33
|
+
* and project the positions of rooms that live in a *different* area onto the
|
|
34
|
+
* current area's coordinate plane, so they can be drawn across the boundary.
|
|
35
|
+
*
|
|
36
|
+
* Areas use independent (area-local) coordinates, so we can't trust a
|
|
37
|
+
* neighbour room's raw x/y to align with the current area. Instead we carry a
|
|
38
|
+
* projected position through the BFS:
|
|
39
|
+
* - within one area, we advance by the real coordinate delta between rooms;
|
|
40
|
+
* - crossing a boundary, we place the target one grid step away in the exit's
|
|
41
|
+
* planar direction (the only geometric anchor we have).
|
|
42
|
+
*
|
|
43
|
+
* Only planar exits (n/s/e/w + diagonals) are followed — non-planar links
|
|
44
|
+
* (up/down/in/out, special exits) can't be placed on the plane. Only rooms on
|
|
45
|
+
* the current z-level (`currentZ`) are collected.
|
|
46
|
+
*
|
|
47
|
+
* Returns `undefined` when there's nothing to draw.
|
|
48
|
+
*/
|
|
49
|
+
export declare function computeNeighborSpill(mapReader: IMapReader, currentAreaId: number, currentZ: number, playerRoomId: number, maxSteps: number, isVisible?: (room: MapData.Room) => boolean): NeighborSpill | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Wraps an {@link IMapReader} so that spilled neighbouring-area rooms appear to
|
|
52
|
+
* live in the current area at their projected positions. {@link getRoom}
|
|
53
|
+
* returns a clone of a spilled room with `x`/`y` swapped for the projected
|
|
54
|
+
* coordinates, `area`/`z` rewritten to the current area+plane, and custom-line
|
|
55
|
+
* points shifted by the same delta so they follow the room; every other room and
|
|
56
|
+
* method passes straight through to the base reader.
|
|
57
|
+
*
|
|
58
|
+
* This lets the overlay code (highlights, paths) treat spilled rooms exactly
|
|
59
|
+
* like current-area rooms: existing area/visibility checks pass for them and
|
|
60
|
+
* all coordinate maths lands on the projected positions, with no special cases.
|
|
61
|
+
*/
|
|
62
|
+
export declare class ProjectedMapReader implements IMapReader {
|
|
63
|
+
private readonly base;
|
|
64
|
+
private readonly currentArea;
|
|
65
|
+
private readonly currentZ;
|
|
66
|
+
private readonly projected;
|
|
67
|
+
constructor(base: IMapReader, currentArea: number, currentZ: number, projected: Map<number, {
|
|
68
|
+
x: number;
|
|
69
|
+
y: number;
|
|
70
|
+
}>);
|
|
71
|
+
getRoom(roomId: number): MapData.Room;
|
|
72
|
+
getArea(areaId: number): IArea;
|
|
73
|
+
getAreas(): IArea[];
|
|
74
|
+
getRooms(): MapData.Room[];
|
|
75
|
+
getColorValue(envId: number): string;
|
|
76
|
+
getSymbolColor(envId: number, opacity?: number): string;
|
|
77
|
+
}
|
|
78
|
+
/** Build a roomId → projected-position map from a {@link NeighborSpill}. */
|
|
79
|
+
export declare function spillPositionMap(spill: NeighborSpill): Map<number, {
|
|
80
|
+
x: number;
|
|
81
|
+
y: number;
|
|
82
|
+
}>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HiddenRoomMode } from '../types/Settings';
|
|
2
|
+
/**
|
|
3
|
+
* userData key Mudlet uses for a room's hidden state on pre-v21 map formats
|
|
4
|
+
* (case-insensitive `"true"`). On v21+ formats Mudlet stores this as a binary
|
|
5
|
+
* `hidden` field instead — which the JSON pipeline does not currently surface,
|
|
6
|
+
* so only maps carrying this fallback key are detected as hidden here.
|
|
7
|
+
*/
|
|
8
|
+
export declare const ROOM_UI_HIDDEN = "system.fallback_hidden";
|
|
9
|
+
/** userData key for a room's custom border colour. */
|
|
10
|
+
export declare const ROOM_UI_BORDER_COLOR = "room.ui_borderColor";
|
|
11
|
+
/** userData key for a room's custom border thickness (Mudlet clamps it to 1..10). */
|
|
12
|
+
export declare const ROOM_UI_BORDER_THICKNESS = "room.ui_borderThickness";
|
|
13
|
+
/** Whether Mudlet has marked this room hidden on the 2D map. */
|
|
14
|
+
export declare function isRoomHidden(room: MapData.Room): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The room's custom border colour as a CSS colour, or `undefined` when none is
|
|
17
|
+
* set. Mudlet stores it as a Qt `#AARRGGBB` string (see {@link qtColorToCss}).
|
|
18
|
+
*/
|
|
19
|
+
export declare function getRoomBorderColor(room: MapData.Room): string | undefined;
|
|
20
|
+
/** Opacity applied to hidden rooms in {@link HiddenRoomMode} `"faded"`. */
|
|
21
|
+
export declare const HIDDEN_ROOM_FADE = 0.35;
|
|
22
|
+
/**
|
|
23
|
+
* The {@link layoutRoom} options that render a room's hidden state for the given
|
|
24
|
+
* mode (`{}` when the room isn't hidden / the mode draws it normally). Shared by
|
|
25
|
+
* the scene build and the current-room overlay so a redrawn hidden room keeps
|
|
26
|
+
* its fade / dashed border.
|
|
27
|
+
*/
|
|
28
|
+
export declare function hiddenRoomLayoutOptions(room: MapData.Room, mode: HiddenRoomMode): {
|
|
29
|
+
fade?: number;
|
|
30
|
+
dashedBorder?: boolean;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The room's custom border thickness clamped to Mudlet's 1..10 range, or
|
|
34
|
+
* `undefined` when unset or unparseable.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getRoomBorderThickness(room: MapData.Room): number | undefined;
|
|
@@ -10,6 +10,18 @@ export interface RoomLayoutOptions {
|
|
|
10
10
|
* as flat diamonds outside the cube footprint).
|
|
11
11
|
*/
|
|
12
12
|
flatPipeline: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* When set (0..1), the room's fill, border, and symbol colours are drawn at
|
|
15
|
+
* this opacity — used to render hidden rooms faded. Baked into the colour
|
|
16
|
+
* strings so every renderer (Konva, canvas, SVG) honours it identically.
|
|
17
|
+
*/
|
|
18
|
+
fade?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Draw the room with a dashed border at full opacity — a more distinct
|
|
21
|
+
* "hidden" marker than {@link fade}. Suppresses emboss (the dashed outline
|
|
22
|
+
* is the signal) and forces a visible border even when borders are off.
|
|
23
|
+
*/
|
|
24
|
+
dashedBorder?: boolean;
|
|
13
25
|
}
|
|
14
26
|
/**
|
|
15
27
|
* Pure layout for a single room. Returns a {@link GroupShape} positioned at
|
package/dist/types/Settings.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export type LabelRenderMode = "image" | "data" | "none";
|
|
2
2
|
export type CullingMode = "none" | "basic" | "indexed";
|
|
3
3
|
export type RoomShape = "rectangle" | "circle" | "roundedRectangle";
|
|
4
|
+
/**
|
|
5
|
+
* How to render rooms Mudlet has marked hidden (see {@link isRoomHidden}):
|
|
6
|
+
* - `"hide"` — omit them from the scene entirely (Mudlet's default).
|
|
7
|
+
* - `"show"` — draw them exactly like any other room.
|
|
8
|
+
* - `"faded"` — draw them at reduced opacity so they read as de-emphasised.
|
|
9
|
+
* - `"dashed"` — draw them at full opacity but with a dashed border, a more
|
|
10
|
+
* distinct "hidden" marker than a fade (which can read as just another shade).
|
|
11
|
+
*/
|
|
12
|
+
export type HiddenRoomMode = "hide" | "show" | "faded" | "dashed";
|
|
4
13
|
export type RoomContextMenuEventDetail = {
|
|
5
14
|
roomId: number;
|
|
6
15
|
position: {
|
|
@@ -171,12 +180,25 @@ export type Settings = {
|
|
|
171
180
|
width: number;
|
|
172
181
|
height: number;
|
|
173
182
|
} | null;
|
|
183
|
+
/**
|
|
184
|
+
* When true, room bodies that share the same fill/stroke/shape are drawn in
|
|
185
|
+
* a single batched path (one `fill()` + one `stroke()` per style) instead of
|
|
186
|
+
* one draw per room. Big win on large areas with few environment colours;
|
|
187
|
+
* see {@link DrawCommandLayerNode}. Rooms with symbols, emboss, gradient
|
|
188
|
+
* fills, or coloured multi-rings fall back to per-room replay automatically.
|
|
189
|
+
*
|
|
190
|
+
* Off by default: coalescing reorders same-style rooms, which can shift
|
|
191
|
+
* sub-pixel border overlaps where rooms touch. Default: false
|
|
192
|
+
*/
|
|
193
|
+
coalesceRooms: boolean;
|
|
174
194
|
/** How to render room labels: "image" | "data". Default: "image" */
|
|
175
195
|
labelRenderMode: LabelRenderMode;
|
|
176
196
|
/** When true, room labels have transparent backgrounds. Default: false */
|
|
177
197
|
transparentLabels: boolean;
|
|
178
198
|
/** Shape used to render rooms: "rectangle" | "circle" | "roundedRectangle". Default: "rectangle" */
|
|
179
199
|
roomShape: RoomShape;
|
|
200
|
+
/** How to render rooms Mudlet has marked hidden: "hide" | "show" | "faded". Default: "hide" */
|
|
201
|
+
hiddenRooms: HiddenRoomMode;
|
|
180
202
|
/** Style configuration for the player position marker. */
|
|
181
203
|
playerMarker: PlayerMarkerStyle;
|
|
182
204
|
/** Style configuration for room highlights (added via {@link MapRenderer.renderHighlight}). */
|
|
@@ -209,6 +231,13 @@ export type Settings = {
|
|
|
209
231
|
/** Font size (in map units) for area-exit labels. Padding, corner radius, and stroke
|
|
210
232
|
* scale proportionally. Default: 0.3 */
|
|
211
233
|
areaExitLabelFontSize: number;
|
|
234
|
+
/** When true, rooms from neighbouring areas reachable within {@link neighborSpillDistance}
|
|
235
|
+
* steps of the player are drawn (faded) across the boundary, projected into the current
|
|
236
|
+
* area's coordinate space. Requires a known player position. Default: false */
|
|
237
|
+
neighborSpill: boolean;
|
|
238
|
+
/** Max number of steps from the player's room to spill neighbouring-area rooms across a
|
|
239
|
+
* boundary (BFS depth over planar exits). Default: 20 */
|
|
240
|
+
neighborSpillDistance: number;
|
|
212
241
|
};
|
|
213
242
|
/** Creates a new Settings object with default values. */
|
|
214
243
|
export declare function createSettings(): Settings;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mudlet-map-renderer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/Delwing/mudlet-map-renderer"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"node-dijkstra": "^2.5.1"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"mudlet-map-binary-reader": ">=0.
|
|
49
|
+
"mudlet-map-binary-reader": ">=1.0.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependenciesMeta": {
|
|
52
52
|
"mudlet-map-binary-reader": {
|
|
@@ -57,8 +57,10 @@
|
|
|
57
57
|
"@playwright/test": "^1.59.1",
|
|
58
58
|
"@types/node": "^25.6.0",
|
|
59
59
|
"@types/node-dijkstra": "^2.5.6",
|
|
60
|
+
"@types/three": "^0.184.1",
|
|
60
61
|
"canvas": "^3.2.3",
|
|
61
|
-
"mudlet-map-binary-reader": "^0.
|
|
62
|
+
"mudlet-map-binary-reader": "^1.0.1",
|
|
63
|
+
"three": "^0.184.0",
|
|
62
64
|
"tslib": "^2.8.1",
|
|
63
65
|
"tsx": "^4.21.0",
|
|
64
66
|
"typescript": "^6.0.2",
|