parse-tmx 4.1.1 → 4.2.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/package.json +5 -5
- package/dist/index.d.ts +0 -200
- package/dist/index.js +0 -761
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "parse-tmx",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "A parser for tmx.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"game-development",
|
|
@@ -52,18 +52,18 @@
|
|
|
52
52
|
"typecheck": "tsc"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@esposter/shared": "4.
|
|
55
|
+
"@esposter/shared": "4.2.0",
|
|
56
56
|
"neverthrow": "^8.2.0",
|
|
57
57
|
"sax": "^1.6.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@arethetypeswrong/core": "^0.18.5",
|
|
61
|
-
"@esposter/configuration": "4.
|
|
62
|
-
"@esposter/shared-node": "4.
|
|
61
|
+
"@esposter/configuration": "4.2.0",
|
|
62
|
+
"@esposter/shared-node": "4.2.0",
|
|
63
63
|
"@types/sax": "^1.2.7",
|
|
64
64
|
"publint": "^0.3.25",
|
|
65
65
|
"tsdown": "^0.23.1",
|
|
66
66
|
"vitest": "^5.0.4"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "fef4971cf6a621a2c1850f32fcec19ee4ec0de99"
|
|
69
69
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { Result, ResultAsync } from "neverthrow";
|
|
2
|
-
//#region src/models/Shape.d.ts
|
|
3
|
-
export declare enum Shape {
|
|
4
|
-
Ellipse = "ellipse",
|
|
5
|
-
Point = "point",
|
|
6
|
-
Polygon = "polygon",
|
|
7
|
-
Polyline = "polyline",
|
|
8
|
-
Rectangle = "rectangle"
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region src/models/tmx/parsed/TMXAnimationFrameParsed.d.ts
|
|
12
|
-
interface TMXAnimationFrameParsed {
|
|
13
|
-
duration: number;
|
|
14
|
-
tileid: number;
|
|
15
|
-
}
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/models/tmx/parsed/TMXAnimationParsed.d.ts
|
|
18
|
-
interface TMXAnimationParsed {
|
|
19
|
-
frames: TMXAnimationFrameParsed[];
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region src/models/tmx/parsed/TMXFlipsParsed.d.ts
|
|
23
|
-
interface TMXFlipsParsed {
|
|
24
|
-
Diagonal: boolean;
|
|
25
|
-
Horizontal: boolean;
|
|
26
|
-
Vertical: boolean;
|
|
27
|
-
}
|
|
28
|
-
//#endregion
|
|
29
|
-
//#region src/models/tmx/parsed/TMXChunkParsed.d.ts
|
|
30
|
-
interface TMXChunkParsed {
|
|
31
|
-
data?: number[];
|
|
32
|
-
flips?: TMXFlipsParsed[];
|
|
33
|
-
height: number;
|
|
34
|
-
width: number;
|
|
35
|
-
x: number;
|
|
36
|
-
y: number;
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/models/tmx/parsed/TMXExportParsed.d.ts
|
|
40
|
-
interface TMXExportParsed {
|
|
41
|
-
format: string;
|
|
42
|
-
target: string;
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region src/models/tmx/parsed/TMXEditorSettingsParsed.d.ts
|
|
46
|
-
interface TMXEditorSettingsParsed {
|
|
47
|
-
export?: TMXExportParsed;
|
|
48
|
-
}
|
|
49
|
-
//#endregion
|
|
50
|
-
//#region src/models/tmx/parsed/TMXImageParsed.d.ts
|
|
51
|
-
interface TMXImageParsed {
|
|
52
|
-
format?: string;
|
|
53
|
-
height: number;
|
|
54
|
-
source: string;
|
|
55
|
-
trans?: string;
|
|
56
|
-
width: number;
|
|
57
|
-
}
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/models/tmx/parsed/TMXPropertyParsed.d.ts
|
|
60
|
-
interface TMXPropertyParsed {
|
|
61
|
-
name: string;
|
|
62
|
-
properties?: TMXPropertiesParsed;
|
|
63
|
-
value: boolean | number | string;
|
|
64
|
-
}
|
|
65
|
-
//#endregion
|
|
66
|
-
//#region src/models/tmx/parsed/TMXPropertiesParsed.d.ts
|
|
67
|
-
type TMXPropertiesParsed = TMXPropertyParsed[];
|
|
68
|
-
//#endregion
|
|
69
|
-
//#region src/models/tmx/parsed/TMXObjectParsed.d.ts
|
|
70
|
-
interface TMXObjectParsed {
|
|
71
|
-
flips?: TMXFlipsParsed;
|
|
72
|
-
gid?: number;
|
|
73
|
-
height: number;
|
|
74
|
-
id: number;
|
|
75
|
-
name: string;
|
|
76
|
-
points?: [number, number][];
|
|
77
|
-
properties?: TMXPropertiesParsed;
|
|
78
|
-
rotation?: number;
|
|
79
|
-
shape: Shape;
|
|
80
|
-
template?: string;
|
|
81
|
-
text?: string;
|
|
82
|
-
type: string;
|
|
83
|
-
visible?: number;
|
|
84
|
-
width: number;
|
|
85
|
-
x: number;
|
|
86
|
-
y: number;
|
|
87
|
-
}
|
|
88
|
-
//#endregion
|
|
89
|
-
//#region src/models/tmx/parsed/TMXTileParsed.d.ts
|
|
90
|
-
interface TMXTileParsed {
|
|
91
|
-
animation?: TMXAnimationParsed;
|
|
92
|
-
id: number;
|
|
93
|
-
image?: TMXImageParsed;
|
|
94
|
-
objects?: TMXObjectParsed[];
|
|
95
|
-
probability?: number;
|
|
96
|
-
properties?: TMXPropertiesParsed;
|
|
97
|
-
terrain?: string;
|
|
98
|
-
type?: string;
|
|
99
|
-
}
|
|
100
|
-
//#endregion
|
|
101
|
-
//#region src/models/tmx/parsed/TMXEmbeddedTilesetParsed.d.ts
|
|
102
|
-
interface TMXEmbeddedTilesetParsed {
|
|
103
|
-
columns: number;
|
|
104
|
-
firstgid: number;
|
|
105
|
-
image?: TMXImageParsed;
|
|
106
|
-
margin?: number;
|
|
107
|
-
name: string;
|
|
108
|
-
spacing?: number;
|
|
109
|
-
tilecount: number;
|
|
110
|
-
tileheight: number;
|
|
111
|
-
tiles: TMXTileParsed[];
|
|
112
|
-
tilewidth: number;
|
|
113
|
-
}
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/models/tmx/parsed/TMXExternalTilesetParsed.d.ts
|
|
116
|
-
interface TMXExternalTilesetParsed {
|
|
117
|
-
firstgid: number;
|
|
118
|
-
source: string;
|
|
119
|
-
}
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/models/tmx/shared/TMXGroupLayerShared.d.ts
|
|
122
|
-
interface TMXGroupLayerShared {
|
|
123
|
-
class?: string;
|
|
124
|
-
id: number;
|
|
125
|
-
name: string;
|
|
126
|
-
offsetx?: number;
|
|
127
|
-
offsety?: number;
|
|
128
|
-
opacity?: number;
|
|
129
|
-
parallaxx?: number;
|
|
130
|
-
parallaxy?: number;
|
|
131
|
-
tintcolor?: string;
|
|
132
|
-
type: string;
|
|
133
|
-
visible?: number;
|
|
134
|
-
}
|
|
135
|
-
//#endregion
|
|
136
|
-
//#region src/models/tmx/parsed/TMXLayerParsed.d.ts
|
|
137
|
-
interface TMXLayerParsed extends TMXGroupLayerShared {
|
|
138
|
-
chunks?: TMXChunkParsed[];
|
|
139
|
-
color?: string;
|
|
140
|
-
data?: number[];
|
|
141
|
-
draworder?: string;
|
|
142
|
-
flips?: TMXFlipsParsed[];
|
|
143
|
-
height?: number;
|
|
144
|
-
image?: TMXImageParsed;
|
|
145
|
-
locked?: number;
|
|
146
|
-
objects?: TMXObjectParsed[];
|
|
147
|
-
properties?: TMXPropertiesParsed;
|
|
148
|
-
width?: number;
|
|
149
|
-
x?: number;
|
|
150
|
-
y?: number;
|
|
151
|
-
}
|
|
152
|
-
//#endregion
|
|
153
|
-
//#region src/models/tmx/parsed/TMXGroupLayerParsed.d.ts
|
|
154
|
-
interface TMXGroupLayerParsed extends TMXGroupLayerShared {
|
|
155
|
-
layers: (TMXGroupLayerParsed | TMXLayerParsed)[];
|
|
156
|
-
properties?: TMXPropertiesParsed;
|
|
157
|
-
}
|
|
158
|
-
//#endregion
|
|
159
|
-
//#region src/models/tmx/parsed/TMXTilesetParsed.d.ts
|
|
160
|
-
type TMXTilesetParsed = TMXEmbeddedTilesetParsed | TMXExternalTilesetParsed;
|
|
161
|
-
//#endregion
|
|
162
|
-
//#region src/models/tmx/parsed/TMXMapParsed.d.ts
|
|
163
|
-
export declare class TMXMapParsed {
|
|
164
|
-
backgroundcolor?: string;
|
|
165
|
-
compressionlevel?: number;
|
|
166
|
-
editorsettings: TMXEditorSettingsParsed;
|
|
167
|
-
height: number;
|
|
168
|
-
hexsidelength?: number;
|
|
169
|
-
infinite: number;
|
|
170
|
-
layers: (TMXGroupLayerParsed | TMXLayerParsed)[];
|
|
171
|
-
nextlayerid: number;
|
|
172
|
-
nextobjectid: number;
|
|
173
|
-
orientation: string;
|
|
174
|
-
parallaxoriginx?: number;
|
|
175
|
-
parallaxoriginy?: number;
|
|
176
|
-
properties: TMXPropertiesParsed;
|
|
177
|
-
renderorder: string;
|
|
178
|
-
staggeraxis?: string;
|
|
179
|
-
staggerindex?: string;
|
|
180
|
-
tiledversion: string;
|
|
181
|
-
tileheight: number;
|
|
182
|
-
tilesets: TMXTilesetParsed[];
|
|
183
|
-
tilewidth: number;
|
|
184
|
-
version: number;
|
|
185
|
-
width: number;
|
|
186
|
-
}
|
|
187
|
-
//#endregion
|
|
188
|
-
//#region src/models/tmx/parsed/TMXParsed.d.ts
|
|
189
|
-
export declare class TMXParsed {
|
|
190
|
-
map: TMXMapParsed;
|
|
191
|
-
constructor(map?: TMXMapParsed);
|
|
192
|
-
}
|
|
193
|
-
//#endregion
|
|
194
|
-
//#region src/parseTmx.d.ts
|
|
195
|
-
export declare const parseTmx: (xmlString: string, translateFlips?: boolean) => ResultAsync<TMXParsed, Error>;
|
|
196
|
-
//#endregion
|
|
197
|
-
//#region src/services/parseTileset.d.ts
|
|
198
|
-
export declare const parseTileset: (xmlString: string) => Result<TMXEmbeddedTilesetParsed, Error>;
|
|
199
|
-
//#endregion
|
|
200
|
-
export type { TMXAnimationFrameParsed, TMXAnimationParsed, TMXChunkParsed, TMXEditorSettingsParsed, TMXEmbeddedTilesetParsed, TMXExportParsed, TMXExternalTilesetParsed, TMXFlipsParsed, TMXGroupLayerParsed, TMXImageParsed, TMXLayerParsed, TMXObjectParsed, TMXPropertiesParsed, TMXPropertyParsed, TMXTileParsed, TMXTilesetParsed };
|
package/dist/index.js
DELETED
|
@@ -1,761 +0,0 @@
|
|
|
1
|
-
import { InvalidOperationError, Operation, exhaustiveGuard, getResult, getResultAsync, normalizeString } from "@esposter/shared";
|
|
2
|
-
import sax from "sax";
|
|
3
|
-
//#region src/models/Shape.ts
|
|
4
|
-
let Shape = /* @__PURE__ */ function(Shape) {
|
|
5
|
-
Shape["Ellipse"] = "ellipse";
|
|
6
|
-
Shape["Point"] = "point";
|
|
7
|
-
Shape["Polygon"] = "polygon";
|
|
8
|
-
Shape["Polyline"] = "polyline";
|
|
9
|
-
Shape["Rectangle"] = "rectangle";
|
|
10
|
-
return Shape;
|
|
11
|
-
}({});
|
|
12
|
-
//#endregion
|
|
13
|
-
//#region src/models/tmx/parsed/TMXMapParsed.ts
|
|
14
|
-
var TMXMapParsed = class {
|
|
15
|
-
editorsettings = {};
|
|
16
|
-
height = 0;
|
|
17
|
-
infinite = 0;
|
|
18
|
-
layers = [];
|
|
19
|
-
nextlayerid = 0;
|
|
20
|
-
nextobjectid = 0;
|
|
21
|
-
orientation = "";
|
|
22
|
-
properties = [];
|
|
23
|
-
renderorder = "";
|
|
24
|
-
tiledversion = "";
|
|
25
|
-
tileheight = 0;
|
|
26
|
-
tilesets = [];
|
|
27
|
-
tilewidth = 0;
|
|
28
|
-
version = 0;
|
|
29
|
-
width = 0;
|
|
30
|
-
};
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/models/tmx/parsed/TMXParsed.ts
|
|
33
|
-
var TMXParsed = class {
|
|
34
|
-
map;
|
|
35
|
-
constructor(map = new TMXMapParsed()) {
|
|
36
|
-
this.map = map;
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/models/tmx/TMXTagName.ts
|
|
41
|
-
let TMXTagName = /* @__PURE__ */ function(TMXTagName) {
|
|
42
|
-
TMXTagName["Animation"] = "animation";
|
|
43
|
-
TMXTagName["Chunk"] = "chunk";
|
|
44
|
-
TMXTagName["Data"] = "data";
|
|
45
|
-
TMXTagName["EditorSettings"] = "editorsettings";
|
|
46
|
-
TMXTagName["Ellipse"] = "ellipse";
|
|
47
|
-
TMXTagName["Export"] = "export";
|
|
48
|
-
TMXTagName["Frame"] = "frame";
|
|
49
|
-
TMXTagName["Group"] = "group";
|
|
50
|
-
TMXTagName["Image"] = "image";
|
|
51
|
-
TMXTagName["ImageLayer"] = "imagelayer";
|
|
52
|
-
TMXTagName["Layer"] = "layer";
|
|
53
|
-
TMXTagName["Map"] = "map";
|
|
54
|
-
TMXTagName["Object"] = "object";
|
|
55
|
-
TMXTagName["Objectgroup"] = "objectgroup";
|
|
56
|
-
TMXTagName["Point"] = "point";
|
|
57
|
-
TMXTagName["Polygon"] = "polygon";
|
|
58
|
-
TMXTagName["Polyline"] = "polyline";
|
|
59
|
-
TMXTagName["Properties"] = "properties";
|
|
60
|
-
TMXTagName["Property"] = "property";
|
|
61
|
-
TMXTagName["Text"] = "text";
|
|
62
|
-
TMXTagName["Tile"] = "tile";
|
|
63
|
-
TMXTagName["Tileset"] = "tileset";
|
|
64
|
-
return TMXTagName;
|
|
65
|
-
}({});
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/models/Compression.ts
|
|
68
|
-
let Compression = /* @__PURE__ */ function(Compression) {
|
|
69
|
-
Compression["Gzip"] = "gzip";
|
|
70
|
-
Compression["Zlib"] = "zlib";
|
|
71
|
-
return Compression;
|
|
72
|
-
}({});
|
|
73
|
-
//#endregion
|
|
74
|
-
//#region src/models/Encoding.ts
|
|
75
|
-
let Encoding = /* @__PURE__ */ function(Encoding) {
|
|
76
|
-
Encoding["Base64"] = "base64";
|
|
77
|
-
Encoding["Csv"] = "csv";
|
|
78
|
-
return Encoding;
|
|
79
|
-
}({});
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/services/getDecompressedBytes.ts
|
|
82
|
-
const getDecompressedBytes = async (bytes, compression) => {
|
|
83
|
-
const format = compression === "gzip" ? "gzip" : "deflate";
|
|
84
|
-
const decompressedTileStream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream(format));
|
|
85
|
-
return new Uint8Array(await new Response(decompressedTileStream).arrayBuffer());
|
|
86
|
-
};
|
|
87
|
-
//#endregion
|
|
88
|
-
//#region src/services/unpackTileBytes.ts
|
|
89
|
-
const unpackTileBytes = (bytes) => {
|
|
90
|
-
if (bytes.byteLength % Uint32Array.BYTES_PER_ELEMENT !== 0) throw new InvalidOperationError(Operation.Read, "TMXLayer", `expected whole ${Uint32Array.BYTES_PER_ELEMENT}-byte tiles, received ${bytes.byteLength} bytes`);
|
|
91
|
-
const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
92
|
-
const tiles = new Uint32Array(bytes.byteLength / Uint32Array.BYTES_PER_ELEMENT);
|
|
93
|
-
for (let index = 0; index < tiles.length; index++) tiles[index] = dataView.getUint32(index * Uint32Array.BYTES_PER_ELEMENT, true);
|
|
94
|
-
return [...tiles];
|
|
95
|
-
};
|
|
96
|
-
//#endregion
|
|
97
|
-
//#region src/services/decodeTileData.ts
|
|
98
|
-
const CSV_SEPARATOR_CODE_POINT = ",".codePointAt(0) ?? 0;
|
|
99
|
-
const ZERO_CODE_POINT = "0".codePointAt(0) ?? 0;
|
|
100
|
-
const NINE_CODE_POINT = "9".codePointAt(0) ?? 0;
|
|
101
|
-
const WHITESPACE_REGEX = /\s/u;
|
|
102
|
-
const decodeCsv = (text) => {
|
|
103
|
-
const tiles = [];
|
|
104
|
-
let tile = 0;
|
|
105
|
-
let hasDigit = false;
|
|
106
|
-
let isEnded = false;
|
|
107
|
-
for (let index = 0; index <= text.length; index++) {
|
|
108
|
-
const codePoint = text.codePointAt(index) ?? CSV_SEPARATOR_CODE_POINT;
|
|
109
|
-
if (codePoint === CSV_SEPARATOR_CODE_POINT) {
|
|
110
|
-
tiles.push(tile);
|
|
111
|
-
tile = 0;
|
|
112
|
-
hasDigit = false;
|
|
113
|
-
isEnded = false;
|
|
114
|
-
} else if (codePoint >= ZERO_CODE_POINT && codePoint <= NINE_CODE_POINT) {
|
|
115
|
-
if (isEnded) throw new InvalidOperationError(Operation.Read, decodeCsv.name, "has a cell with two numbers");
|
|
116
|
-
tile = tile * 10 + codePoint - ZERO_CODE_POINT;
|
|
117
|
-
hasDigit = true;
|
|
118
|
-
} else if (WHITESPACE_REGEX.test(text.charAt(index))) isEnded ||= hasDigit;
|
|
119
|
-
else throw new InvalidOperationError(Operation.Read, decodeCsv.name, `${text.charAt(index)} is not a tile gid`);
|
|
120
|
-
}
|
|
121
|
-
return tiles;
|
|
122
|
-
};
|
|
123
|
-
const decodeTileData = async (source) => {
|
|
124
|
-
const { compression, encoding, gids, text } = source;
|
|
125
|
-
if (encoding === void 0) return gids;
|
|
126
|
-
const data = normalizeString(text);
|
|
127
|
-
switch (encoding) {
|
|
128
|
-
case "base64": {
|
|
129
|
-
const bytes = Uint8Array.fromBase64(data);
|
|
130
|
-
switch (compression) {
|
|
131
|
-
case "gzip":
|
|
132
|
-
case "zlib": return unpackTileBytes(await getDecompressedBytes(bytes, compression));
|
|
133
|
-
case void 0: return unpackTileBytes(bytes);
|
|
134
|
-
default: return exhaustiveGuard(compression);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
case "csv": return decodeCsv(data);
|
|
138
|
-
default: return exhaustiveGuard(encoding);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
const Flippeds = Object.values(/* @__PURE__ */ function(Flipped) {
|
|
142
|
-
Flipped[Flipped["Diagonally"] = 536870912] = "Diagonally";
|
|
143
|
-
Flipped[Flipped["Vertically"] = 1073741824] = "Vertically";
|
|
144
|
-
Flipped[Flipped["Horizontally"] = 2147483648] = "Horizontally";
|
|
145
|
-
return Flipped;
|
|
146
|
-
}({})).filter((value) => typeof value === "number");
|
|
147
|
-
//#endregion
|
|
148
|
-
//#region src/services/parseFlips.ts
|
|
149
|
-
const parseFlips = (gid) => ({
|
|
150
|
-
Diagonal: Boolean(gid & 536870912),
|
|
151
|
-
Horizontal: Boolean(gid & 2147483648),
|
|
152
|
-
Vertical: Boolean(gid & 1073741824)
|
|
153
|
-
});
|
|
154
|
-
//#endregion
|
|
155
|
-
//#region src/services/parseTileId.ts
|
|
156
|
-
const FLIPPED_MASK = ~Flippeds.reduce((accumulator, flipped) => accumulator | flipped, 0);
|
|
157
|
-
const parseTileId = (gid) => gid & FLIPPED_MASK;
|
|
158
|
-
//#endregion
|
|
159
|
-
//#region src/services/assignTileData.ts
|
|
160
|
-
const assignTileData = async (pending, translateFlips) => {
|
|
161
|
-
await Promise.all(pending.map(async ({ expectedCount, owner, source }) => {
|
|
162
|
-
if (source.chunked) return;
|
|
163
|
-
const tiles = await decodeTileData(source);
|
|
164
|
-
if (expectedCount !== void 0 && tiles.length !== expectedCount) throw new InvalidOperationError(Operation.Read, "TMXLayer", `expected ${expectedCount} tiles, received ${tiles.length}`);
|
|
165
|
-
if (translateFlips) {
|
|
166
|
-
owner.data = tiles.map((gid) => parseTileId(gid));
|
|
167
|
-
owner.flips = tiles.map((gid) => parseFlips(gid));
|
|
168
|
-
} else owner.data = tiles;
|
|
169
|
-
}));
|
|
170
|
-
};
|
|
171
|
-
//#endregion
|
|
172
|
-
//#region src/models/PropertyType.ts
|
|
173
|
-
let PropertyType = /* @__PURE__ */ function(PropertyType) {
|
|
174
|
-
PropertyType["Bool"] = "bool";
|
|
175
|
-
PropertyType["Class"] = "class";
|
|
176
|
-
PropertyType["Color"] = "color";
|
|
177
|
-
PropertyType["File"] = "file";
|
|
178
|
-
PropertyType["Float"] = "float";
|
|
179
|
-
PropertyType["Int"] = "int";
|
|
180
|
-
PropertyType["Object"] = "object";
|
|
181
|
-
PropertyType["String"] = "string";
|
|
182
|
-
return PropertyType;
|
|
183
|
-
}({});
|
|
184
|
-
//#endregion
|
|
185
|
-
//#region src/services/closeTmxFrame.ts
|
|
186
|
-
const parsePropertyValue = (propertyType, value) => {
|
|
187
|
-
switch (propertyType) {
|
|
188
|
-
case "bool": return value === "true";
|
|
189
|
-
case "class":
|
|
190
|
-
case "color":
|
|
191
|
-
case "file":
|
|
192
|
-
case "object":
|
|
193
|
-
case "string": return value;
|
|
194
|
-
case "float":
|
|
195
|
-
case "int": return Number(value);
|
|
196
|
-
default: return exhaustiveGuard(propertyType);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
const closeTmxFrame = (frame) => {
|
|
200
|
-
switch (frame.tag) {
|
|
201
|
-
case "chunk":
|
|
202
|
-
case "data":
|
|
203
|
-
case "text":
|
|
204
|
-
frame.target.text = frame.text;
|
|
205
|
-
return;
|
|
206
|
-
case "property":
|
|
207
|
-
if (frame.propertyType === "class") return;
|
|
208
|
-
frame.target.value = parsePropertyValue(frame.propertyType, frame.valueAttribute ?? frame.text);
|
|
209
|
-
return;
|
|
210
|
-
default: return;
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
//#endregion
|
|
214
|
-
//#region src/services/readTmxAttributes.ts
|
|
215
|
-
const readTmxAttributes = (attributes, table) => {
|
|
216
|
-
const values = {};
|
|
217
|
-
for (const [name, kind] of Object.entries(table)) {
|
|
218
|
-
const isNumber = kind === "number" || kind === "requiredNumber";
|
|
219
|
-
const isRequired = kind === "requiredNumber" || kind === "requiredString";
|
|
220
|
-
const text = attributes[name];
|
|
221
|
-
if (text === void 0 || isNumber && text === "") {
|
|
222
|
-
if (isRequired) values[name] = isNumber ? 0 : "";
|
|
223
|
-
} else if (isNumber) {
|
|
224
|
-
const number = Number(text);
|
|
225
|
-
if (Number.isNaN(number)) throw new InvalidOperationError(Operation.Read, readTmxAttributes.name, `${text} is not a number`);
|
|
226
|
-
values[name] = number;
|
|
227
|
-
} else values[name] = text;
|
|
228
|
-
}
|
|
229
|
-
return values;
|
|
230
|
-
};
|
|
231
|
-
//#endregion
|
|
232
|
-
//#region src/services/createTmxImage.ts
|
|
233
|
-
const imageAttributeKindMap = {
|
|
234
|
-
format: "string",
|
|
235
|
-
height: "requiredNumber",
|
|
236
|
-
source: "requiredString",
|
|
237
|
-
trans: "string",
|
|
238
|
-
width: "requiredNumber"
|
|
239
|
-
};
|
|
240
|
-
const createTmxImage = (attributes) => readTmxAttributes(attributes, imageAttributeKindMap);
|
|
241
|
-
//#endregion
|
|
242
|
-
//#region src/services/openTmxLayer.ts
|
|
243
|
-
const groupAttributeKindMap = {
|
|
244
|
-
class: "string",
|
|
245
|
-
id: "requiredNumber",
|
|
246
|
-
name: "requiredString",
|
|
247
|
-
offsetx: "number",
|
|
248
|
-
offsety: "number",
|
|
249
|
-
opacity: "number",
|
|
250
|
-
parallaxx: "number",
|
|
251
|
-
parallaxy: "number",
|
|
252
|
-
tintcolor: "string",
|
|
253
|
-
visible: "number"
|
|
254
|
-
};
|
|
255
|
-
const layerAttributeKindMap = {
|
|
256
|
-
...groupAttributeKindMap,
|
|
257
|
-
color: "string",
|
|
258
|
-
draworder: "string",
|
|
259
|
-
height: "number",
|
|
260
|
-
locked: "number",
|
|
261
|
-
width: "number",
|
|
262
|
-
x: "number",
|
|
263
|
-
y: "number"
|
|
264
|
-
};
|
|
265
|
-
const openTmxLayer = (layers, tag, attributes) => {
|
|
266
|
-
if (tag === "group") {
|
|
267
|
-
const group = {
|
|
268
|
-
...readTmxAttributes(attributes, groupAttributeKindMap),
|
|
269
|
-
layers: [],
|
|
270
|
-
type: tag
|
|
271
|
-
};
|
|
272
|
-
layers.push(group);
|
|
273
|
-
return {
|
|
274
|
-
tag,
|
|
275
|
-
target: group,
|
|
276
|
-
text: ""
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
const layer = {
|
|
280
|
-
...readTmxAttributes(attributes, layerAttributeKindMap),
|
|
281
|
-
type: tag
|
|
282
|
-
};
|
|
283
|
-
layers.push(layer);
|
|
284
|
-
return {
|
|
285
|
-
tag,
|
|
286
|
-
target: layer,
|
|
287
|
-
text: ""
|
|
288
|
-
};
|
|
289
|
-
};
|
|
290
|
-
//#endregion
|
|
291
|
-
//#region src/services/openTmxProperties.ts
|
|
292
|
-
const openTmxProperties = (target) => {
|
|
293
|
-
target.properties ??= [];
|
|
294
|
-
return {
|
|
295
|
-
tag: "properties",
|
|
296
|
-
target: target.properties,
|
|
297
|
-
text: ""
|
|
298
|
-
};
|
|
299
|
-
};
|
|
300
|
-
//#endregion
|
|
301
|
-
//#region src/services/parseEnumAttribute.ts
|
|
302
|
-
const parseEnumAttribute = (operation, label, enumObject, value) => {
|
|
303
|
-
if (value === void 0) return void 0;
|
|
304
|
-
const enumValue = Object.values(enumObject).find((member) => member === value);
|
|
305
|
-
if (enumValue !== void 0) return enumValue;
|
|
306
|
-
throw new InvalidOperationError(Operation.Read, operation, `${value} is not a supported ${label}`);
|
|
307
|
-
};
|
|
308
|
-
//#endregion
|
|
309
|
-
//#region src/services/openTmxLayerChild.ts
|
|
310
|
-
const gidAttributeKindMap = { gid: "requiredNumber" };
|
|
311
|
-
const chunkAttributeKindMap = {
|
|
312
|
-
height: "requiredNumber",
|
|
313
|
-
width: "requiredNumber",
|
|
314
|
-
x: "requiredNumber",
|
|
315
|
-
y: "requiredNumber"
|
|
316
|
-
};
|
|
317
|
-
const parseCompression = (value) => parseEnumAttribute(parseCompression.name, "compression", Compression, value);
|
|
318
|
-
const parseEncoding = (value) => parseEnumAttribute(parseEncoding.name, "encoding", Encoding, value);
|
|
319
|
-
const createDataSource = (compression, encoding) => ({
|
|
320
|
-
chunked: false,
|
|
321
|
-
compression,
|
|
322
|
-
encoding,
|
|
323
|
-
gids: [],
|
|
324
|
-
text: ""
|
|
325
|
-
});
|
|
326
|
-
const openTileData = (layer, attributes, context) => {
|
|
327
|
-
const source = createDataSource(parseCompression(attributes.compression), parseEncoding(attributes.encoding));
|
|
328
|
-
context.pending.push({
|
|
329
|
-
expectedCount: context.tileCount,
|
|
330
|
-
owner: layer,
|
|
331
|
-
source
|
|
332
|
-
});
|
|
333
|
-
return {
|
|
334
|
-
owner: layer,
|
|
335
|
-
tag: "data",
|
|
336
|
-
target: source,
|
|
337
|
-
text: ""
|
|
338
|
-
};
|
|
339
|
-
};
|
|
340
|
-
const openTmxDataChild = (parent, tag, attributes, context) => {
|
|
341
|
-
const source = parent.target;
|
|
342
|
-
switch (tag) {
|
|
343
|
-
case "chunk": {
|
|
344
|
-
if (parent.tag !== "data") return void 0;
|
|
345
|
-
const chunk = readTmxAttributes(attributes, chunkAttributeKindMap);
|
|
346
|
-
parent.owner.chunks ??= [];
|
|
347
|
-
parent.owner.chunks.push(chunk);
|
|
348
|
-
source.chunked = true;
|
|
349
|
-
const chunkSource = createDataSource(source.compression, source.encoding);
|
|
350
|
-
context.pending.push({
|
|
351
|
-
owner: chunk,
|
|
352
|
-
source: chunkSource
|
|
353
|
-
});
|
|
354
|
-
return {
|
|
355
|
-
tag,
|
|
356
|
-
target: chunkSource,
|
|
357
|
-
text: ""
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
case "tile":
|
|
361
|
-
source.gids.push(readTmxAttributes(attributes, gidAttributeKindMap).gid);
|
|
362
|
-
return;
|
|
363
|
-
default: return;
|
|
364
|
-
}
|
|
365
|
-
};
|
|
366
|
-
const openTmxLayerChild = (parent, tag, attributes, context) => {
|
|
367
|
-
if (parent.tag === "chunk" || parent.tag === "data") return openTmxDataChild(parent, tag, attributes, context);
|
|
368
|
-
switch (tag) {
|
|
369
|
-
case "data":
|
|
370
|
-
if (parent.tag !== "layer") return void 0;
|
|
371
|
-
return openTileData(parent.target, attributes, context);
|
|
372
|
-
case "group":
|
|
373
|
-
case "imagelayer":
|
|
374
|
-
case "layer":
|
|
375
|
-
case "objectgroup":
|
|
376
|
-
if (parent.tag !== "group") return void 0;
|
|
377
|
-
return openTmxLayer(parent.target.layers, tag, attributes);
|
|
378
|
-
case "image":
|
|
379
|
-
if (parent.tag !== "imagelayer") return void 0;
|
|
380
|
-
parent.target.image = createTmxImage(attributes);
|
|
381
|
-
return {
|
|
382
|
-
tag,
|
|
383
|
-
target: parent.target.image,
|
|
384
|
-
text: ""
|
|
385
|
-
};
|
|
386
|
-
case "properties": return openTmxProperties(parent.target);
|
|
387
|
-
default: return;
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
//#endregion
|
|
391
|
-
//#region src/services/openTmxObjectChild.ts
|
|
392
|
-
const NUMBER_REGEX = /^[+-]?\d+(?:\.\d+)?$/u;
|
|
393
|
-
const objectAttributeKindMap = {
|
|
394
|
-
gid: "number",
|
|
395
|
-
height: "requiredNumber",
|
|
396
|
-
id: "requiredNumber",
|
|
397
|
-
name: "requiredString",
|
|
398
|
-
rotation: "number",
|
|
399
|
-
template: "string",
|
|
400
|
-
type: "requiredString",
|
|
401
|
-
visible: "number",
|
|
402
|
-
width: "requiredNumber",
|
|
403
|
-
x: "requiredNumber",
|
|
404
|
-
y: "requiredNumber"
|
|
405
|
-
};
|
|
406
|
-
const createObject = (attributes) => {
|
|
407
|
-
const { gid, ...object } = readTmxAttributes(attributes, objectAttributeKindMap);
|
|
408
|
-
const shaped = {
|
|
409
|
-
...object,
|
|
410
|
-
shape: "rectangle"
|
|
411
|
-
};
|
|
412
|
-
if (gid === void 0) return shaped;
|
|
413
|
-
return gid ? {
|
|
414
|
-
...shaped,
|
|
415
|
-
flips: parseFlips(gid),
|
|
416
|
-
gid: parseTileId(gid)
|
|
417
|
-
} : {
|
|
418
|
-
...shaped,
|
|
419
|
-
gid
|
|
420
|
-
};
|
|
421
|
-
};
|
|
422
|
-
const parsePoints = (points) => points === "" ? [] : points.split(" ").map((point) => {
|
|
423
|
-
const [x = "", y = ""] = point.split(",");
|
|
424
|
-
return [Number(x), Number(y)];
|
|
425
|
-
});
|
|
426
|
-
const parseUntypedValue = (value) => {
|
|
427
|
-
if (value === "true") return true;
|
|
428
|
-
else if (value === "false") return false;
|
|
429
|
-
else if (NUMBER_REGEX.test(value)) return Number(value);
|
|
430
|
-
else return value;
|
|
431
|
-
};
|
|
432
|
-
const createTextProperties = (attributes) => Object.entries(attributes).map(([name, value]) => ({
|
|
433
|
-
name,
|
|
434
|
-
value: parseUntypedValue(value)
|
|
435
|
-
}));
|
|
436
|
-
const openTmxObjectChild = (parent, tag, attributes) => {
|
|
437
|
-
if (parent.tag === "objectgroup") {
|
|
438
|
-
if (tag === "properties") return openTmxProperties(parent.target);
|
|
439
|
-
if (tag !== "object") return void 0;
|
|
440
|
-
const object = createObject(attributes);
|
|
441
|
-
parent.target.objects ??= [];
|
|
442
|
-
parent.target.objects.push(object);
|
|
443
|
-
return {
|
|
444
|
-
tag,
|
|
445
|
-
target: object,
|
|
446
|
-
text: ""
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
const object = parent.target;
|
|
450
|
-
switch (tag) {
|
|
451
|
-
case "ellipse":
|
|
452
|
-
case "point":
|
|
453
|
-
object.shape = tag === "point" ? "point" : "ellipse";
|
|
454
|
-
return {
|
|
455
|
-
tag,
|
|
456
|
-
target: object,
|
|
457
|
-
text: ""
|
|
458
|
-
};
|
|
459
|
-
case "polygon":
|
|
460
|
-
case "polyline":
|
|
461
|
-
object.shape = tag === "polygon" ? "polygon" : "polyline";
|
|
462
|
-
object.points = parsePoints(attributes.points ?? "");
|
|
463
|
-
return {
|
|
464
|
-
tag,
|
|
465
|
-
target: object,
|
|
466
|
-
text: ""
|
|
467
|
-
};
|
|
468
|
-
case "properties": return openTmxProperties(object);
|
|
469
|
-
case "text":
|
|
470
|
-
object.properties = [...object.properties ?? [], ...createTextProperties(attributes)];
|
|
471
|
-
return {
|
|
472
|
-
tag,
|
|
473
|
-
target: object,
|
|
474
|
-
text: ""
|
|
475
|
-
};
|
|
476
|
-
default: return;
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
//#endregion
|
|
480
|
-
//#region src/services/openTmxFrame.ts
|
|
481
|
-
const mapAttributeKindMap = {
|
|
482
|
-
backgroundcolor: "string",
|
|
483
|
-
compressionlevel: "number",
|
|
484
|
-
height: "requiredNumber",
|
|
485
|
-
hexsidelength: "number",
|
|
486
|
-
infinite: "requiredNumber",
|
|
487
|
-
nextlayerid: "requiredNumber",
|
|
488
|
-
nextobjectid: "requiredNumber",
|
|
489
|
-
orientation: "requiredString",
|
|
490
|
-
parallaxoriginx: "number",
|
|
491
|
-
parallaxoriginy: "number",
|
|
492
|
-
renderorder: "requiredString",
|
|
493
|
-
staggeraxis: "string",
|
|
494
|
-
staggerindex: "string",
|
|
495
|
-
tiledversion: "requiredString",
|
|
496
|
-
tileheight: "requiredNumber",
|
|
497
|
-
tilewidth: "requiredNumber",
|
|
498
|
-
version: "requiredNumber",
|
|
499
|
-
width: "requiredNumber"
|
|
500
|
-
};
|
|
501
|
-
const embeddedTilesetAttributeKindMap = {
|
|
502
|
-
columns: "requiredNumber",
|
|
503
|
-
firstgid: "requiredNumber",
|
|
504
|
-
margin: "number",
|
|
505
|
-
name: "requiredString",
|
|
506
|
-
spacing: "number",
|
|
507
|
-
tilecount: "requiredNumber",
|
|
508
|
-
tileheight: "requiredNumber",
|
|
509
|
-
tilewidth: "requiredNumber"
|
|
510
|
-
};
|
|
511
|
-
const externalTilesetAttributeKindMap = {
|
|
512
|
-
firstgid: "requiredNumber",
|
|
513
|
-
source: "requiredString"
|
|
514
|
-
};
|
|
515
|
-
const tileAttributeKindMap = {
|
|
516
|
-
id: "requiredNumber",
|
|
517
|
-
probability: "number",
|
|
518
|
-
terrain: "string",
|
|
519
|
-
type: "string"
|
|
520
|
-
};
|
|
521
|
-
const animationFrameAttributeKindMap = {
|
|
522
|
-
duration: "requiredNumber",
|
|
523
|
-
tileid: "requiredNumber"
|
|
524
|
-
};
|
|
525
|
-
const exportAttributeKindMap = {
|
|
526
|
-
format: "requiredString",
|
|
527
|
-
target: "requiredString"
|
|
528
|
-
};
|
|
529
|
-
const propertyAttributeKindMap = { name: "requiredString" };
|
|
530
|
-
const createEmbeddedTileset = (attributes) => ({
|
|
531
|
-
...readTmxAttributes(attributes, embeddedTilesetAttributeKindMap),
|
|
532
|
-
tiles: []
|
|
533
|
-
});
|
|
534
|
-
const parseTmxTagName = (name) => Object.values(TMXTagName).find((tagName) => tagName === name);
|
|
535
|
-
const parsePropertyType = (value) => parseEnumAttribute(parsePropertyType.name, "property type", PropertyType, value) ?? "string";
|
|
536
|
-
const openTmxRoot = (name, attributes, context) => {
|
|
537
|
-
const tag = parseTmxTagName(name);
|
|
538
|
-
switch (tag) {
|
|
539
|
-
case "map": {
|
|
540
|
-
const map = Object.assign(new TMXMapParsed(), readTmxAttributes(attributes, mapAttributeKindMap));
|
|
541
|
-
context.tileCount = map.width * map.height;
|
|
542
|
-
return {
|
|
543
|
-
tag,
|
|
544
|
-
target: map,
|
|
545
|
-
text: ""
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
case "tileset":
|
|
549
|
-
if (attributes.source !== void 0) return void 0;
|
|
550
|
-
return {
|
|
551
|
-
tag,
|
|
552
|
-
target: createEmbeddedTileset(attributes),
|
|
553
|
-
text: ""
|
|
554
|
-
};
|
|
555
|
-
default: throw new InvalidOperationError(Operation.Read, openTmxRoot.name, `${name} is not a map or a tileset`);
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
const openTmxMapChild = (parent, name, tag, attributes) => {
|
|
559
|
-
const map = parent.target;
|
|
560
|
-
switch (tag) {
|
|
561
|
-
case "data":
|
|
562
|
-
case "export":
|
|
563
|
-
case "image":
|
|
564
|
-
case "object":
|
|
565
|
-
case "property": return;
|
|
566
|
-
case "editorsettings": {
|
|
567
|
-
const editorSettings = {};
|
|
568
|
-
map.editorsettings = editorSettings;
|
|
569
|
-
return {
|
|
570
|
-
tag,
|
|
571
|
-
target: editorSettings,
|
|
572
|
-
text: ""
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
case "group":
|
|
576
|
-
case "imagelayer":
|
|
577
|
-
case "layer":
|
|
578
|
-
case "objectgroup": return openTmxLayer(map.layers, tag, attributes);
|
|
579
|
-
case "properties": return openTmxProperties(map);
|
|
580
|
-
case "tileset": {
|
|
581
|
-
if (attributes.source !== void 0) {
|
|
582
|
-
map.tilesets.push(readTmxAttributes(attributes, externalTilesetAttributeKindMap));
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
const tileset = createEmbeddedTileset(attributes);
|
|
586
|
-
map.tilesets.push(tileset);
|
|
587
|
-
return {
|
|
588
|
-
tag,
|
|
589
|
-
target: tileset,
|
|
590
|
-
text: ""
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
default: throw new InvalidOperationError(Operation.Read, openTmxMapChild.name, `${name} is not a map child`);
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
const openTmxTileChild = (parent, tag, attributes) => {
|
|
597
|
-
const tile = parent.target;
|
|
598
|
-
switch (tag) {
|
|
599
|
-
case "animation": {
|
|
600
|
-
const animation = { frames: [] };
|
|
601
|
-
tile.animation = animation;
|
|
602
|
-
return {
|
|
603
|
-
tag,
|
|
604
|
-
target: animation,
|
|
605
|
-
text: ""
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
case "image": {
|
|
609
|
-
const image = createTmxImage(attributes);
|
|
610
|
-
tile.image = image;
|
|
611
|
-
return {
|
|
612
|
-
tag,
|
|
613
|
-
target: image,
|
|
614
|
-
text: ""
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
case "objectgroup": return {
|
|
618
|
-
tag,
|
|
619
|
-
target: tile,
|
|
620
|
-
text: ""
|
|
621
|
-
};
|
|
622
|
-
case "properties": return openTmxProperties(tile);
|
|
623
|
-
default: return;
|
|
624
|
-
}
|
|
625
|
-
};
|
|
626
|
-
const openTmxTilesetChild = (parent, tag, attributes) => {
|
|
627
|
-
const tileset = parent.target;
|
|
628
|
-
switch (tag) {
|
|
629
|
-
case "image": {
|
|
630
|
-
const image = createTmxImage(attributes);
|
|
631
|
-
tileset.image = image;
|
|
632
|
-
return {
|
|
633
|
-
tag,
|
|
634
|
-
target: image,
|
|
635
|
-
text: ""
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
case "tile": {
|
|
639
|
-
const tile = readTmxAttributes(attributes, tileAttributeKindMap);
|
|
640
|
-
tileset.tiles.push(tile);
|
|
641
|
-
return {
|
|
642
|
-
tag,
|
|
643
|
-
target: tile,
|
|
644
|
-
text: ""
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
default: return;
|
|
648
|
-
}
|
|
649
|
-
};
|
|
650
|
-
const openTmxPropertyChild = (parent, tag, attributes) => {
|
|
651
|
-
if (tag !== "property") return void 0;
|
|
652
|
-
const target = {
|
|
653
|
-
...readTmxAttributes(attributes, propertyAttributeKindMap),
|
|
654
|
-
value: ""
|
|
655
|
-
};
|
|
656
|
-
parent.target.push(target);
|
|
657
|
-
return {
|
|
658
|
-
propertyType: parsePropertyType(attributes.type),
|
|
659
|
-
tag,
|
|
660
|
-
target,
|
|
661
|
-
text: "",
|
|
662
|
-
valueAttribute: attributes.value
|
|
663
|
-
};
|
|
664
|
-
};
|
|
665
|
-
const openTmxFrame = (parent, name, attributes, context) => {
|
|
666
|
-
if (parent === void 0) return openTmxRoot(name, attributes, context);
|
|
667
|
-
const tag = parseTmxTagName(name);
|
|
668
|
-
switch (parent.tag) {
|
|
669
|
-
case "animation": {
|
|
670
|
-
if (tag !== "frame") return void 0;
|
|
671
|
-
const frame = readTmxAttributes(attributes, animationFrameAttributeKindMap);
|
|
672
|
-
parent.target.frames.push(frame);
|
|
673
|
-
return {
|
|
674
|
-
tag,
|
|
675
|
-
target: frame,
|
|
676
|
-
text: ""
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
case "chunk":
|
|
680
|
-
case "data":
|
|
681
|
-
case "group":
|
|
682
|
-
case "imagelayer":
|
|
683
|
-
case "layer": return openTmxLayerChild(parent, tag, attributes, context);
|
|
684
|
-
case "editorsettings":
|
|
685
|
-
if (tag !== "export") return void 0;
|
|
686
|
-
parent.target.export = readTmxAttributes(attributes, exportAttributeKindMap);
|
|
687
|
-
return {
|
|
688
|
-
tag,
|
|
689
|
-
target: parent.target.export,
|
|
690
|
-
text: ""
|
|
691
|
-
};
|
|
692
|
-
case "map": return openTmxMapChild(parent, name, tag, attributes);
|
|
693
|
-
case "object":
|
|
694
|
-
case "objectgroup": return openTmxObjectChild(parent, tag, attributes);
|
|
695
|
-
case "properties": return openTmxPropertyChild(parent, tag, attributes);
|
|
696
|
-
case "property": return tag === "properties" ? openTmxProperties(parent.target) : void 0;
|
|
697
|
-
case "tile": return openTmxTileChild(parent, tag, attributes);
|
|
698
|
-
case "tileset": return openTmxTilesetChild(parent, tag, attributes);
|
|
699
|
-
default: return;
|
|
700
|
-
}
|
|
701
|
-
};
|
|
702
|
-
//#endregion
|
|
703
|
-
//#region src/services/readTmxDocument.ts
|
|
704
|
-
const BYTE_ORDER_MARK_REGEX = /^\uFEFF/u;
|
|
705
|
-
const toTmxAttributes = (attributes) => Object.fromEntries(Object.entries(attributes).map(([name, attribute]) => [name, typeof attribute === "string" ? attribute : attribute.value]));
|
|
706
|
-
const readTmxDocument = (xmlString, context) => {
|
|
707
|
-
const parser = sax.parser(true, {
|
|
708
|
-
normalize: false,
|
|
709
|
-
trim: false
|
|
710
|
-
});
|
|
711
|
-
const stack = [];
|
|
712
|
-
let root;
|
|
713
|
-
parser.onerror = (error) => {
|
|
714
|
-
throw new InvalidOperationError(Operation.Read, readTmxDocument.name, error.message);
|
|
715
|
-
};
|
|
716
|
-
parser.onopentag = (node) => {
|
|
717
|
-
if (stack.length === 0) {
|
|
718
|
-
root = openTmxFrame(void 0, node.name, toTmxAttributes(node.attributes), context);
|
|
719
|
-
stack.push(root);
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
const parent = stack.at(-1);
|
|
723
|
-
stack.push(parent && openTmxFrame(parent, node.name, toTmxAttributes(node.attributes), context));
|
|
724
|
-
};
|
|
725
|
-
parser.onclosetag = () => {
|
|
726
|
-
const frame = stack.pop();
|
|
727
|
-
if (frame) closeTmxFrame(frame);
|
|
728
|
-
};
|
|
729
|
-
const appendText = (text) => {
|
|
730
|
-
const frame = stack.at(-1);
|
|
731
|
-
if (frame) frame.text += text;
|
|
732
|
-
};
|
|
733
|
-
parser.ontext = appendText;
|
|
734
|
-
parser.oncdata = appendText;
|
|
735
|
-
parser.write(xmlString.replace(BYTE_ORDER_MARK_REGEX, "")).close();
|
|
736
|
-
return root;
|
|
737
|
-
};
|
|
738
|
-
//#endregion
|
|
739
|
-
//#region src/parseTmx.ts
|
|
740
|
-
const parseTmx = (xmlString, translateFlips = false) => {
|
|
741
|
-
const context = {
|
|
742
|
-
pending: [],
|
|
743
|
-
tileCount: 0
|
|
744
|
-
};
|
|
745
|
-
return getResult(() => readTmxDocument(xmlString, context)).asyncAndThen((root) => getResultAsync(async () => {
|
|
746
|
-
if (root?.tag !== "map") throw new InvalidOperationError(Operation.Read, parseTmx.name, "has no map root element");
|
|
747
|
-
await assignTileData(context.pending, translateFlips);
|
|
748
|
-
return new TMXParsed(root.target);
|
|
749
|
-
}));
|
|
750
|
-
};
|
|
751
|
-
//#endregion
|
|
752
|
-
//#region src/services/parseTileset.ts
|
|
753
|
-
const parseTileset = (xmlString) => getResult(() => readTmxDocument(xmlString, {
|
|
754
|
-
pending: [],
|
|
755
|
-
tileCount: 0
|
|
756
|
-
})).andThen((root) => getResult(() => {
|
|
757
|
-
if (root?.tag !== "tileset") throw new InvalidOperationError(Operation.Read, parseTileset.name, "has no embedded tileset root element");
|
|
758
|
-
return root.target;
|
|
759
|
-
}));
|
|
760
|
-
//#endregion
|
|
761
|
-
export { Shape, TMXMapParsed, TMXParsed, parseTileset, parseTmx };
|