parse-tmx 4.0.0 → 4.1.1
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 +7 -1
- package/dist/index.d.ts +106 -291
- package/dist/index.js +680 -236
- package/package.json +11 -8
package/dist/index.js
CHANGED
|
@@ -1,166 +1,82 @@
|
|
|
1
|
-
import { InvalidOperationError, Operation, exhaustiveGuard,
|
|
2
|
-
import
|
|
3
|
-
//#region src/models/Compression.ts
|
|
4
|
-
let Compression = /* @__PURE__ */ function(Compression) {
|
|
5
|
-
Compression["Gzip"] = "gzip";
|
|
6
|
-
Compression["Zlib"] = "zlib";
|
|
7
|
-
return Compression;
|
|
8
|
-
}({});
|
|
9
|
-
//#endregion
|
|
10
|
-
//#region src/models/Encoding.ts
|
|
11
|
-
let Encoding = /* @__PURE__ */ function(Encoding) {
|
|
12
|
-
Encoding["Base64"] = "base64";
|
|
13
|
-
Encoding["Csv"] = "csv";
|
|
14
|
-
return Encoding;
|
|
15
|
-
}({});
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/models/Flipped.ts
|
|
18
|
-
let Flipped = /* @__PURE__ */ function(Flipped) {
|
|
19
|
-
Flipped[Flipped["Diagonally"] = 536870912] = "Diagonally";
|
|
20
|
-
Flipped[Flipped["Vertically"] = 1073741824] = "Vertically";
|
|
21
|
-
Flipped[Flipped["Horizontally"] = 2147483648] = "Horizontally";
|
|
22
|
-
return Flipped;
|
|
23
|
-
}({});
|
|
24
|
-
const Flippeds = Object.values(Flipped).filter((value) => typeof value === "number");
|
|
25
|
-
//#endregion
|
|
1
|
+
import { InvalidOperationError, Operation, exhaustiveGuard, getResult, getResultAsync, normalizeString } from "@esposter/shared";
|
|
2
|
+
import sax from "sax";
|
|
26
3
|
//#region src/models/Shape.ts
|
|
27
4
|
let Shape = /* @__PURE__ */ function(Shape) {
|
|
28
5
|
Shape["Ellipse"] = "ellipse";
|
|
29
6
|
Shape["Point"] = "point";
|
|
30
7
|
Shape["Polygon"] = "polygon";
|
|
8
|
+
Shape["Polyline"] = "polyline";
|
|
31
9
|
Shape["Rectangle"] = "rectangle";
|
|
32
10
|
return Shape;
|
|
33
11
|
}({});
|
|
34
12
|
//#endregion
|
|
35
|
-
//#region src/models/tmx/
|
|
36
|
-
var
|
|
37
|
-
|
|
38
|
-
$;
|
|
39
|
-
};
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/models/tmx/node/TMXNodeType.ts
|
|
42
|
-
let TMXNodeType = /* @__PURE__ */ function(TMXNodeType) {
|
|
43
|
-
TMXNodeType["Data"] = "data";
|
|
44
|
-
TMXNodeType["EditorSettings"] = "editorsettings";
|
|
45
|
-
TMXNodeType["Export"] = "export";
|
|
46
|
-
TMXNodeType["Group"] = "group";
|
|
47
|
-
TMXNodeType["Image"] = "image";
|
|
48
|
-
TMXNodeType["ImageLayer"] = "imagelayer";
|
|
49
|
-
TMXNodeType["Layer"] = "layer";
|
|
50
|
-
TMXNodeType["Object"] = "object";
|
|
51
|
-
TMXNodeType["Objectgroup"] = "objectgroup";
|
|
52
|
-
TMXNodeType["Properties"] = "properties";
|
|
53
|
-
TMXNodeType["Property"] = "property";
|
|
54
|
-
TMXNodeType["Tileset"] = "tileset";
|
|
55
|
-
return TMXNodeType;
|
|
56
|
-
}({});
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region src/models/tmx/shared/TMXMapShared.ts
|
|
59
|
-
var TMXMapShared = class {
|
|
13
|
+
//#region src/models/tmx/parsed/TMXMapParsed.ts
|
|
14
|
+
var TMXMapParsed = class {
|
|
15
|
+
editorsettings = {};
|
|
60
16
|
height = 0;
|
|
61
17
|
infinite = 0;
|
|
18
|
+
layers = [];
|
|
62
19
|
nextlayerid = 0;
|
|
63
20
|
nextobjectid = 0;
|
|
64
21
|
orientation = "";
|
|
22
|
+
properties = [];
|
|
65
23
|
renderorder = "";
|
|
66
24
|
tiledversion = "";
|
|
67
25
|
tileheight = 0;
|
|
26
|
+
tilesets = [];
|
|
68
27
|
tilewidth = 0;
|
|
69
28
|
version = 0;
|
|
70
29
|
width = 0;
|
|
71
30
|
};
|
|
72
31
|
//#endregion
|
|
73
|
-
//#region src/models/tmx/parsed/TMXMapParsed.ts
|
|
74
|
-
var TMXMapParsed = class extends TMXMapShared {
|
|
75
|
-
editorsettings = {};
|
|
76
|
-
layers = [];
|
|
77
|
-
properties = [];
|
|
78
|
-
tilesets = [];
|
|
79
|
-
constructor(init) {
|
|
80
|
-
super();
|
|
81
|
-
Object.assign(this, init);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
//#endregion
|
|
85
32
|
//#region src/models/tmx/parsed/TMXParsed.ts
|
|
86
33
|
var TMXParsed = class {
|
|
87
|
-
map
|
|
88
|
-
constructor(map) {
|
|
89
|
-
|
|
34
|
+
map;
|
|
35
|
+
constructor(map = new TMXMapParsed()) {
|
|
36
|
+
this.map = map;
|
|
90
37
|
}
|
|
91
38
|
};
|
|
92
39
|
//#endregion
|
|
93
|
-
//#region src/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
})));
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/services/parseTileId.ts
|
|
122
|
-
const FLIPPED_MASK = ~Flippeds.reduce((accumulator, flipped) => accumulator | flipped, 0);
|
|
123
|
-
const parseTileId = (gid) => gid & FLIPPED_MASK;
|
|
124
|
-
//#endregion
|
|
125
|
-
//#region src/services/parseObject.ts
|
|
126
|
-
const parseObject = (node) => {
|
|
127
|
-
const { $, polygon, properties, text } = node;
|
|
128
|
-
const object = structuredClone($);
|
|
129
|
-
object.shape = parseObjectShape(node);
|
|
130
|
-
if (properties) object.properties = parseProperties(properties);
|
|
131
|
-
if (polygon) object.points = takeOne(polygon).$.points.split(" ").map((point) => {
|
|
132
|
-
const points = point.split(",");
|
|
133
|
-
const x = takeOne(points);
|
|
134
|
-
const y = takeOne(points, 1);
|
|
135
|
-
return [Number(x), Number(y)];
|
|
136
|
-
});
|
|
137
|
-
if (text) {
|
|
138
|
-
const textNode = takeOne(text);
|
|
139
|
-
object.text = textNode._;
|
|
140
|
-
object.properties = [...object.properties ?? [], ...Object.entries(textNode.$ ?? {}).map(([name, value]) => ({
|
|
141
|
-
name,
|
|
142
|
-
value
|
|
143
|
-
}))];
|
|
144
|
-
}
|
|
145
|
-
if (object.gid) {
|
|
146
|
-
object.flips = parseFlips(object.gid);
|
|
147
|
-
object.gid = parseTileId(object.gid);
|
|
148
|
-
}
|
|
149
|
-
return object;
|
|
150
|
-
};
|
|
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
|
+
}({});
|
|
151
66
|
//#endregion
|
|
152
|
-
//#region src/
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (properties) layer.properties = parseProperties(properties);
|
|
159
|
-
return layer;
|
|
160
|
-
};
|
|
67
|
+
//#region src/models/Compression.ts
|
|
68
|
+
let Compression = /* @__PURE__ */ function(Compression) {
|
|
69
|
+
Compression["Gzip"] = "gzip";
|
|
70
|
+
Compression["Zlib"] = "zlib";
|
|
71
|
+
return Compression;
|
|
72
|
+
}({});
|
|
161
73
|
//#endregion
|
|
162
|
-
//#region src/
|
|
163
|
-
|
|
74
|
+
//#region src/models/Encoding.ts
|
|
75
|
+
let Encoding = /* @__PURE__ */ function(Encoding) {
|
|
76
|
+
Encoding["Base64"] = "base64";
|
|
77
|
+
Encoding["Csv"] = "csv";
|
|
78
|
+
return Encoding;
|
|
79
|
+
}({});
|
|
164
80
|
//#endregion
|
|
165
81
|
//#region src/services/getDecompressedBytes.ts
|
|
166
82
|
const getDecompressedBytes = async (bytes, compression) => {
|
|
@@ -172,21 +88,45 @@ const getDecompressedBytes = async (bytes, compression) => {
|
|
|
172
88
|
//#region src/services/unpackTileBytes.ts
|
|
173
89
|
const unpackTileBytes = (bytes) => {
|
|
174
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`);
|
|
175
|
-
const unpackedTiles = [];
|
|
176
91
|
const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
177
|
-
|
|
178
|
-
|
|
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];
|
|
179
95
|
};
|
|
180
96
|
//#endregion
|
|
181
97
|
//#region src/services/decodeTileData.ts
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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);
|
|
187
127
|
switch (encoding) {
|
|
188
128
|
case "base64": {
|
|
189
|
-
const bytes = Uint8Array.fromBase64(
|
|
129
|
+
const bytes = Uint8Array.fromBase64(data);
|
|
190
130
|
switch (compression) {
|
|
191
131
|
case "gzip":
|
|
192
132
|
case "zlib": return unpackTileBytes(await getDecompressedBytes(bytes, compression));
|
|
@@ -194,124 +134,628 @@ const decodeTileData = async (nodeData) => {
|
|
|
194
134
|
default: return exhaustiveGuard(compression);
|
|
195
135
|
}
|
|
196
136
|
}
|
|
197
|
-
case "csv": return
|
|
137
|
+
case "csv": return decodeCsv(data);
|
|
198
138
|
default: return exhaustiveGuard(encoding);
|
|
199
139
|
}
|
|
200
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
|
+
};
|
|
201
213
|
//#endregion
|
|
202
|
-
//#region src/services/
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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;
|
|
216
230
|
};
|
|
217
231
|
//#endregion
|
|
218
|
-
//#region src/services/
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
+
};
|
|
232
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
|
+
};
|
|
233
289
|
};
|
|
234
290
|
//#endregion
|
|
235
|
-
//#region src/services/
|
|
236
|
-
const
|
|
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
|
+
};
|
|
237
300
|
//#endregion
|
|
238
|
-
//#region src/services/
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
if (properties) tile.properties = parseProperties(properties);
|
|
245
|
-
return tile;
|
|
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}`);
|
|
246
307
|
};
|
|
247
308
|
//#endregion
|
|
248
|
-
//#region src/services/
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
+
});
|
|
256
333
|
return {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
334
|
+
owner: layer,
|
|
335
|
+
tag: "data",
|
|
336
|
+
target: source,
|
|
337
|
+
text: ""
|
|
260
338
|
};
|
|
261
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
|
+
};
|
|
262
390
|
//#endregion
|
|
263
|
-
//#region src/services/
|
|
264
|
-
const NUMBER_REGEX = /^[+-]?\d+(
|
|
265
|
-
const
|
|
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) => {
|
|
266
427
|
if (value === "true") return true;
|
|
267
428
|
else if (value === "false") return false;
|
|
268
429
|
else if (NUMBER_REGEX.test(value)) return Number(value);
|
|
269
430
|
else return value;
|
|
270
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
|
+
};
|
|
271
479
|
//#endregion
|
|
272
|
-
//#region src/services/
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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: []
|
|
277
533
|
});
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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;
|
|
303
584
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
+
};
|
|
312
616
|
}
|
|
617
|
+
case "objectgroup": return {
|
|
618
|
+
tag,
|
|
619
|
+
target: tile,
|
|
620
|
+
text: ""
|
|
621
|
+
};
|
|
622
|
+
case "properties": return openTmxProperties(tile);
|
|
623
|
+
default: return;
|
|
313
624
|
}
|
|
314
|
-
return new TMXParsed(map);
|
|
315
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
|
+
}));
|
|
316
760
|
//#endregion
|
|
317
|
-
export {
|
|
761
|
+
export { Shape, TMXMapParsed, TMXParsed, parseTileset, parseTmx };
|