@game_engine/import-ldtk 0.1.0-alpha

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.
@@ -0,0 +1,67 @@
1
+ import { SceneDocument, Diagnostic, ValidationResult } from '@game_engine/scene';
2
+
3
+ interface LdtkProject {
4
+ jsonVersion?: string;
5
+ levels?: LdtkLevel[];
6
+ }
7
+ interface LdtkLevel {
8
+ identifier?: string;
9
+ iid?: string;
10
+ pxWid?: number;
11
+ pxHei?: number;
12
+ worldX?: number;
13
+ worldY?: number;
14
+ layerInstances?: LdtkLayerInstance[] | null;
15
+ }
16
+ interface LdtkLayerInstance {
17
+ __identifier?: string;
18
+ __type?: string;
19
+ __gridSize?: number;
20
+ entityInstances?: LdtkEntityInstance[];
21
+ gridTiles?: unknown[];
22
+ autoLayerTiles?: unknown[];
23
+ intGridCsv?: unknown[];
24
+ }
25
+ interface LdtkEntityInstance {
26
+ __identifier?: string;
27
+ iid?: string;
28
+ px?: [number, number];
29
+ width?: number;
30
+ height?: number;
31
+ fieldInstances?: LdtkFieldInstance[];
32
+ }
33
+ interface LdtkFieldInstance {
34
+ __identifier?: string;
35
+ __value?: unknown;
36
+ }
37
+ interface LdtkImportOptions {
38
+ levelIdentifier?: string;
39
+ }
40
+ interface LdtkImportSummary {
41
+ importedLevel: {
42
+ name: string;
43
+ identifier?: string;
44
+ iid?: string;
45
+ };
46
+ ignoredLevelCount: number;
47
+ ignoredLayerCount: number;
48
+ ignoredFieldCount: number;
49
+ entityCount: number;
50
+ }
51
+ interface LdtkImportResult {
52
+ inputPath?: string;
53
+ outPath?: string;
54
+ scene?: SceneDocument;
55
+ yaml?: string;
56
+ summary?: LdtkImportSummary;
57
+ diagnostics: Diagnostic[];
58
+ }
59
+ declare function importLdtkSceneFile(inputPath: string, outPath: string, options?: LdtkImportOptions & {
60
+ cwd?: string;
61
+ }): Promise<LdtkImportResult>;
62
+ declare function parseLdtkSource(source: string, file?: string): ValidationResult<LdtkProject>;
63
+ declare function importLdtkProject(project: LdtkProject, options?: LdtkImportOptions & {
64
+ file?: string;
65
+ }): LdtkImportResult;
66
+
67
+ export { type LdtkEntityInstance, type LdtkFieldInstance, type LdtkImportOptions, type LdtkImportResult, type LdtkImportSummary, type LdtkLayerInstance, type LdtkLevel, type LdtkProject, importLdtkProject, importLdtkSceneFile, parseLdtkSource };
package/dist/index.js ADDED
@@ -0,0 +1,417 @@
1
+ // src/index.ts
2
+ import { mkdir, readFile, writeFile } from "fs/promises";
3
+ import path from "path";
4
+ import {
5
+ formatScene,
6
+ hasErrors,
7
+ validateSceneDocument
8
+ } from "@game_engine/scene";
9
+ async function importLdtkSceneFile(inputPath, outPath, options = {}) {
10
+ const resolvedInputPath = path.resolve(options.cwd ?? process.cwd(), inputPath);
11
+ const resolvedOutPath = path.resolve(options.cwd ?? process.cwd(), outPath);
12
+ let source;
13
+ try {
14
+ source = await readFile(resolvedInputPath, "utf8");
15
+ } catch (error) {
16
+ return {
17
+ inputPath: resolvedInputPath,
18
+ outPath: resolvedOutPath,
19
+ diagnostics: [
20
+ {
21
+ severity: "error",
22
+ code: "LDTK_FILE_READ_FAILED",
23
+ file: resolvedInputPath,
24
+ path: "$",
25
+ message: error instanceof Error ? error.message : String(error),
26
+ suggestion: "Check that the LDtk input path exists and is readable."
27
+ }
28
+ ]
29
+ };
30
+ }
31
+ const parsed = parseLdtkSource(source, resolvedInputPath);
32
+ const diagnostics = [...parsed.diagnostics];
33
+ if (!parsed.document || hasErrors(diagnostics)) {
34
+ return {
35
+ inputPath: resolvedInputPath,
36
+ outPath: resolvedOutPath,
37
+ diagnostics
38
+ };
39
+ }
40
+ const imported = importLdtkProject(parsed.document, {
41
+ ...options,
42
+ file: resolvedInputPath
43
+ });
44
+ diagnostics.push(...imported.diagnostics);
45
+ if (!imported.scene || hasErrors(diagnostics)) {
46
+ return {
47
+ inputPath: resolvedInputPath,
48
+ outPath: resolvedOutPath,
49
+ diagnostics
50
+ };
51
+ }
52
+ const yaml = formatScene(imported.scene);
53
+ await mkdir(path.dirname(resolvedOutPath), { recursive: true });
54
+ await writeFile(resolvedOutPath, yaml, "utf8");
55
+ return {
56
+ inputPath: resolvedInputPath,
57
+ outPath: resolvedOutPath,
58
+ scene: imported.scene,
59
+ yaml,
60
+ summary: imported.summary,
61
+ diagnostics
62
+ };
63
+ }
64
+ function parseLdtkSource(source, file = "world.ldtk") {
65
+ try {
66
+ const document = JSON.parse(source);
67
+ const diagnostics = validateLdtkProjectShape(document, file);
68
+ return {
69
+ file,
70
+ document,
71
+ diagnostics
72
+ };
73
+ } catch (error) {
74
+ return {
75
+ file,
76
+ diagnostics: [
77
+ {
78
+ severity: "error",
79
+ code: "LDTK_PARSE_ERROR",
80
+ file,
81
+ path: "$",
82
+ message: error instanceof Error ? error.message : String(error),
83
+ suggestion: "Fix the LDtk JSON before importing."
84
+ }
85
+ ]
86
+ };
87
+ }
88
+ }
89
+ function importLdtkProject(project, options = {}) {
90
+ const file = options.file ?? "world.ldtk";
91
+ const diagnostics = validateLdtkProjectShape(project, file);
92
+ if (hasErrors(diagnostics)) {
93
+ return { diagnostics };
94
+ }
95
+ const selected = selectLevel(project, options, file, diagnostics);
96
+ if (!selected || hasErrors(diagnostics)) {
97
+ return { diagnostics };
98
+ }
99
+ const stats = {
100
+ ignoredLayerCount: 0,
101
+ ignoredFieldCount: 0
102
+ };
103
+ const scene = levelToScene(selected, file, diagnostics, stats);
104
+ diagnostics.push(...validateSceneDocument(scene, file));
105
+ const summary = buildSummary(selected, stats, scene);
106
+ return {
107
+ scene: hasErrors(diagnostics) ? void 0 : scene,
108
+ yaml: hasErrors(diagnostics) ? void 0 : formatScene(scene),
109
+ summary: hasErrors(diagnostics) ? void 0 : summary,
110
+ diagnostics
111
+ };
112
+ }
113
+ function validateLdtkProjectShape(value, file) {
114
+ const diagnostics = [];
115
+ if (!isRecord(value)) {
116
+ diagnostics.push({
117
+ severity: "error",
118
+ code: "LDTK_SCHEMA_INVALID",
119
+ file,
120
+ path: "$",
121
+ message: "LDtk input must be a JSON object.",
122
+ suggestion: "Export or save a valid LDtk project JSON file."
123
+ });
124
+ return diagnostics;
125
+ }
126
+ if (!Array.isArray(value.levels)) {
127
+ diagnostics.push({
128
+ severity: "error",
129
+ code: "LDTK_LEVELS_MISSING",
130
+ file,
131
+ path: "$.levels",
132
+ message: "LDtk input must contain a levels array.",
133
+ suggestion: "Save the LDtk project with embedded level data before importing."
134
+ });
135
+ return diagnostics;
136
+ }
137
+ if (value.levels.length === 0) {
138
+ diagnostics.push({
139
+ severity: "error",
140
+ code: "LDTK_LEVELS_EMPTY",
141
+ file,
142
+ path: "$.levels",
143
+ message: "LDtk input does not contain any levels.",
144
+ suggestion: "Add a level in LDtk before importing."
145
+ });
146
+ }
147
+ return diagnostics;
148
+ }
149
+ function selectLevel(project, options, file, diagnostics) {
150
+ const levels = project.levels ?? [];
151
+ if (options.levelIdentifier) {
152
+ const levelIndex = levels.findIndex(
153
+ (candidate) => candidate.identifier === options.levelIdentifier || candidate.iid === options.levelIdentifier
154
+ );
155
+ if (levelIndex === -1) {
156
+ diagnostics.push({
157
+ severity: "error",
158
+ code: "LDTK_LEVEL_NOT_FOUND",
159
+ file,
160
+ path: "$.levels",
161
+ message: `LDtk level '${options.levelIdentifier}' was not found. Available levels: ${availableLevelList(levels)}.`,
162
+ suggestion: "Pass --level with one of the listed identifiers or iids."
163
+ });
164
+ return void 0;
165
+ }
166
+ return {
167
+ level: levels[levelIndex],
168
+ index: levelIndex,
169
+ ignoredLevelCount: Math.max(0, levels.length - 1)
170
+ };
171
+ }
172
+ if (levels.length > 1) {
173
+ diagnostics.push({
174
+ severity: "warning",
175
+ code: "LDTK_MULTIPLE_LEVELS_IGNORED",
176
+ file,
177
+ path: "$.levels",
178
+ message: `Imported the first LDtk level and ignored ${levels.length - 1} additional level(s).`,
179
+ suggestion: "Pass --level <identifierOrIid> to import a specific level."
180
+ });
181
+ }
182
+ return {
183
+ level: levels[0],
184
+ index: 0,
185
+ ignoredLevelCount: Math.max(0, levels.length - 1)
186
+ };
187
+ }
188
+ function levelToScene(selected, file, diagnostics, stats) {
189
+ const level = selected.level;
190
+ const layerInstances = level.layerInstances;
191
+ if (!Array.isArray(layerInstances)) {
192
+ diagnostics.push({
193
+ severity: "error",
194
+ code: "LDTK_LEVEL_LAYERS_MISSING",
195
+ file,
196
+ path: `$.levels[${selected.index}].layerInstances`,
197
+ message: `LDtk level '${levelLabel(level, selected.index)}' does not contain embedded layer instances.`,
198
+ suggestion: "Save the LDtk project with internal level data before importing."
199
+ });
200
+ return {
201
+ version: 1,
202
+ name: sceneName(level),
203
+ entities: []
204
+ };
205
+ }
206
+ const usedEntityIds = /* @__PURE__ */ new Map();
207
+ const entities = [];
208
+ layerInstances.forEach((layer, layerIndex) => {
209
+ stats.ignoredLayerCount += warnForIgnoredLayerData(layer, selected, layerIndex, file, diagnostics);
210
+ const entityInstances = Array.isArray(layer.entityInstances) ? layer.entityInstances : [];
211
+ entityInstances.forEach((entity, entityIndex) => {
212
+ const converted = entityInstanceToSceneEntity(entity, {
213
+ levelIndex: selected.index,
214
+ layer,
215
+ layerIndex,
216
+ entityIndex,
217
+ usedEntityIds,
218
+ file,
219
+ diagnostics,
220
+ stats
221
+ });
222
+ if (converted) {
223
+ entities.push(converted);
224
+ }
225
+ });
226
+ });
227
+ return {
228
+ version: 1,
229
+ name: sceneName(level),
230
+ entities
231
+ };
232
+ }
233
+ function entityInstanceToSceneEntity(entity, context) {
234
+ const position = readVector2(entity.px);
235
+ const entityPath = `$.levels[${context.levelIndex}].layerInstances[${context.layerIndex}].entityInstances[${context.entityIndex}]`;
236
+ if (!position) {
237
+ context.diagnostics.push({
238
+ severity: "error",
239
+ code: "LDTK_ENTITY_POSITION_INVALID",
240
+ file: context.file,
241
+ path: `${entityPath}.px`,
242
+ message: `LDtk entity '${entityLabel(entity, context.entityIndex)}' in layer '${layerLabel(context.layer, context.layerIndex)}' is missing a two-number px position.`,
243
+ suggestion: "Ensure the entity has a valid LDtk px coordinate before importing."
244
+ });
245
+ return void 0;
246
+ }
247
+ context.stats.ignoredFieldCount += warnForIgnoredEntityFields(
248
+ entity,
249
+ context.entityIndex,
250
+ entityPath,
251
+ context.file,
252
+ context.diagnostics
253
+ );
254
+ const width = entity.width;
255
+ const height = entity.height;
256
+ const hasBoxCollider = isPositiveFiniteNumber(width) && isPositiveFiniteNumber(height);
257
+ const transformPosition = hasBoxCollider ? [position[0] + width / 2, position[1] + height / 2] : position;
258
+ const components = {
259
+ Transform: {
260
+ position: transformPosition,
261
+ rotation: 0,
262
+ scale: [1, 1]
263
+ }
264
+ };
265
+ if (hasBoxCollider) {
266
+ components.Collider = {
267
+ shape: "box",
268
+ size: [width, height],
269
+ static: true
270
+ };
271
+ }
272
+ return {
273
+ id: uniqueEntityId(stableEntityIdBase(entity, context), context.usedEntityIds),
274
+ components
275
+ };
276
+ }
277
+ function warnForIgnoredLayerData(layer, selected, layerIndex, file, diagnostics) {
278
+ const hasIgnoredData = nonEmptyArray(layer.gridTiles) || nonEmptyArray(layer.autoLayerTiles) || nonEmptyArray(layer.intGridCsv);
279
+ if (!hasIgnoredData) {
280
+ return 0;
281
+ }
282
+ diagnostics.push({
283
+ severity: "warning",
284
+ code: "LDTK_LAYER_DATA_IGNORED",
285
+ file,
286
+ path: `$.levels[${selected.index}].layerInstances[${layerIndex}]`,
287
+ message: `LDtk level '${levelLabel(selected.level, selected.index)}' layer '${layerLabel(layer, layerIndex)}' contains tile or grid data that importer v0 does not map.`,
288
+ suggestion: "Importer v0 only converts entity instances. Add an explicit contract before relying on tile or grid data."
289
+ });
290
+ return 1;
291
+ }
292
+ function warnForIgnoredEntityFields(entity, entityIndex, entityPath, file, diagnostics) {
293
+ const ignoredFieldCount = Array.isArray(entity.fieldInstances) ? entity.fieldInstances.length : 0;
294
+ if (ignoredFieldCount === 0) {
295
+ return 0;
296
+ }
297
+ diagnostics.push({
298
+ severity: "warning",
299
+ code: "LDTK_ENTITY_FIELDS_IGNORED",
300
+ file,
301
+ path: `${entityPath}.fieldInstances`,
302
+ message: `LDtk fields for entity '${entityLabel(entity, entityIndex)}' were not imported into components.`,
303
+ suggestion: "Add a component mapping before relying on LDtk field data."
304
+ });
305
+ return ignoredFieldCount;
306
+ }
307
+ function buildSummary(selected, stats, scene) {
308
+ return {
309
+ importedLevel: {
310
+ name: sceneName(selected.level),
311
+ identifier: nonEmptyString(selected.level.identifier),
312
+ iid: nonEmptyString(selected.level.iid)
313
+ },
314
+ ignoredLevelCount: selected.ignoredLevelCount,
315
+ ignoredLayerCount: stats.ignoredLayerCount,
316
+ ignoredFieldCount: stats.ignoredFieldCount,
317
+ entityCount: scene.entities.length
318
+ };
319
+ }
320
+ function availableLevelList(levels) {
321
+ if (levels.length === 0) {
322
+ return "none";
323
+ }
324
+ return levels.map((level, index) => levelLabel(level, index)).join(", ");
325
+ }
326
+ function levelLabel(level, index) {
327
+ const identifier = nonEmptyString(level.identifier);
328
+ const iid = nonEmptyString(level.iid);
329
+ if (identifier && iid) {
330
+ return `${identifier} (${iid})`;
331
+ }
332
+ return identifier ?? iid ?? `level ${index + 1}`;
333
+ }
334
+ function layerLabel(layer, index) {
335
+ return nonEmptyString(layer.__identifier) ?? `layer ${index + 1}`;
336
+ }
337
+ function entityLabel(entity, index) {
338
+ const identifier = nonEmptyString(entity.__identifier);
339
+ const iid = nonEmptyString(entity.iid);
340
+ if (identifier && iid) {
341
+ return `${identifier} (${iid})`;
342
+ }
343
+ return identifier ?? iid ?? `entity ${index + 1}`;
344
+ }
345
+ function stableEntityIdBase(entity, context) {
346
+ const type = nonEmptyString(entity.__identifier) ?? "entity";
347
+ const name = readNameField(entity.fieldInstances);
348
+ const iid = nonEmptyString(entity.iid);
349
+ const fallback = `${nonEmptyString(context.layer.__identifier) ?? `layer${context.layerIndex + 1}`}_${context.entityIndex + 1}`;
350
+ const parts = [type, name && name !== type ? name : void 0, iid ?? fallback].filter(Boolean);
351
+ return sanitizeEntityId(parts.join("_"));
352
+ }
353
+ function uniqueEntityId(base, usedEntityIds) {
354
+ const count = usedEntityIds.get(base) ?? 0;
355
+ usedEntityIds.set(base, count + 1);
356
+ if (count === 0) {
357
+ return base;
358
+ }
359
+ return `${base}_${count + 1}`;
360
+ }
361
+ function sanitizeEntityId(value) {
362
+ const cleaned = value.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/_+/g, "_").replace(/^[_-]+|[_-]+$/g, "");
363
+ if (!cleaned) {
364
+ return "entity";
365
+ }
366
+ if (!/^[A-Za-z]/.test(cleaned)) {
367
+ return `entity_${cleaned}`;
368
+ }
369
+ return cleaned;
370
+ }
371
+ function sceneName(level) {
372
+ return nonEmptyString(level.identifier) ?? nonEmptyString(level.iid) ?? "ldtk_import";
373
+ }
374
+ function readNameField(fields) {
375
+ if (!Array.isArray(fields)) {
376
+ return void 0;
377
+ }
378
+ for (const field of fields) {
379
+ const fieldName = nonEmptyString(field.__identifier)?.toLowerCase();
380
+ if (!fieldName || !["entityid", "entity_id", "id", "name"].includes(fieldName)) {
381
+ continue;
382
+ }
383
+ const value = nonEmptyString(field.__value);
384
+ if (value) {
385
+ return value;
386
+ }
387
+ }
388
+ return void 0;
389
+ }
390
+ function readVector2(value) {
391
+ if (!Array.isArray(value) || value.length !== 2) {
392
+ return void 0;
393
+ }
394
+ const [x, y] = value;
395
+ if (!Number.isFinite(x) || !Number.isFinite(y)) {
396
+ return void 0;
397
+ }
398
+ return [x, y];
399
+ }
400
+ function nonEmptyString(value) {
401
+ return typeof value === "string" && value.length > 0 ? value : void 0;
402
+ }
403
+ function isPositiveFiniteNumber(value) {
404
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
405
+ }
406
+ function nonEmptyArray(value) {
407
+ return Array.isArray(value) && value.length > 0;
408
+ }
409
+ function isRecord(value) {
410
+ return typeof value === "object" && value !== null && !Array.isArray(value);
411
+ }
412
+ export {
413
+ importLdtkProject,
414
+ importLdtkSceneFile,
415
+ parseLdtkSource
416
+ };
417
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport {\r\n formatScene,\r\n hasErrors,\r\n validateSceneDocument,\r\n type Diagnostic,\r\n type SceneDocument,\r\n type SceneEntity,\r\n type ValidationResult\r\n} from \"@game_engine/scene\";\r\n\r\nexport interface LdtkProject {\r\n jsonVersion?: string;\r\n levels?: LdtkLevel[];\r\n}\r\n\r\nexport interface LdtkLevel {\r\n identifier?: string;\r\n iid?: string;\r\n pxWid?: number;\r\n pxHei?: number;\r\n worldX?: number;\r\n worldY?: number;\r\n layerInstances?: LdtkLayerInstance[] | null;\r\n}\r\n\r\nexport interface LdtkLayerInstance {\r\n __identifier?: string;\r\n __type?: string;\r\n __gridSize?: number;\r\n entityInstances?: LdtkEntityInstance[];\r\n gridTiles?: unknown[];\r\n autoLayerTiles?: unknown[];\r\n intGridCsv?: unknown[];\r\n}\r\n\r\nexport interface LdtkEntityInstance {\r\n __identifier?: string;\r\n iid?: string;\r\n px?: [number, number];\r\n width?: number;\r\n height?: number;\r\n fieldInstances?: LdtkFieldInstance[];\r\n}\r\n\r\nexport interface LdtkFieldInstance {\r\n __identifier?: string;\r\n __value?: unknown;\r\n}\r\n\r\nexport interface LdtkImportOptions {\r\n levelIdentifier?: string;\r\n}\r\n\r\nexport interface LdtkImportSummary {\r\n importedLevel: {\r\n name: string;\r\n identifier?: string;\r\n iid?: string;\r\n };\r\n ignoredLevelCount: number;\r\n ignoredLayerCount: number;\r\n ignoredFieldCount: number;\r\n entityCount: number;\r\n}\r\n\r\nexport interface LdtkImportResult {\r\n inputPath?: string;\r\n outPath?: string;\r\n scene?: SceneDocument;\r\n yaml?: string;\r\n summary?: LdtkImportSummary;\r\n diagnostics: Diagnostic[];\r\n}\r\n\r\ninterface SelectedLdtkLevel {\r\n level: LdtkLevel;\r\n index: number;\r\n ignoredLevelCount: number;\r\n}\r\n\r\ninterface LevelImportStats {\r\n ignoredLayerCount: number;\r\n ignoredFieldCount: number;\r\n}\r\n\r\nexport async function importLdtkSceneFile(\r\n inputPath: string,\r\n outPath: string,\r\n options: LdtkImportOptions & { cwd?: string } = {}\r\n): Promise<LdtkImportResult> {\r\n const resolvedInputPath = path.resolve(options.cwd ?? process.cwd(), inputPath);\r\n const resolvedOutPath = path.resolve(options.cwd ?? process.cwd(), outPath);\r\n\r\n let source: string;\r\n try {\r\n source = await readFile(resolvedInputPath, \"utf8\");\r\n } catch (error) {\r\n return {\r\n inputPath: resolvedInputPath,\r\n outPath: resolvedOutPath,\r\n diagnostics: [\r\n {\r\n severity: \"error\",\r\n code: \"LDTK_FILE_READ_FAILED\",\r\n file: resolvedInputPath,\r\n path: \"$\",\r\n message: error instanceof Error ? error.message : String(error),\r\n suggestion: \"Check that the LDtk input path exists and is readable.\"\r\n }\r\n ]\r\n };\r\n }\r\n\r\n const parsed = parseLdtkSource(source, resolvedInputPath);\r\n const diagnostics = [...parsed.diagnostics];\r\n\r\n if (!parsed.document || hasErrors(diagnostics)) {\r\n return {\r\n inputPath: resolvedInputPath,\r\n outPath: resolvedOutPath,\r\n diagnostics\r\n };\r\n }\r\n\r\n const imported = importLdtkProject(parsed.document, {\r\n ...options,\r\n file: resolvedInputPath\r\n });\r\n diagnostics.push(...imported.diagnostics);\r\n\r\n if (!imported.scene || hasErrors(diagnostics)) {\r\n return {\r\n inputPath: resolvedInputPath,\r\n outPath: resolvedOutPath,\r\n diagnostics\r\n };\r\n }\r\n\r\n const yaml = formatScene(imported.scene);\r\n await mkdir(path.dirname(resolvedOutPath), { recursive: true });\r\n await writeFile(resolvedOutPath, yaml, \"utf8\");\r\n\r\n return {\r\n inputPath: resolvedInputPath,\r\n outPath: resolvedOutPath,\r\n scene: imported.scene,\r\n yaml,\r\n summary: imported.summary,\r\n diagnostics\r\n };\r\n}\r\n\r\nexport function parseLdtkSource(source: string, file = \"world.ldtk\"): ValidationResult<LdtkProject> {\r\n try {\r\n const document = JSON.parse(source) as unknown;\r\n const diagnostics = validateLdtkProjectShape(document, file);\r\n\r\n return {\r\n file,\r\n document: document as LdtkProject,\r\n diagnostics\r\n };\r\n } catch (error) {\r\n return {\r\n file,\r\n diagnostics: [\r\n {\r\n severity: \"error\",\r\n code: \"LDTK_PARSE_ERROR\",\r\n file,\r\n path: \"$\",\r\n message: error instanceof Error ? error.message : String(error),\r\n suggestion: \"Fix the LDtk JSON before importing.\"\r\n }\r\n ]\r\n };\r\n }\r\n}\r\n\r\nexport function importLdtkProject(\r\n project: LdtkProject,\r\n options: LdtkImportOptions & { file?: string } = {}\r\n): LdtkImportResult {\r\n const file = options.file ?? \"world.ldtk\";\r\n const diagnostics = validateLdtkProjectShape(project, file);\r\n\r\n if (hasErrors(diagnostics)) {\r\n return { diagnostics };\r\n }\r\n\r\n const selected = selectLevel(project, options, file, diagnostics);\r\n if (!selected || hasErrors(diagnostics)) {\r\n return { diagnostics };\r\n }\r\n\r\n const stats: LevelImportStats = {\r\n ignoredLayerCount: 0,\r\n ignoredFieldCount: 0\r\n };\r\n const scene = levelToScene(selected, file, diagnostics, stats);\r\n diagnostics.push(...validateSceneDocument(scene, file));\r\n const summary = buildSummary(selected, stats, scene);\r\n\r\n return {\r\n scene: hasErrors(diagnostics) ? undefined : scene,\r\n yaml: hasErrors(diagnostics) ? undefined : formatScene(scene),\r\n summary: hasErrors(diagnostics) ? undefined : summary,\r\n diagnostics\r\n };\r\n}\r\n\r\nfunction validateLdtkProjectShape(value: unknown, file: string): Diagnostic[] {\r\n const diagnostics: Diagnostic[] = [];\r\n\r\n if (!isRecord(value)) {\r\n diagnostics.push({\r\n severity: \"error\",\r\n code: \"LDTK_SCHEMA_INVALID\",\r\n file,\r\n path: \"$\",\r\n message: \"LDtk input must be a JSON object.\",\r\n suggestion: \"Export or save a valid LDtk project JSON file.\"\r\n });\r\n return diagnostics;\r\n }\r\n\r\n if (!Array.isArray(value.levels)) {\r\n diagnostics.push({\r\n severity: \"error\",\r\n code: \"LDTK_LEVELS_MISSING\",\r\n file,\r\n path: \"$.levels\",\r\n message: \"LDtk input must contain a levels array.\",\r\n suggestion: \"Save the LDtk project with embedded level data before importing.\"\r\n });\r\n return diagnostics;\r\n }\r\n\r\n if (value.levels.length === 0) {\r\n diagnostics.push({\r\n severity: \"error\",\r\n code: \"LDTK_LEVELS_EMPTY\",\r\n file,\r\n path: \"$.levels\",\r\n message: \"LDtk input does not contain any levels.\",\r\n suggestion: \"Add a level in LDtk before importing.\"\r\n });\r\n }\r\n\r\n return diagnostics;\r\n}\r\n\r\nfunction selectLevel(\r\n project: LdtkProject,\r\n options: LdtkImportOptions,\r\n file: string,\r\n diagnostics: Diagnostic[]\r\n): SelectedLdtkLevel | undefined {\r\n const levels = project.levels ?? [];\r\n\r\n if (options.levelIdentifier) {\r\n const levelIndex = levels.findIndex(\r\n (candidate) => candidate.identifier === options.levelIdentifier || candidate.iid === options.levelIdentifier\r\n );\r\n if (levelIndex === -1) {\r\n diagnostics.push({\r\n severity: \"error\",\r\n code: \"LDTK_LEVEL_NOT_FOUND\",\r\n file,\r\n path: \"$.levels\",\r\n message: `LDtk level '${options.levelIdentifier}' was not found. Available levels: ${availableLevelList(levels)}.`,\r\n suggestion: \"Pass --level with one of the listed identifiers or iids.\"\r\n });\r\n return undefined;\r\n }\r\n return {\r\n level: levels[levelIndex]!,\r\n index: levelIndex,\r\n ignoredLevelCount: Math.max(0, levels.length - 1)\r\n };\r\n }\r\n\r\n if (levels.length > 1) {\r\n diagnostics.push({\r\n severity: \"warning\",\r\n code: \"LDTK_MULTIPLE_LEVELS_IGNORED\",\r\n file,\r\n path: \"$.levels\",\r\n message: `Imported the first LDtk level and ignored ${levels.length - 1} additional level(s).`,\r\n suggestion: \"Pass --level <identifierOrIid> to import a specific level.\"\r\n });\r\n }\r\n\r\n return {\r\n level: levels[0]!,\r\n index: 0,\r\n ignoredLevelCount: Math.max(0, levels.length - 1)\r\n };\r\n}\r\n\r\nfunction levelToScene(\r\n selected: SelectedLdtkLevel,\r\n file: string,\r\n diagnostics: Diagnostic[],\r\n stats: LevelImportStats\r\n): SceneDocument {\r\n const level = selected.level;\r\n const layerInstances = level.layerInstances;\r\n if (!Array.isArray(layerInstances)) {\r\n diagnostics.push({\r\n severity: \"error\",\r\n code: \"LDTK_LEVEL_LAYERS_MISSING\",\r\n file,\r\n path: `$.levels[${selected.index}].layerInstances`,\r\n message: `LDtk level '${levelLabel(level, selected.index)}' does not contain embedded layer instances.`,\r\n suggestion: \"Save the LDtk project with internal level data before importing.\"\r\n });\r\n\r\n return {\r\n version: 1,\r\n name: sceneName(level),\r\n entities: []\r\n };\r\n }\r\n\r\n const usedEntityIds = new Map<string, number>();\r\n const entities: SceneEntity[] = [];\r\n\r\n layerInstances.forEach((layer, layerIndex) => {\r\n stats.ignoredLayerCount += warnForIgnoredLayerData(layer, selected, layerIndex, file, diagnostics);\r\n\r\n const entityInstances = Array.isArray(layer.entityInstances) ? layer.entityInstances : [];\r\n entityInstances.forEach((entity, entityIndex) => {\r\n const converted = entityInstanceToSceneEntity(entity, {\r\n levelIndex: selected.index,\r\n layer,\r\n layerIndex,\r\n entityIndex,\r\n usedEntityIds,\r\n file,\r\n diagnostics,\r\n stats\r\n });\r\n\r\n if (converted) {\r\n entities.push(converted);\r\n }\r\n });\r\n });\r\n\r\n return {\r\n version: 1,\r\n name: sceneName(level),\r\n entities\r\n };\r\n}\r\n\r\nfunction entityInstanceToSceneEntity(\r\n entity: LdtkEntityInstance,\r\n context: {\r\n levelIndex: number;\r\n layer: LdtkLayerInstance;\r\n layerIndex: number;\r\n entityIndex: number;\r\n usedEntityIds: Map<string, number>;\r\n file: string;\r\n diagnostics: Diagnostic[];\r\n stats: LevelImportStats;\r\n }\r\n): SceneEntity | undefined {\r\n const position = readVector2(entity.px);\r\n const entityPath = `$.levels[${context.levelIndex}].layerInstances[${context.layerIndex}].entityInstances[${context.entityIndex}]`;\r\n\r\n if (!position) {\r\n context.diagnostics.push({\r\n severity: \"error\",\r\n code: \"LDTK_ENTITY_POSITION_INVALID\",\r\n file: context.file,\r\n path: `${entityPath}.px`,\r\n message: `LDtk entity '${entityLabel(entity, context.entityIndex)}' in layer '${layerLabel(context.layer, context.layerIndex)}' is missing a two-number px position.`,\r\n suggestion: \"Ensure the entity has a valid LDtk px coordinate before importing.\"\r\n });\r\n return undefined;\r\n }\r\n\r\n context.stats.ignoredFieldCount += warnForIgnoredEntityFields(\r\n entity,\r\n context.entityIndex,\r\n entityPath,\r\n context.file,\r\n context.diagnostics\r\n );\r\n\r\n const width = entity.width;\n const height = entity.height;\n const hasBoxCollider = isPositiveFiniteNumber(width) && isPositiveFiniteNumber(height);\n const transformPosition: [number, number] = hasBoxCollider\n ? [position[0] + width / 2, position[1] + height / 2]\n : position;\n const components: Record<string, unknown> = {\n Transform: {\n position: transformPosition,\n rotation: 0,\n scale: [1, 1]\n }\n };\n\n if (hasBoxCollider) {\n components.Collider = {\n shape: \"box\",\n size: [width, height],\n static: true\n };\n }\n\r\n return {\r\n id: uniqueEntityId(stableEntityIdBase(entity, context), context.usedEntityIds),\r\n components\r\n };\r\n}\r\n\r\nfunction warnForIgnoredLayerData(\r\n layer: LdtkLayerInstance,\r\n selected: SelectedLdtkLevel,\r\n layerIndex: number,\r\n file: string,\r\n diagnostics: Diagnostic[]\r\n): number {\r\n const hasIgnoredData =\r\n nonEmptyArray(layer.gridTiles) || nonEmptyArray(layer.autoLayerTiles) || nonEmptyArray(layer.intGridCsv);\r\n\r\n if (!hasIgnoredData) {\r\n return 0;\r\n }\r\n\r\n diagnostics.push({\r\n severity: \"warning\",\r\n code: \"LDTK_LAYER_DATA_IGNORED\",\r\n file,\r\n path: `$.levels[${selected.index}].layerInstances[${layerIndex}]`,\r\n message: `LDtk level '${levelLabel(selected.level, selected.index)}' layer '${layerLabel(layer, layerIndex)}' contains tile or grid data that importer v0 does not map.`,\r\n suggestion: \"Importer v0 only converts entity instances. Add an explicit contract before relying on tile or grid data.\"\r\n });\r\n\r\n return 1;\r\n}\r\n\r\nfunction warnForIgnoredEntityFields(\r\n entity: LdtkEntityInstance,\r\n entityIndex: number,\r\n entityPath: string,\r\n file: string,\r\n diagnostics: Diagnostic[]\r\n): number {\r\n const ignoredFieldCount = Array.isArray(entity.fieldInstances) ? entity.fieldInstances.length : 0;\r\n if (ignoredFieldCount === 0) {\r\n return 0;\r\n }\r\n\r\n diagnostics.push({\r\n severity: \"warning\",\r\n code: \"LDTK_ENTITY_FIELDS_IGNORED\",\r\n file,\r\n path: `${entityPath}.fieldInstances`,\r\n message: `LDtk fields for entity '${entityLabel(entity, entityIndex)}' were not imported into components.`,\r\n suggestion: \"Add a component mapping before relying on LDtk field data.\"\r\n });\r\n\r\n return ignoredFieldCount;\r\n}\r\n\r\nfunction buildSummary(\r\n selected: SelectedLdtkLevel,\r\n stats: LevelImportStats,\r\n scene: SceneDocument\r\n): LdtkImportSummary {\r\n return {\r\n importedLevel: {\r\n name: sceneName(selected.level),\r\n identifier: nonEmptyString(selected.level.identifier),\r\n iid: nonEmptyString(selected.level.iid)\r\n },\r\n ignoredLevelCount: selected.ignoredLevelCount,\r\n ignoredLayerCount: stats.ignoredLayerCount,\r\n ignoredFieldCount: stats.ignoredFieldCount,\r\n entityCount: scene.entities.length\r\n };\r\n}\r\n\r\nfunction availableLevelList(levels: LdtkLevel[]): string {\r\n if (levels.length === 0) {\r\n return \"none\";\r\n }\r\n\r\n return levels.map((level, index) => levelLabel(level, index)).join(\", \");\r\n}\r\n\r\nfunction levelLabel(level: LdtkLevel, index: number): string {\r\n const identifier = nonEmptyString(level.identifier);\r\n const iid = nonEmptyString(level.iid);\r\n\r\n if (identifier && iid) {\r\n return `${identifier} (${iid})`;\r\n }\r\n\r\n return identifier ?? iid ?? `level ${index + 1}`;\r\n}\r\n\r\nfunction layerLabel(layer: LdtkLayerInstance, index: number): string {\r\n return nonEmptyString(layer.__identifier) ?? `layer ${index + 1}`;\r\n}\r\n\r\nfunction entityLabel(entity: LdtkEntityInstance, index: number): string {\r\n const identifier = nonEmptyString(entity.__identifier);\r\n const iid = nonEmptyString(entity.iid);\r\n\r\n if (identifier && iid) {\r\n return `${identifier} (${iid})`;\r\n }\r\n\r\n return identifier ?? iid ?? `entity ${index + 1}`;\r\n}\r\n\r\nfunction stableEntityIdBase(\r\n entity: LdtkEntityInstance,\r\n context: { layer: LdtkLayerInstance; layerIndex: number; entityIndex: number }\r\n): string {\r\n const type = nonEmptyString(entity.__identifier) ?? \"entity\";\r\n const name = readNameField(entity.fieldInstances);\r\n const iid = nonEmptyString(entity.iid);\r\n const fallback = `${nonEmptyString(context.layer.__identifier) ?? `layer${context.layerIndex + 1}`}_${context.entityIndex + 1}`;\r\n const parts = [type, name && name !== type ? name : undefined, iid ?? fallback].filter(Boolean);\r\n\r\n return sanitizeEntityId(parts.join(\"_\"));\r\n}\r\n\r\nfunction uniqueEntityId(base: string, usedEntityIds: Map<string, number>): string {\r\n const count = usedEntityIds.get(base) ?? 0;\r\n usedEntityIds.set(base, count + 1);\r\n\r\n if (count === 0) {\r\n return base;\r\n }\r\n\r\n return `${base}_${count + 1}`;\r\n}\r\n\r\nfunction sanitizeEntityId(value: string): string {\r\n const cleaned = value\r\n .replace(/[^A-Za-z0-9_-]+/g, \"_\")\r\n .replace(/_+/g, \"_\")\r\n .replace(/^[_-]+|[_-]+$/g, \"\");\r\n\r\n if (!cleaned) {\r\n return \"entity\";\r\n }\r\n\r\n if (!/^[A-Za-z]/.test(cleaned)) {\r\n return `entity_${cleaned}`;\r\n }\r\n\r\n return cleaned;\r\n}\r\n\r\nfunction sceneName(level: LdtkLevel): string {\r\n return nonEmptyString(level.identifier) ?? nonEmptyString(level.iid) ?? \"ldtk_import\";\r\n}\r\n\r\nfunction readNameField(fields: LdtkFieldInstance[] | undefined): string | undefined {\r\n if (!Array.isArray(fields)) {\r\n return undefined;\r\n }\r\n\r\n for (const field of fields) {\r\n const fieldName = nonEmptyString(field.__identifier)?.toLowerCase();\r\n if (!fieldName || ![\"entityid\", \"entity_id\", \"id\", \"name\"].includes(fieldName)) {\r\n continue;\r\n }\r\n\r\n const value = nonEmptyString(field.__value);\r\n if (value) {\r\n return value;\r\n }\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\nfunction readVector2(value: unknown): [number, number] | undefined {\r\n if (!Array.isArray(value) || value.length !== 2) {\r\n return undefined;\r\n }\r\n\r\n const [x, y] = value;\r\n if (!Number.isFinite(x) || !Number.isFinite(y)) {\r\n return undefined;\r\n }\r\n\r\n return [x, y];\r\n}\r\n\r\nfunction nonEmptyString(value: unknown): string | undefined {\r\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\r\n}\r\n\r\nfunction isPositiveFiniteNumber(value: unknown): value is number {\r\n return typeof value === \"number\" && Number.isFinite(value) && value > 0;\r\n}\r\n\r\nfunction nonEmptyArray(value: unknown): boolean {\r\n return Array.isArray(value) && value.length > 0;\r\n}\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@game_engine/import-ldtk",
3
+ "version": "0.1.0-alpha",
4
+ "description": "LDtk-to-Agent Engine scene importer for text-first workflows.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/rktkdduq01/game_engine.git",
9
+ "directory": "packages/import-ldtk"
10
+ },
11
+ "keywords": [
12
+ "agent-engine",
13
+ "game-engine",
14
+ "ai-agent",
15
+ "ldtk",
16
+ "importer"
17
+ ],
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ }
32
+ },
33
+ "scripts": {
34
+ "build": "tsup src/index.ts --format esm --dts --sourcemap --clean"
35
+ },
36
+ "dependencies": {
37
+ "@game_engine/scene": "workspace:*"
38
+ },
39
+ "devDependencies": {
40
+ "tsup": "^8.3.5",
41
+ "typescript": "^5.7.2",
42
+ "vitest": "^2.1.8"
43
+ }
44
+ }