mudlet-map-renderer 1.0.0 → 1.1.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/README.md +520 -0
- package/dist/AreaMapRenderer.d.ts +125 -0
- package/dist/CullingManager.d.ts +15 -0
- package/dist/ExitRenderer.d.ts +109 -0
- package/dist/InteractionHandler.d.ts +47 -0
- package/dist/MapGraph.d.ts +28 -0
- package/dist/MapReader-mU_4JWv_.js +224 -0
- package/dist/MapReader-mU_4JWv_.js.map +1 -0
- package/dist/MapState.d.ts +110 -0
- package/dist/PathData.d.ts +18 -0
- package/dist/PathFinder.d.ts +12 -0
- package/dist/ScenePipeline.d.ts +226 -0
- package/dist/SvgTypes.d.ts +21 -0
- package/dist/TypedEventEmitter.d.ts +17 -0
- package/dist/binary/BinaryMapReader.d.ts +36 -0
- package/dist/binary/index.d.ts +2 -0
- package/dist/binary.mjs +34 -0
- package/dist/binary.mjs.map +1 -0
- package/dist/camera/Camera.d.ts +106 -0
- package/dist/coord/CoordFn.d.ts +13 -0
- package/dist/directions.d.ts +25 -0
- package/dist/draw/DrawCommand.d.ts +104 -0
- package/dist/draw/DrawCommandBuilder.d.ts +19 -0
- package/dist/export/CanvasExporter.d.ts +71 -0
- package/dist/export/Exporter.d.ts +58 -0
- package/dist/export/PngExporter.d.ts +23 -0
- package/dist/export/SvgExporter.d.ts +19 -0
- package/dist/export/canvasToBytes.d.ts +19 -0
- package/dist/export/clipSceneToViewport.d.ts +48 -0
- package/dist/export/flushSceneShapes.d.ts +21 -0
- package/dist/export/sceneBounds.d.ts +24 -0
- package/dist/hit/HitTester.d.ts +101 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.mjs +6656 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lens/ExplorationLens.d.ts +29 -0
- package/dist/lens/RoomLens.d.ts +47 -0
- package/dist/lens/composeLenses.d.ts +31 -0
- package/dist/lens/index.d.ts +5 -0
- package/dist/overlay/AmbientLightOverlay.d.ts +32 -0
- package/dist/overlay/LiveEffect.d.ts +33 -0
- package/dist/overlay/SceneOverlay.d.ts +68 -0
- package/dist/reader/Area.d.ts +63 -0
- package/dist/reader/Exit.d.ts +15 -0
- package/dist/reader/MapReader.d.ts +34 -0
- package/dist/reader/Plane.d.ts +33 -0
- package/dist/render/CanvasRenderer.d.ts +17 -0
- package/dist/render/RecordingLayer.d.ts +158 -0
- package/dist/render/SvgRenderer.d.ts +7 -0
- package/dist/render/shapeToRecording.d.ts +3 -0
- package/dist/rendering/KonvaRenderBackend.d.ts +122 -0
- package/dist/rendering/MapRenderer.d.ts +213 -0
- package/dist/rendering/SceneManager.d.ts +54 -0
- package/dist/scene/AmbientLightStyle.d.ts +29 -0
- package/dist/scene/GridStyle.d.ts +21 -0
- package/dist/scene/InnerExitStyle.d.ts +24 -0
- package/dist/scene/OverlayStyle.d.ts +47 -0
- package/dist/scene/RoomStyle.d.ts +32 -0
- package/dist/scene/Shape.d.ts +151 -0
- package/dist/scene/SpecialExitStyle.d.ts +37 -0
- package/dist/scene/StubStyle.d.ts +15 -0
- package/dist/scene/elements/ExitLayout.d.ts +22 -0
- package/dist/scene/elements/GridLayout.d.ts +24 -0
- package/dist/scene/elements/LabelLayout.d.ts +11 -0
- package/dist/scene/elements/OverlayLayout.d.ts +14 -0
- package/dist/scene/elements/RoomLayout.d.ts +19 -0
- package/dist/scene/elements/SpecialExitLayout.d.ts +19 -0
- package/dist/scene/elements/StubLayout.d.ts +19 -0
- package/dist/style/Style.d.ts +60 -0
- package/dist/style/applyStyle.d.ts +3 -0
- package/dist/style/index.d.ts +21 -0
- package/dist/style/shape/BlueprintStyle.d.ts +11 -0
- package/dist/style/shape/ConstructionStyle.d.ts +17 -0
- package/dist/style/shape/IsometricStyle.d.ts +32 -0
- package/dist/style/shape/NeonStyle.d.ts +17 -0
- package/dist/style/shape/ParchmentStyle.d.ts +13 -0
- package/dist/style/shape/SciFiStyle.d.ts +16 -0
- package/dist/style/shape/SketchyStyle.d.ts +22 -0
- package/dist/style/shape/index.d.ts +25 -0
- package/dist/style/shape/paintMap.d.ts +25 -0
- package/dist/style/shape/wobble.d.ts +24 -0
- package/{src/types/MapData.ts → dist/types/MapData.d.ts} +70 -90
- package/dist/types/Settings.d.ts +206 -0
- package/dist/utils/color.d.ts +12 -0
- package/dist/utils/textMeasure.d.ts +38 -0
- package/package.json +67 -37
- package/demo/colors.json +0 -1
- package/demo/index.html +0 -102
- package/demo/main.ts +0 -389
- package/demo/mapExport.json +0 -1
- package/demo/tsconfig.json +0 -11
- package/src/ExitRenderer.ts +0 -275
- package/src/PathFinder.ts +0 -93
- package/src/PathRenderer.ts +0 -129
- package/src/Renderer.ts +0 -374
- package/src/directions.ts +0 -66
- package/src/index.ts +0 -4
- package/src/reader/Area.ts +0 -96
- package/src/reader/Exit.ts +0 -36
- package/src/reader/ExplorationArea.ts +0 -132
- package/src/reader/MapReader.ts +0 -123
- package/src/reader/Plane.ts +0 -42
- package/tsconfig.json +0 -17
- package/vercel.json +0 -5
- package/vite.config.ts +0 -29
- package/vite.demo.config.ts +0 -15
package/src/Renderer.ts
DELETED
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
import Konva from "konva";
|
|
2
|
-
import ExitRenderer from "./ExitRenderer";
|
|
3
|
-
import MapReader from "./reader/MapReader";
|
|
4
|
-
import Exit from "./reader/Exit";
|
|
5
|
-
import PathRenderer from "./PathRenderer";
|
|
6
|
-
|
|
7
|
-
const defaultRoomSize = 0.6;
|
|
8
|
-
const padding = 1;
|
|
9
|
-
const defaultZoom = 75
|
|
10
|
-
const lineColor = 'rgb(225, 255, 225)';
|
|
11
|
-
|
|
12
|
-
export class Settings {
|
|
13
|
-
static roomSize = defaultRoomSize;
|
|
14
|
-
static lineColor = lineColor;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type HighlightData = {
|
|
18
|
-
color: string;
|
|
19
|
-
area: number;
|
|
20
|
-
z: number;
|
|
21
|
-
shape?: Konva.Circle;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export class Renderer {
|
|
25
|
-
|
|
26
|
-
private readonly stage: Konva.Stage;
|
|
27
|
-
private readonly roomLayer: Konva.Layer;
|
|
28
|
-
private readonly linkLayer: Konva.Layer;
|
|
29
|
-
private readonly overlayLayer: Konva.Layer;
|
|
30
|
-
private readonly positionLayer: Konva.Layer;
|
|
31
|
-
private mapReader: MapReader;
|
|
32
|
-
private exitRenderer: ExitRenderer;
|
|
33
|
-
private pathRenderer: PathRenderer;
|
|
34
|
-
private highlights: Map<number, HighlightData> = new Map();
|
|
35
|
-
private currentArea?: number;
|
|
36
|
-
private currentZIndex?: number;
|
|
37
|
-
private currentAreaVersion?: number;
|
|
38
|
-
private positionRender?: Konva.Circle;
|
|
39
|
-
private currentTransition?: Konva.Tween;
|
|
40
|
-
private currentZoom: number = 1;
|
|
41
|
-
|
|
42
|
-
constructor(container: HTMLDivElement, mapReader: MapReader) {
|
|
43
|
-
this.stage = new Konva.Stage({
|
|
44
|
-
container: container,
|
|
45
|
-
width: container.clientWidth,
|
|
46
|
-
height: container.clientHeight,
|
|
47
|
-
draggable: true
|
|
48
|
-
});
|
|
49
|
-
container.addEventListener('resize', () => {
|
|
50
|
-
this.stage.width(container.clientWidth);
|
|
51
|
-
this.stage.height(container.clientHeight);
|
|
52
|
-
this.stage.batchDraw();
|
|
53
|
-
})
|
|
54
|
-
this.linkLayer = new Konva.Layer({
|
|
55
|
-
listening: false,
|
|
56
|
-
});
|
|
57
|
-
this.stage.add(this.linkLayer);
|
|
58
|
-
this.roomLayer = new Konva.Layer();
|
|
59
|
-
this.stage.add(this.roomLayer);
|
|
60
|
-
this.overlayLayer = new Konva.Layer({
|
|
61
|
-
listening: false,
|
|
62
|
-
})
|
|
63
|
-
this.stage.add(this.overlayLayer);
|
|
64
|
-
this.positionLayer = new Konva.Layer({
|
|
65
|
-
listening: false,
|
|
66
|
-
});
|
|
67
|
-
this.stage.add(this.positionLayer);
|
|
68
|
-
this.mapReader = mapReader;
|
|
69
|
-
this.exitRenderer = new ExitRenderer(mapReader);
|
|
70
|
-
this.pathRenderer = new PathRenderer(mapReader, this.overlayLayer);
|
|
71
|
-
|
|
72
|
-
const scaleBy = 1.1;
|
|
73
|
-
this.initScaling(scaleBy);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private initScaling(scaleBy: number) {
|
|
77
|
-
this.stage.on('wheel', (e) => {
|
|
78
|
-
e.evt.preventDefault();
|
|
79
|
-
|
|
80
|
-
const oldScale = this.stage.scaleX();
|
|
81
|
-
const pointer = this.stage.getPointerPosition();
|
|
82
|
-
if (!pointer) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const mousePointTo = {
|
|
87
|
-
x: (pointer.x - this.stage.x()) / oldScale,
|
|
88
|
-
y: (pointer.y - this.stage.y()) / oldScale,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
let direction = e.evt.deltaY > 0 ? -1 : 1;
|
|
92
|
-
|
|
93
|
-
if (e.evt.ctrlKey) {
|
|
94
|
-
direction = -direction;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const newZoom = direction > 0 ? this.currentZoom * scaleBy : this.currentZoom / scaleBy;
|
|
98
|
-
const newScale = newZoom * defaultZoom;
|
|
99
|
-
this.setZoom(newZoom);
|
|
100
|
-
|
|
101
|
-
const newPos = {
|
|
102
|
-
x: pointer.x - mousePointTo.x * newScale,
|
|
103
|
-
y: pointer.y - mousePointTo.y * newScale,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
this.stage.position(newPos);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
drawArea(id: number, zIndex: number) {
|
|
111
|
-
const area = this.mapReader.getArea(id);
|
|
112
|
-
if (!area) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const plane = area.getPlane(zIndex);
|
|
116
|
-
if (!plane) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
this.currentArea = id;
|
|
120
|
-
this.currentZIndex = zIndex;
|
|
121
|
-
this.currentAreaVersion = area.getVersion();
|
|
122
|
-
this.roomLayer.destroyChildren();
|
|
123
|
-
this.linkLayer.destroyChildren();
|
|
124
|
-
|
|
125
|
-
const {minX, maxX, minY, maxY} = plane.getBounds();
|
|
126
|
-
|
|
127
|
-
this.stage.offset({x: minX - padding, y: minY - padding});
|
|
128
|
-
this.stage.scale({x: defaultZoom * this.currentZoom, y: defaultZoom * this.currentZoom});
|
|
129
|
-
|
|
130
|
-
this.renderLabels(plane.getLabels());
|
|
131
|
-
this.renderRooms(plane.getRooms() ?? []);
|
|
132
|
-
this.renderExits(area.getLinkExits(zIndex));
|
|
133
|
-
this.refreshHighlights();
|
|
134
|
-
this.stage.batchDraw();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
setZoom(zoom: number) {
|
|
138
|
-
this.currentZoom = zoom;
|
|
139
|
-
this.stage.scale({x: defaultZoom * zoom, y: defaultZoom * zoom});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
getZoom() {
|
|
143
|
-
return this.currentZoom;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
getCurrentArea() {
|
|
147
|
-
return this.currentArea ? this.mapReader.getArea(this.currentArea) : undefined
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
setPosition(roomId: number) {
|
|
151
|
-
const room = this.mapReader.getRoom(roomId);
|
|
152
|
-
if (!room) return;
|
|
153
|
-
const area = this.mapReader.getArea(room.area);
|
|
154
|
-
const areaVersion = area?.getVersion();
|
|
155
|
-
let instant = this.currentArea !== room.area || this.currentZIndex !== room.z
|
|
156
|
-
if (this.currentArea !== room.area || this.currentZIndex !== room.z || (areaVersion !== undefined && this.currentAreaVersion !== areaVersion)) {
|
|
157
|
-
this.drawArea(room.area, room.z);
|
|
158
|
-
}
|
|
159
|
-
if (!this.positionRender) {
|
|
160
|
-
this.positionRender = new Konva.Circle({
|
|
161
|
-
x: room.x,
|
|
162
|
-
y: room.y,
|
|
163
|
-
radius: defaultRoomSize * 0.85,
|
|
164
|
-
stroke: "rgb(0, 229, 178)",
|
|
165
|
-
strokeWidth: 0.1,
|
|
166
|
-
dash: [0.05, 0.05],
|
|
167
|
-
dashEnabled: true,
|
|
168
|
-
})
|
|
169
|
-
this.positionLayer.add(this.positionRender);
|
|
170
|
-
}
|
|
171
|
-
this.centerOnRoom(room, instant);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
renderPath(locations: number[]) {
|
|
175
|
-
return this.pathRenderer.renderPath(locations, this.currentArea, this.currentZIndex);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
clearPaths() {
|
|
179
|
-
this.pathRenderer.clearPaths();
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
renderHighlight(roomId: number, color: string) {
|
|
183
|
-
const room = this.mapReader.getRoom(roomId);
|
|
184
|
-
if (!room) {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const existing = this.highlights.get(roomId);
|
|
189
|
-
if (existing?.shape) {
|
|
190
|
-
existing.shape.destroy();
|
|
191
|
-
delete existing.shape;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const highlightData: HighlightData = {color, area: room.area, z: room.z};
|
|
195
|
-
|
|
196
|
-
this.highlights.set(roomId, highlightData);
|
|
197
|
-
|
|
198
|
-
if (room.area === this.currentArea && room.z === this.currentZIndex) {
|
|
199
|
-
const shape = this.createHighlightShape(room, color);
|
|
200
|
-
this.overlayLayer.add(shape);
|
|
201
|
-
highlightData.shape = shape;
|
|
202
|
-
this.overlayLayer.batchDraw();
|
|
203
|
-
return shape;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return highlightData.shape;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
clearHighlights() {
|
|
210
|
-
this.highlights.forEach(({shape}) => shape?.destroy());
|
|
211
|
-
this.highlights.clear();
|
|
212
|
-
this.overlayLayer.batchDraw();
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
private refreshHighlights() {
|
|
216
|
-
this.highlights.forEach((highlight, roomId) => {
|
|
217
|
-
highlight.shape?.destroy();
|
|
218
|
-
delete highlight.shape;
|
|
219
|
-
|
|
220
|
-
if (highlight.area !== this.currentArea || highlight.z !== this.currentZIndex) {
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const room = this.mapReader.getRoom(roomId);
|
|
225
|
-
if (!room) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const shape = this.createHighlightShape(room, highlight.color);
|
|
230
|
-
this.overlayLayer.add(shape);
|
|
231
|
-
highlight.shape = shape;
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
this.overlayLayer.batchDraw();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
private createHighlightShape(room: MapData.Room, color: string) {
|
|
238
|
-
return new Konva.Circle({
|
|
239
|
-
x: room.x,
|
|
240
|
-
y: room.y,
|
|
241
|
-
radius: Settings.roomSize * 0.9,
|
|
242
|
-
stroke: color,
|
|
243
|
-
strokeWidth: 0.15,
|
|
244
|
-
dash: [0.1, 0.05],
|
|
245
|
-
dashEnabled: true,
|
|
246
|
-
listening: false,
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
private centerOnRoom(room: MapData.Room, instant: boolean = false) {
|
|
251
|
-
const roomCenter = {x: room.x, y: room.y};
|
|
252
|
-
|
|
253
|
-
this.positionRender?.position(room)
|
|
254
|
-
|
|
255
|
-
const abs = this.stage.getAbsoluteTransform()
|
|
256
|
-
const screenPoint = abs.point(roomCenter);
|
|
257
|
-
|
|
258
|
-
const target = {
|
|
259
|
-
x: this.stage.width() / 2,
|
|
260
|
-
y: this.stage.height() / 2,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const dx = target.x - screenPoint.x;
|
|
264
|
-
const dy = target.y - screenPoint.y;
|
|
265
|
-
|
|
266
|
-
if (this.currentTransition) {
|
|
267
|
-
this.currentTransition.pause()
|
|
268
|
-
this.currentTransition.destroy()
|
|
269
|
-
delete this.currentTransition;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (instant) {
|
|
273
|
-
this.stage.position({
|
|
274
|
-
x: this.stage.x() + dx,
|
|
275
|
-
y: this.stage.y() + dy,
|
|
276
|
-
})
|
|
277
|
-
} else {
|
|
278
|
-
this.currentTransition = new Konva.Tween({
|
|
279
|
-
node: this.stage,
|
|
280
|
-
x: this.stage.x() + dx,
|
|
281
|
-
y: this.stage.y() + dy,
|
|
282
|
-
duration: 0.2,
|
|
283
|
-
easing: Konva.Easings.EaseInOut,
|
|
284
|
-
})
|
|
285
|
-
this.currentTransition.play()
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
private renderRooms(rooms: MapData.Room[]) {
|
|
290
|
-
rooms.forEach(room => {
|
|
291
|
-
const roomRender = new Konva.Group({
|
|
292
|
-
x: room.x - Settings.roomSize / 2,
|
|
293
|
-
y: room.y - Settings.roomSize / 2,
|
|
294
|
-
});
|
|
295
|
-
const roomRect = new Konva.Rect({
|
|
296
|
-
x: 0,
|
|
297
|
-
y: 0,
|
|
298
|
-
width: Settings.roomSize,
|
|
299
|
-
height: Settings.roomSize,
|
|
300
|
-
fill: this.mapReader.getColorValue(room.env),
|
|
301
|
-
strokeWidth: 0.025,
|
|
302
|
-
stroke: Settings.lineColor,
|
|
303
|
-
});
|
|
304
|
-
roomRender.on('mouseenter', () => {
|
|
305
|
-
this.stage.container().style.cursor = 'pointer';
|
|
306
|
-
})
|
|
307
|
-
roomRender.on('mouseleave', () => {
|
|
308
|
-
this.stage.container().style.cursor = 'auto';
|
|
309
|
-
})
|
|
310
|
-
roomRender.add(roomRect);
|
|
311
|
-
this.renderSymbol(room, roomRender);
|
|
312
|
-
this.roomLayer.add(roomRender);
|
|
313
|
-
|
|
314
|
-
this.exitRenderer.renderSpecialExits(room).forEach(render => {
|
|
315
|
-
this.linkLayer.add(render)
|
|
316
|
-
})
|
|
317
|
-
this.exitRenderer.renderStubs(room).forEach(render => {
|
|
318
|
-
this.linkLayer.add(render)
|
|
319
|
-
})
|
|
320
|
-
this.exitRenderer.renderInnerExits(room).forEach(render => {
|
|
321
|
-
this.roomLayer.add(render)
|
|
322
|
-
})
|
|
323
|
-
})
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
private renderSymbol(room: MapData.Room, roomRender: Konva.Group) {
|
|
327
|
-
if (room.roomChar !== undefined) {
|
|
328
|
-
const roomChar = new Konva.Text({
|
|
329
|
-
x: 0,
|
|
330
|
-
y: 0,
|
|
331
|
-
text: room.roomChar,
|
|
332
|
-
fontSize: 0.45,
|
|
333
|
-
fontStyle: "bold",
|
|
334
|
-
fill: this.mapReader.getSymbolColor(room.env),
|
|
335
|
-
align: "center",
|
|
336
|
-
verticalAlign: "middle",
|
|
337
|
-
width: Settings.roomSize,
|
|
338
|
-
height: Settings.roomSize,
|
|
339
|
-
})
|
|
340
|
-
roomRender.add(roomChar);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private renderExits(exits: Exit[]) {
|
|
345
|
-
exits.forEach(exit => {
|
|
346
|
-
const render = this.exitRenderer.render(exit);
|
|
347
|
-
if (!render) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
this.linkLayer.add(render);
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
private renderLabels(Labels: MapData.Label[]) {
|
|
356
|
-
Labels.forEach(label => {
|
|
357
|
-
if (!label.pixMap) {
|
|
358
|
-
return
|
|
359
|
-
}
|
|
360
|
-
const image = new Image()
|
|
361
|
-
image.src = `data:image/png;base64,${label.pixMap}`
|
|
362
|
-
const labelRender = new Konva.Image({
|
|
363
|
-
x: label.X,
|
|
364
|
-
y: -label.Y,
|
|
365
|
-
width: label.Width,
|
|
366
|
-
height: label.Height,
|
|
367
|
-
image: image
|
|
368
|
-
})
|
|
369
|
-
this.linkLayer.add(labelRender)
|
|
370
|
-
})
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
package/src/directions.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
export type PlanarDirection =
|
|
2
|
-
| "north"
|
|
3
|
-
| "south"
|
|
4
|
-
| "east"
|
|
5
|
-
| "west"
|
|
6
|
-
| "northeast"
|
|
7
|
-
| "northwest"
|
|
8
|
-
| "southeast"
|
|
9
|
-
| "southwest";
|
|
10
|
-
|
|
11
|
-
const planarDirectionOffsets: Record<PlanarDirection, {x: number; y: number}> = {
|
|
12
|
-
north: {x: 0, y: -1},
|
|
13
|
-
south: {x: 0, y: 1},
|
|
14
|
-
east: {x: 1, y: 0},
|
|
15
|
-
west: {x: -1, y: 0},
|
|
16
|
-
northeast: {x: 1, y: -1},
|
|
17
|
-
northwest: {x: -1, y: -1},
|
|
18
|
-
southeast: {x: 1, y: 1},
|
|
19
|
-
southwest: {x: -1, y: 1},
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const planarDirections: PlanarDirection[] = [
|
|
23
|
-
"north",
|
|
24
|
-
"south",
|
|
25
|
-
"east",
|
|
26
|
-
"west",
|
|
27
|
-
"northeast",
|
|
28
|
-
"northwest",
|
|
29
|
-
"southeast",
|
|
30
|
-
"southwest",
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
export const oppositeDirections: Record<PlanarDirection, PlanarDirection> = {
|
|
34
|
-
north: "south",
|
|
35
|
-
south: "north",
|
|
36
|
-
east: "west",
|
|
37
|
-
west: "east",
|
|
38
|
-
northeast: "southwest",
|
|
39
|
-
northwest: "southeast",
|
|
40
|
-
southeast: "northwest",
|
|
41
|
-
southwest: "northeast",
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
function isPlanarDirection(direction: MapData.direction | undefined): direction is PlanarDirection {
|
|
45
|
-
if (!direction) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return Object.prototype.hasOwnProperty.call(planarDirectionOffsets, direction);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function movePoint(
|
|
52
|
-
x: number,
|
|
53
|
-
y: number,
|
|
54
|
-
direction?: MapData.direction,
|
|
55
|
-
distance: number = 1,
|
|
56
|
-
) {
|
|
57
|
-
if (!isPlanarDirection(direction)) {
|
|
58
|
-
return {x, y};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const offset = planarDirectionOffsets[direction];
|
|
62
|
-
return {
|
|
63
|
-
x: x + offset.x * distance,
|
|
64
|
-
y: y + offset.y * distance,
|
|
65
|
-
};
|
|
66
|
-
}
|
package/src/index.ts
DELETED
package/src/reader/Area.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import Plane from "./Plane";
|
|
2
|
-
|
|
3
|
-
import Exit, {longToShort, regularExits} from "./Exit";
|
|
4
|
-
|
|
5
|
-
export default class Area {
|
|
6
|
-
|
|
7
|
-
private readonly planes: Record<number, Plane> = {};
|
|
8
|
-
private readonly area: MapData.Area;
|
|
9
|
-
private readonly exits: Map<string, Exit> = new Map();
|
|
10
|
-
private version = 0;
|
|
11
|
-
|
|
12
|
-
constructor(area: MapData.Area) {
|
|
13
|
-
this.area = area;
|
|
14
|
-
this.planes = this.createPlanes();
|
|
15
|
-
this.createExits();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
getAreaName() {
|
|
19
|
-
return this.area.areaName
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
getAreaId() {
|
|
23
|
-
return parseInt(this.area.areaId)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
getVersion() {
|
|
27
|
-
return this.version;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
protected markDirty() {
|
|
31
|
-
this.version++;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
getPlane(zIndex: number) {
|
|
35
|
-
return this.planes[zIndex];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
getPlanes() {
|
|
39
|
-
return Object.values(this.planes);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
getRooms() {
|
|
43
|
-
return this.area.rooms
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getLinkExits(zIndex: number) {
|
|
47
|
-
return Array.from(this.exits.values()).filter(e => e.zIndex.includes(zIndex));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private createPlanes() {
|
|
51
|
-
const grouped = this.area.rooms.reduce<Record<number, MapData.Room[]>>((acc, room) => {
|
|
52
|
-
if (!acc[room.z]) {
|
|
53
|
-
acc[room.z] = [];
|
|
54
|
-
}
|
|
55
|
-
// @ts-ignore
|
|
56
|
-
acc[room.z].push(room);
|
|
57
|
-
return acc;
|
|
58
|
-
}, {});
|
|
59
|
-
return Object.entries(grouped).reduce(
|
|
60
|
-
(acc, [z, rooms]) => {
|
|
61
|
-
acc[+z] = new Plane(rooms, this.area.labels.filter(label => label.Z === +z));
|
|
62
|
-
return acc;
|
|
63
|
-
},
|
|
64
|
-
{} as Record<number, Plane>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private createExits() {
|
|
69
|
-
this.area.rooms.forEach(room => {
|
|
70
|
-
Object.entries(room.exits)
|
|
71
|
-
.filter(([direction, _]) => regularExits.indexOf(direction as MapData.direction) > -1 && !room.customLines.hasOwnProperty(longToShort[direction as MapData.direction]))
|
|
72
|
-
.forEach(([direction, targetRoomId]) => this.createHalfExit(room.id, targetRoomId, room.z, direction as MapData.direction))
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private createHalfExit(originRoom: number, targetRoom: number, zIndex: number, direction: MapData.direction,) {
|
|
77
|
-
if (originRoom === targetRoom) {
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
const a = Math.min(originRoom, targetRoom);
|
|
81
|
-
const b = Math.max(originRoom, targetRoom);
|
|
82
|
-
const key = `${a}-${b}`;
|
|
83
|
-
let edge = this.exits.get(key);
|
|
84
|
-
if (!edge) {
|
|
85
|
-
edge = {a: a, b: b, zIndex: [zIndex]};
|
|
86
|
-
}
|
|
87
|
-
if (a == originRoom) {
|
|
88
|
-
edge.aDir = direction;
|
|
89
|
-
} else {
|
|
90
|
-
edge.bDir = direction;
|
|
91
|
-
}
|
|
92
|
-
edge.zIndex.push(zIndex);
|
|
93
|
-
this.exits.set(key, edge);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
}
|
package/src/reader/Exit.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export type Kind = "exit" | "specialExit";
|
|
2
|
-
|
|
3
|
-
export default interface Exit {
|
|
4
|
-
a: number;
|
|
5
|
-
b: number;
|
|
6
|
-
aDir?: MapData.direction;
|
|
7
|
-
bDir?: MapData.direction;
|
|
8
|
-
kind?: Kind;
|
|
9
|
-
zIndex: number[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const regularExits: MapData.direction[] = ["north", "south", "east", "west", "northeast", "northwest", "southeast", "southwest"];
|
|
13
|
-
export const shortTolong: Record<string, MapData.direction> = {
|
|
14
|
-
"n": "north",
|
|
15
|
-
"s": "south",
|
|
16
|
-
"e": "east",
|
|
17
|
-
"w": "west",
|
|
18
|
-
"ne": "northeast",
|
|
19
|
-
"nw": "northwest",
|
|
20
|
-
"se": "southeast",
|
|
21
|
-
"sw": "southwest",
|
|
22
|
-
}
|
|
23
|
-
export const longToShort: Record<MapData.direction, string> = {
|
|
24
|
-
"north": "n",
|
|
25
|
-
"south": "s",
|
|
26
|
-
"east": "e",
|
|
27
|
-
"west": "w",
|
|
28
|
-
"northeast": "ne",
|
|
29
|
-
"northwest": "nw",
|
|
30
|
-
"southeast": "se",
|
|
31
|
-
"southwest": "sw",
|
|
32
|
-
"up": "u",
|
|
33
|
-
"down": "d",
|
|
34
|
-
"in": "i",
|
|
35
|
-
"out": "o"
|
|
36
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import Area from "./Area";
|
|
2
|
-
import Plane from "./Plane";
|
|
3
|
-
import Exit from "./Exit";
|
|
4
|
-
|
|
5
|
-
class ExplorationPlane extends Plane {
|
|
6
|
-
|
|
7
|
-
private readonly basePlane: Plane;
|
|
8
|
-
private readonly visitedRooms: Set<number>;
|
|
9
|
-
|
|
10
|
-
constructor(plane: Plane, visitedRooms: Set<number>) {
|
|
11
|
-
super(plane.getRooms(), plane.getLabels());
|
|
12
|
-
this.basePlane = plane;
|
|
13
|
-
this.visitedRooms = visitedRooms;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
override getRooms() {
|
|
17
|
-
return this.basePlane.getRooms().filter(room => this.visitedRooms.has(room.id));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
override getLabels() {
|
|
21
|
-
return this.basePlane.getLabels();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
override getBounds() {
|
|
25
|
-
const rooms = this.getRooms();
|
|
26
|
-
if (!rooms.length) {
|
|
27
|
-
return this.basePlane.getBounds();
|
|
28
|
-
}
|
|
29
|
-
return rooms.reduce(
|
|
30
|
-
(acc, room) => ({
|
|
31
|
-
minX: Math.min(acc.minX, room.x),
|
|
32
|
-
maxX: Math.max(acc.maxX, room.x),
|
|
33
|
-
minY: Math.min(acc.minY, room.y),
|
|
34
|
-
maxY: Math.max(acc.maxY, room.y),
|
|
35
|
-
}),
|
|
36
|
-
{
|
|
37
|
-
minX: Number.POSITIVE_INFINITY,
|
|
38
|
-
maxX: Number.NEGATIVE_INFINITY,
|
|
39
|
-
minY: Number.POSITIVE_INFINITY,
|
|
40
|
-
maxY: Number.NEGATIVE_INFINITY,
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export default class ExplorationArea extends Area {
|
|
48
|
-
|
|
49
|
-
private readonly visitedRooms: Set<number>;
|
|
50
|
-
private readonly areaRoomIds: Set<number>;
|
|
51
|
-
private readonly planeCache: WeakMap<Plane, ExplorationPlane> = new WeakMap();
|
|
52
|
-
|
|
53
|
-
constructor(area: MapData.Area, visitedRooms?: Iterable<number> | Set<number>) {
|
|
54
|
-
super(area);
|
|
55
|
-
this.visitedRooms = visitedRooms instanceof Set ? visitedRooms : new Set(visitedRooms ?? []);
|
|
56
|
-
this.areaRoomIds = new Set(area.rooms.map(room => room.id));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
override getPlane(zIndex: number) {
|
|
60
|
-
const basePlane = super.getPlane(zIndex);
|
|
61
|
-
if (!basePlane) {
|
|
62
|
-
return basePlane;
|
|
63
|
-
}
|
|
64
|
-
let decorated = this.planeCache.get(basePlane);
|
|
65
|
-
if (!decorated) {
|
|
66
|
-
decorated = new ExplorationPlane(basePlane, this.visitedRooms);
|
|
67
|
-
this.planeCache.set(basePlane, decorated);
|
|
68
|
-
}
|
|
69
|
-
return decorated;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
override getPlanes() {
|
|
73
|
-
return super.getPlanes().map(plane => {
|
|
74
|
-
let decorated = this.planeCache.get(plane);
|
|
75
|
-
if (!decorated) {
|
|
76
|
-
decorated = new ExplorationPlane(plane, this.visitedRooms);
|
|
77
|
-
this.planeCache.set(plane, decorated);
|
|
78
|
-
}
|
|
79
|
-
return decorated;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
override getLinkExits(zIndex: number) {
|
|
84
|
-
return super
|
|
85
|
-
.getLinkExits(zIndex)
|
|
86
|
-
.filter((exit: Exit) => this.visitedRooms.has(exit.a) || this.visitedRooms.has(exit.b));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
getVisitedRoomCount() {
|
|
90
|
-
return super.getRooms().reduce((count, room) => count + (this.visitedRooms.has(room.id) ? 1 : 0), 0);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
getTotalRoomCount() {
|
|
94
|
-
return this.areaRoomIds.size;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
hasVisitedRoom(roomId: number) {
|
|
98
|
-
return this.areaRoomIds.has(roomId) && this.visitedRooms.has(roomId);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
getVisitedRoomIds() {
|
|
102
|
-
return super.getRooms()
|
|
103
|
-
.filter(room => this.visitedRooms.has(room.id))
|
|
104
|
-
.map(room => room.id);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
addVisitedRoom(roomId: number) {
|
|
108
|
-
const wasVisited = this.visitedRooms.has(roomId);
|
|
109
|
-
this.visitedRooms.add(roomId);
|
|
110
|
-
const newlyVisited = !wasVisited && this.areaRoomIds.has(roomId);
|
|
111
|
-
if (newlyVisited) {
|
|
112
|
-
this.markDirty();
|
|
113
|
-
}
|
|
114
|
-
return newlyVisited;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
addVisitedRooms(roomIds: Iterable<number>) {
|
|
118
|
-
let newlyVisited = 0;
|
|
119
|
-
for (const roomId of roomIds) {
|
|
120
|
-
const wasVisited = this.visitedRooms.has(roomId);
|
|
121
|
-
this.visitedRooms.add(roomId);
|
|
122
|
-
if (!wasVisited && this.areaRoomIds.has(roomId)) {
|
|
123
|
-
newlyVisited++;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (newlyVisited > 0) {
|
|
127
|
-
this.markDirty();
|
|
128
|
-
}
|
|
129
|
-
return newlyVisited;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
}
|