@nice2dev/game-engine 1.0.2 → 1.0.4

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.
Files changed (188) hide show
  1. package/dist/cjs/ai/BehaviorTree.js +1215 -0
  2. package/dist/cjs/ai/BehaviorTree.js.map +1 -0
  3. package/dist/cjs/ai/StateMachine.js +783 -0
  4. package/dist/cjs/ai/StateMachine.js.map +1 -0
  5. package/dist/cjs/editor/ShaderGraph.js +1616 -0
  6. package/dist/cjs/editor/ShaderGraph.js.map +1 -0
  7. package/dist/cjs/editor/TimelineEditor.js +819 -0
  8. package/dist/cjs/editor/TimelineEditor.js.map +1 -0
  9. package/dist/cjs/export/GodotExporter.js +1102 -0
  10. package/dist/cjs/export/GodotExporter.js.map +1 -0
  11. package/dist/cjs/export/PlatformExporter.js +236 -0
  12. package/dist/cjs/export/PlatformExporter.js.map +1 -0
  13. package/dist/cjs/export/ThreeJSExporter.js +1116 -0
  14. package/dist/cjs/export/ThreeJSExporter.js.map +1 -0
  15. package/dist/cjs/export/UnityExporter.js +1193 -0
  16. package/dist/cjs/export/UnityExporter.js.map +1 -0
  17. package/dist/cjs/export/WebExporter.js +1036 -0
  18. package/dist/cjs/export/WebExporter.js.map +1 -0
  19. package/dist/cjs/export/index.js +58 -0
  20. package/dist/cjs/export/index.js.map +1 -0
  21. package/dist/cjs/import/AsepriteImporter.js +761 -0
  22. package/dist/cjs/import/AsepriteImporter.js.map +1 -0
  23. package/dist/cjs/import/DragonBonesImporter.js +499 -0
  24. package/dist/cjs/import/DragonBonesImporter.js.map +1 -0
  25. package/dist/cjs/import/GameMakerImporter.js +559 -0
  26. package/dist/cjs/import/GameMakerImporter.js.map +1 -0
  27. package/dist/cjs/import/GodotSceneImporter.js +824 -0
  28. package/dist/cjs/import/GodotSceneImporter.js.map +1 -0
  29. package/dist/cjs/import/LDtkImporter.js +481 -0
  30. package/dist/cjs/import/LDtkImporter.js.map +1 -0
  31. package/dist/cjs/import/Live2DImporter.js +553 -0
  32. package/dist/cjs/import/Live2DImporter.js.map +1 -0
  33. package/dist/cjs/import/NdgFormat.js +499 -0
  34. package/dist/cjs/import/NdgFormat.js.map +1 -0
  35. package/dist/cjs/import/OgmoImporter.js +529 -0
  36. package/dist/cjs/import/OgmoImporter.js.map +1 -0
  37. package/dist/cjs/import/RPGMakerImporter.js +520 -0
  38. package/dist/cjs/import/RPGMakerImporter.js.map +1 -0
  39. package/dist/cjs/import/SceneImporter.js +449 -0
  40. package/dist/cjs/import/SceneImporter.js.map +1 -0
  41. package/dist/cjs/import/SpineImporter.js +583 -0
  42. package/dist/cjs/import/SpineImporter.js.map +1 -0
  43. package/dist/cjs/import/SpriterImporter.js +652 -0
  44. package/dist/cjs/import/SpriterImporter.js.map +1 -0
  45. package/dist/cjs/import/TiledMapImporter.js +859 -0
  46. package/dist/cjs/import/TiledMapImporter.js.map +1 -0
  47. package/dist/cjs/import/UnitySceneImporter.js +732 -0
  48. package/dist/cjs/import/UnitySceneImporter.js.map +1 -0
  49. package/dist/cjs/import/index.js +305 -0
  50. package/dist/cjs/import/index.js.map +1 -0
  51. package/dist/cjs/index.js +201 -0
  52. package/dist/cjs/index.js.map +1 -1
  53. package/dist/cjs/scripting/GraphToAST.js +567 -0
  54. package/dist/cjs/scripting/GraphToAST.js.map +1 -0
  55. package/dist/cjs/scripting/LanguageExporter.js +321 -0
  56. package/dist/cjs/scripting/LanguageExporter.js.map +1 -0
  57. package/dist/cjs/scripting/ScriptAST.js +67 -0
  58. package/dist/cjs/scripting/ScriptAST.js.map +1 -0
  59. package/dist/cjs/scripting/VisualScripting2.js +1140 -0
  60. package/dist/cjs/scripting/VisualScripting2.js.map +1 -0
  61. package/dist/cjs/scripting/exporters/CSharpExporter.js +503 -0
  62. package/dist/cjs/scripting/exporters/CSharpExporter.js.map +1 -0
  63. package/dist/cjs/scripting/exporters/GDScriptExporter.js +452 -0
  64. package/dist/cjs/scripting/exporters/GDScriptExporter.js.map +1 -0
  65. package/dist/cjs/scripting/exporters/LuaExporter.js +457 -0
  66. package/dist/cjs/scripting/exporters/LuaExporter.js.map +1 -0
  67. package/dist/cjs/scripting/exporters/PythonExporter.js +565 -0
  68. package/dist/cjs/scripting/exporters/PythonExporter.js.map +1 -0
  69. package/dist/cjs/scripting/exporters/RustExporter.js +525 -0
  70. package/dist/cjs/scripting/exporters/RustExporter.js.map +1 -0
  71. package/dist/cjs/scripting/exporters/TypeScriptExporter.js +570 -0
  72. package/dist/cjs/scripting/exporters/TypeScriptExporter.js.map +1 -0
  73. package/dist/cjs/systems/ParticleSystem2.js +1478 -0
  74. package/dist/cjs/systems/ParticleSystem2.js.map +1 -0
  75. package/dist/esm/ai/BehaviorTree.js +1186 -0
  76. package/dist/esm/ai/BehaviorTree.js.map +1 -0
  77. package/dist/esm/ai/StateMachine.js +767 -0
  78. package/dist/esm/ai/StateMachine.js.map +1 -0
  79. package/dist/esm/editor/ShaderGraph.js +1606 -0
  80. package/dist/esm/editor/ShaderGraph.js.map +1 -0
  81. package/dist/esm/editor/TimelineEditor.js +800 -0
  82. package/dist/esm/editor/TimelineEditor.js.map +1 -0
  83. package/dist/esm/export/GodotExporter.js +1100 -0
  84. package/dist/esm/export/GodotExporter.js.map +1 -0
  85. package/dist/esm/export/PlatformExporter.js +230 -0
  86. package/dist/esm/export/PlatformExporter.js.map +1 -0
  87. package/dist/esm/export/ThreeJSExporter.js +1114 -0
  88. package/dist/esm/export/ThreeJSExporter.js.map +1 -0
  89. package/dist/esm/export/UnityExporter.js +1191 -0
  90. package/dist/esm/export/UnityExporter.js.map +1 -0
  91. package/dist/esm/export/WebExporter.js +1033 -0
  92. package/dist/esm/export/WebExporter.js.map +1 -0
  93. package/dist/esm/export/index.js +44 -0
  94. package/dist/esm/export/index.js.map +1 -0
  95. package/dist/esm/import/AsepriteImporter.js +759 -0
  96. package/dist/esm/import/AsepriteImporter.js.map +1 -0
  97. package/dist/esm/import/DragonBonesImporter.js +496 -0
  98. package/dist/esm/import/DragonBonesImporter.js.map +1 -0
  99. package/dist/esm/import/GameMakerImporter.js +556 -0
  100. package/dist/esm/import/GameMakerImporter.js.map +1 -0
  101. package/dist/esm/import/GodotSceneImporter.js +822 -0
  102. package/dist/esm/import/GodotSceneImporter.js.map +1 -0
  103. package/dist/esm/import/LDtkImporter.js +479 -0
  104. package/dist/esm/import/LDtkImporter.js.map +1 -0
  105. package/dist/esm/import/Live2DImporter.js +550 -0
  106. package/dist/esm/import/Live2DImporter.js.map +1 -0
  107. package/dist/esm/import/NdgFormat.js +490 -0
  108. package/dist/esm/import/NdgFormat.js.map +1 -0
  109. package/dist/esm/import/OgmoImporter.js +526 -0
  110. package/dist/esm/import/OgmoImporter.js.map +1 -0
  111. package/dist/esm/import/RPGMakerImporter.js +517 -0
  112. package/dist/esm/import/RPGMakerImporter.js.map +1 -0
  113. package/dist/esm/import/SceneImporter.js +441 -0
  114. package/dist/esm/import/SceneImporter.js.map +1 -0
  115. package/dist/esm/import/SpineImporter.js +580 -0
  116. package/dist/esm/import/SpineImporter.js.map +1 -0
  117. package/dist/esm/import/SpriterImporter.js +649 -0
  118. package/dist/esm/import/SpriterImporter.js.map +1 -0
  119. package/dist/esm/import/TiledMapImporter.js +857 -0
  120. package/dist/esm/import/TiledMapImporter.js.map +1 -0
  121. package/dist/esm/import/UnitySceneImporter.js +730 -0
  122. package/dist/esm/import/UnitySceneImporter.js.map +1 -0
  123. package/dist/esm/import/index.js +279 -0
  124. package/dist/esm/import/index.js.map +1 -0
  125. package/dist/esm/index.js +36 -0
  126. package/dist/esm/index.js.map +1 -1
  127. package/dist/esm/scripting/GraphToAST.js +564 -0
  128. package/dist/esm/scripting/GraphToAST.js.map +1 -0
  129. package/dist/esm/scripting/LanguageExporter.js +311 -0
  130. package/dist/esm/scripting/LanguageExporter.js.map +1 -0
  131. package/dist/esm/scripting/ScriptAST.js +52 -0
  132. package/dist/esm/scripting/ScriptAST.js.map +1 -0
  133. package/dist/esm/scripting/VisualScripting2.js +1130 -0
  134. package/dist/esm/scripting/VisualScripting2.js.map +1 -0
  135. package/dist/esm/scripting/exporters/CSharpExporter.js +501 -0
  136. package/dist/esm/scripting/exporters/CSharpExporter.js.map +1 -0
  137. package/dist/esm/scripting/exporters/GDScriptExporter.js +450 -0
  138. package/dist/esm/scripting/exporters/GDScriptExporter.js.map +1 -0
  139. package/dist/esm/scripting/exporters/LuaExporter.js +455 -0
  140. package/dist/esm/scripting/exporters/LuaExporter.js.map +1 -0
  141. package/dist/esm/scripting/exporters/PythonExporter.js +563 -0
  142. package/dist/esm/scripting/exporters/PythonExporter.js.map +1 -0
  143. package/dist/esm/scripting/exporters/RustExporter.js +523 -0
  144. package/dist/esm/scripting/exporters/RustExporter.js.map +1 -0
  145. package/dist/esm/scripting/exporters/TypeScriptExporter.js +568 -0
  146. package/dist/esm/scripting/exporters/TypeScriptExporter.js.map +1 -0
  147. package/dist/esm/systems/ParticleSystem2.js +1471 -0
  148. package/dist/esm/systems/ParticleSystem2.js.map +1 -0
  149. package/dist/types/ai/BehaviorTree.d.ts +375 -0
  150. package/dist/types/ai/StateMachine.d.ts +296 -0
  151. package/dist/types/editor/ShaderGraph.d.ts +207 -0
  152. package/dist/types/editor/TimelineEditor.d.ts +393 -0
  153. package/dist/types/export/GodotExporter.d.ts +56 -0
  154. package/dist/types/export/PlatformExporter.d.ts +201 -0
  155. package/dist/types/export/ThreeJSExporter.d.ts +40 -0
  156. package/dist/types/export/UnityExporter.d.ts +69 -0
  157. package/dist/types/export/WebExporter.d.ts +58 -0
  158. package/dist/types/export/index.d.ts +19 -0
  159. package/dist/types/import/AsepriteImporter.d.ts +46 -0
  160. package/dist/types/import/DragonBonesImporter.d.ts +331 -0
  161. package/dist/types/import/GameMakerImporter.d.ts +375 -0
  162. package/dist/types/import/GodotSceneImporter.d.ts +34 -0
  163. package/dist/types/import/LDtkImporter.d.ts +177 -0
  164. package/dist/types/import/Live2DImporter.d.ts +237 -0
  165. package/dist/types/import/NdgFormat.d.ts +387 -0
  166. package/dist/types/import/OgmoImporter.d.ts +237 -0
  167. package/dist/types/import/RPGMakerImporter.d.ts +186 -0
  168. package/dist/types/import/SceneImporter.d.ts +276 -0
  169. package/dist/types/import/SpineImporter.d.ts +372 -0
  170. package/dist/types/import/SpriterImporter.d.ts +230 -0
  171. package/dist/types/import/TiledMapImporter.d.ts +57 -0
  172. package/dist/types/import/UnitySceneImporter.d.ts +87 -0
  173. package/dist/types/import/index.d.ts +59 -0
  174. package/dist/types/index.d.ts +29 -17
  175. package/dist/types/scripting/GraphToAST.d.ts +55 -0
  176. package/dist/types/scripting/LanguageExporter.d.ts +136 -0
  177. package/dist/types/scripting/ScriptAST.d.ts +312 -0
  178. package/dist/types/scripting/VisualScripting2.d.ts +353 -0
  179. package/dist/types/scripting/exporters/CSharpExporter.d.ts +44 -0
  180. package/dist/types/scripting/exporters/GDScriptExporter.d.ts +46 -0
  181. package/dist/types/scripting/exporters/LuaExporter.d.ts +46 -0
  182. package/dist/types/scripting/exporters/PythonExporter.d.ts +49 -0
  183. package/dist/types/scripting/exporters/RustExporter.d.ts +46 -0
  184. package/dist/types/scripting/exporters/TypeScriptExporter.d.ts +48 -0
  185. package/dist/types/scripting/exporters/index.d.ts +8 -0
  186. package/dist/types/scripting/index.d.ts +11 -0
  187. package/dist/types/systems/ParticleSystem2.d.ts +646 -0
  188. package/package.json +3 -3
@@ -0,0 +1,1191 @@
1
+ import { PlatformExporter } from './PlatformExporter.js';
2
+ import { CSharpExporter } from '../scripting/exporters/CSharpExporter.js';
3
+ import { GraphToAST } from '../scripting/GraphToAST.js';
4
+
5
+ /* ────────────────────────────────────────────────────────────────
6
+ Unity Package Exporter
7
+
8
+ Exports Nice2Dev projects to Unity .unitypackage format.
9
+ Generates C# scripts, prefabs, scenes, and materials.
10
+ ──────────────────────────────────────────────────────────────── */
11
+ /* ── Unity Exporter Class ─────────────────────────────────────── */
12
+ class UnityExporter extends PlatformExporter {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.platformId = 'unity';
16
+ this.platformInfo = {
17
+ id: 'unity',
18
+ name: 'Unity',
19
+ description: 'Professional game engine for 2D and 3D games',
20
+ website: 'https://unity.com',
21
+ features: [
22
+ '2d-rendering',
23
+ '3d-rendering',
24
+ 'physics-2d',
25
+ 'physics-3d',
26
+ 'audio',
27
+ 'networking',
28
+ 'ui-system',
29
+ 'visual-scripting',
30
+ 'particles',
31
+ 'animation',
32
+ 'vr-ar',
33
+ ],
34
+ supportedAssets: [
35
+ 'sprite',
36
+ 'tileset',
37
+ 'audio',
38
+ 'font',
39
+ 'script',
40
+ 'scene',
41
+ 'prefab',
42
+ 'material',
43
+ 'shader',
44
+ 'animation',
45
+ 'particleSystem',
46
+ ],
47
+ exportFormats: ['.unitypackage', '.prefab', '.unity', '.cs'],
48
+ };
49
+ this.csharpExporter = new CSharpExporter();
50
+ this.graphToAST = new GraphToAST();
51
+ this.guidMap = new Map();
52
+ this.fileIdCounter = 100000;
53
+ }
54
+ async doExport(project, options) {
55
+ const unity = options.platformOptions;
56
+ const projectName = options.projectName || project.name;
57
+ const ns = (unity === null || unity === void 0 ? void 0 : unity.namespace) || this.toValidNamespace(projectName);
58
+ // Generate GUIDs for all assets
59
+ this.generateGuids(project);
60
+ // 1. Generate project structure
61
+ await this.exportProjectSettings(project, options, unity);
62
+ // 2. Export scripts
63
+ await this.exportScripts(project, options, ns);
64
+ // 3. Export prefabs
65
+ await this.exportPrefabs(project, options);
66
+ // 4. Export scenes
67
+ await this.exportScenes(project, options);
68
+ // 5. Export materials
69
+ await this.exportMaterials(project, options, unity);
70
+ // 6. Export assets (sprites, audio, etc.)
71
+ await this.exportAssets(project, options);
72
+ // 7. Generate assembly definition
73
+ if ((unity === null || unity === void 0 ? void 0 : unity.generateAsmdef) !== false) {
74
+ this.exportAssemblyDefinition(projectName, ns);
75
+ }
76
+ // 8. Generate Nice2Dev runtime bridge
77
+ if ((unity === null || unity === void 0 ? void 0 : unity.includeRuntime) !== false) {
78
+ this.exportRuntimeBridge(ns);
79
+ }
80
+ // 9. Generate manifest for .unitypackage
81
+ this.exportPackageManifest(project);
82
+ }
83
+ /* ── Project Settings ───────────────────────────────────────── */
84
+ async exportProjectSettings(project, options, unity) {
85
+ var _a;
86
+ // ProjectSettings.asset
87
+ const settings = `%YAML 1.1
88
+ %TAG !u! tag:unity3d.com,2011:
89
+ --- !u!129 &1
90
+ PlayerSettings:
91
+ productName: ${project.name}
92
+ companyName: ${project.author || 'Nice2Dev'}
93
+ defaultScreenWidth: ${project.settings.resolution.width}
94
+ defaultScreenHeight: ${project.settings.resolution.height}
95
+ runInBackground: 1
96
+ colorSpace: 1
97
+ activeInputHandler: 2
98
+ targetGpuSkinning: 1`;
99
+ this.addTextFile(`ProjectSettings/ProjectSettings.asset`, settings);
100
+ this.addTextFile(`ProjectSettings/ProjectSettings.asset.meta`, this.createMetaFile('project-settings'));
101
+ // Physics2DSettings.asset
102
+ if ((_a = project.settings.physics) === null || _a === void 0 ? void 0 : _a.enabled) {
103
+ const gravity = project.settings.physics.gravity;
104
+ const physics2d = `%YAML 1.1
105
+ %TAG !u! tag:unity3d.com,2011:
106
+ --- !u!19 &1
107
+ Physics2DSettings:
108
+ m_Gravity: {x: ${gravity.x}, y: ${gravity.y}}
109
+ m_DefaultMaterial: {fileID: 0}
110
+ m_VelocityIterations: 8
111
+ m_PositionIterations: 3`;
112
+ this.addTextFile(`ProjectSettings/Physics2DSettings.asset`, physics2d);
113
+ }
114
+ }
115
+ /* ── Scripts ────────────────────────────────────────────────── */
116
+ async exportScripts(project, options, namespace) {
117
+ for (const script of project.scripts) {
118
+ try {
119
+ const ast = this.graphToAST.convert(script);
120
+ const result = this.csharpExporter.export(ast, {
121
+ namespace,
122
+ includeDebugComments: options.debug,
123
+ });
124
+ for (const file of result.files) {
125
+ const path = `Assets/Scripts/${file.path}`;
126
+ this.addTextFile(path, file.content);
127
+ this.addTextFile(`${path}.meta`, this.createScriptMetaFile(script.id));
128
+ }
129
+ }
130
+ catch (error) {
131
+ this.addWarning('SCRIPT_EXPORT_ERROR', `Failed to export script "${script.name}": ${error}`, 'Check visual script for errors');
132
+ }
133
+ }
134
+ }
135
+ /* ── Prefabs ────────────────────────────────────────────────── */
136
+ async exportPrefabs(project, options) {
137
+ for (const prefab of project.prefabs) {
138
+ const yaml = this.createPrefabYAML(prefab, project);
139
+ const path = `Assets/Prefabs/${this.sanitizeFileName(prefab.name)}.prefab`;
140
+ this.addTextFile(path, yaml);
141
+ this.addTextFile(`${path}.meta`, this.createMetaFile(prefab.id));
142
+ }
143
+ }
144
+ createPrefabYAML(prefab, project) {
145
+ var _a, _b, _c, _d, _e, _f, _g, _h;
146
+ const objects = [];
147
+ const rootId = this.nextFileId();
148
+ const transformId = this.nextFileId();
149
+ const gameObjectId = this.nextFileId();
150
+ // PrefabInstance header
151
+ objects.push({
152
+ fileID: rootId,
153
+ classID: 1001, // PrefabInstance
154
+ type: 'PrefabInstance',
155
+ properties: {
156
+ m_ObjectHideFlags: 0,
157
+ m_CorrespondingSourceObject: { fileID: 0 },
158
+ m_PrefabInstance: { fileID: 0 },
159
+ m_PrefabAsset: { fileID: 0 },
160
+ },
161
+ });
162
+ // Root GameObject
163
+ objects.push({
164
+ fileID: gameObjectId,
165
+ classID: 1, // GameObject
166
+ type: 'GameObject',
167
+ properties: {
168
+ m_ObjectHideFlags: 0,
169
+ m_Name: prefab.name,
170
+ m_IsActive: 1,
171
+ m_Layer: 0,
172
+ m_Tag: 'Untagged',
173
+ },
174
+ });
175
+ // Transform component
176
+ objects.push({
177
+ fileID: transformId,
178
+ classID: 4, // Transform
179
+ type: 'Transform',
180
+ properties: {
181
+ m_LocalRotation: { x: 0, y: 0, z: 0, w: 1 },
182
+ m_LocalPosition: {
183
+ x: (_b = (_a = prefab.entity.position) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0,
184
+ y: (_d = (_c = prefab.entity.position) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0,
185
+ z: 0,
186
+ },
187
+ m_LocalScale: { x: (_f = (_e = prefab.entity.scale) === null || _e === void 0 ? void 0 : _e.x) !== null && _f !== void 0 ? _f : 1, y: (_h = (_g = prefab.entity.scale) === null || _g === void 0 ? void 0 : _g.y) !== null && _h !== void 0 ? _h : 1, z: 1 },
188
+ m_Children: [],
189
+ m_Father: { fileID: 0 },
190
+ m_RootOrder: 0,
191
+ },
192
+ });
193
+ // Add components based on entity type
194
+ this.addEntityComponents(prefab.entity, objects, gameObjectId, project);
195
+ return this.serializeUnityYAML({ objects });
196
+ }
197
+ /* ── Scenes ─────────────────────────────────────────────────── */
198
+ async exportScenes(project, options) {
199
+ for (const scene of project.scenes) {
200
+ const yaml = this.createSceneYAML(scene, project);
201
+ const path = `Assets/Scenes/${this.sanitizeFileName(scene.name)}.unity`;
202
+ this.addTextFile(path, yaml);
203
+ this.addTextFile(`${path}.meta`, this.createMetaFile(scene.id));
204
+ }
205
+ }
206
+ createSceneYAML(scene, project) {
207
+ var _a;
208
+ const objects = [];
209
+ // Scene settings (OcclusionCullingSettings, RenderSettings, etc.)
210
+ this.addSceneSettings(objects, project);
211
+ // Create hierarchy of GameObjects
212
+ for (const entity of scene.entities) {
213
+ this.createGameObjectHierarchy(entity, objects, project, null);
214
+ }
215
+ // Handle tilemaps
216
+ for (const tilemap of (_a = scene.tilemaps) !== null && _a !== void 0 ? _a : []) {
217
+ this.createTilemapGameObject(tilemap, objects, project);
218
+ }
219
+ return this.serializeUnityYAML({ objects });
220
+ }
221
+ addSceneSettings(objects, project) {
222
+ // OcclusionCullingSettings
223
+ objects.push({
224
+ fileID: 1,
225
+ classID: 29,
226
+ type: 'OcclusionCullingSettings',
227
+ properties: {},
228
+ });
229
+ // RenderSettings
230
+ const bgColor = this.parseColor(project.settings.backgroundColor);
231
+ objects.push({
232
+ fileID: 2,
233
+ classID: 104,
234
+ type: 'RenderSettings',
235
+ properties: {
236
+ m_AmbientSkyColor: bgColor,
237
+ m_AmbientEquatorColor: bgColor,
238
+ m_AmbientGroundColor: bgColor,
239
+ },
240
+ });
241
+ // LightmapSettings
242
+ objects.push({
243
+ fileID: 3,
244
+ classID: 157,
245
+ type: 'LightmapSettings',
246
+ properties: {},
247
+ });
248
+ // NavMeshSettings
249
+ objects.push({
250
+ fileID: 4,
251
+ classID: 196,
252
+ type: 'NavMeshSettings',
253
+ properties: {},
254
+ });
255
+ }
256
+ createGameObjectHierarchy(entity, objects, project, parentTransformId) {
257
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
258
+ const gameObjectId = this.nextFileId();
259
+ const transformId = this.nextFileId();
260
+ // GameObject
261
+ objects.push({
262
+ fileID: gameObjectId,
263
+ classID: 1,
264
+ type: 'GameObject',
265
+ properties: {
266
+ m_ObjectHideFlags: 0,
267
+ m_Name: entity.name,
268
+ m_IsActive: 1,
269
+ m_Layer: 0,
270
+ m_Tag: 'Untagged',
271
+ },
272
+ });
273
+ // Process children for transform hierarchy
274
+ const childTransformIds = [];
275
+ if (entity.children) {
276
+ for (const child of entity.children) {
277
+ const childTransformId = this.createGameObjectHierarchy(child, objects, project, transformId);
278
+ childTransformIds.push(childTransformId);
279
+ }
280
+ }
281
+ // Transform component
282
+ const isRectTransform = entity.components.some((c) => c.type === 'ui-text' || c.type === 'ui-button' || c.type === 'ui-image');
283
+ objects.push({
284
+ fileID: transformId,
285
+ classID: isRectTransform ? 224 : 4, // RectTransform or Transform
286
+ type: isRectTransform ? 'RectTransform' : 'Transform',
287
+ properties: {
288
+ m_GameObject: { fileID: gameObjectId },
289
+ m_LocalRotation: {
290
+ x: 0,
291
+ y: 0,
292
+ z: Math.sin(((_a = entity.rotation) !== null && _a !== void 0 ? _a : 0) / 2),
293
+ w: Math.cos(((_b = entity.rotation) !== null && _b !== void 0 ? _b : 0) / 2),
294
+ },
295
+ m_LocalPosition: { x: (_d = (_c = entity.position) === null || _c === void 0 ? void 0 : _c.x) !== null && _d !== void 0 ? _d : 0, y: (_f = (_e = entity.position) === null || _e === void 0 ? void 0 : _e.y) !== null && _f !== void 0 ? _f : 0, z: 0 },
296
+ m_LocalScale: { x: (_h = (_g = entity.scale) === null || _g === void 0 ? void 0 : _g.x) !== null && _h !== void 0 ? _h : 1, y: (_k = (_j = entity.scale) === null || _j === void 0 ? void 0 : _j.y) !== null && _k !== void 0 ? _k : 1, z: 1 },
297
+ m_Children: childTransformIds.map((id) => ({ fileID: id })),
298
+ m_Father: parentTransformId ? { fileID: parentTransformId } : { fileID: 0 },
299
+ m_RootOrder: 0,
300
+ },
301
+ });
302
+ // Add other components
303
+ this.addEntityComponents(entity, objects, gameObjectId, project);
304
+ return transformId;
305
+ }
306
+ addEntityComponents(entity, objects, gameObjectId, project) {
307
+ var _a;
308
+ for (const component of entity.components) {
309
+ const props = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
310
+ switch (component.type) {
311
+ case 'sprite':
312
+ this.addSpriteRenderer(objects, gameObjectId, props);
313
+ break;
314
+ case 'rigidbody-2d':
315
+ this.addRigidbody2D(objects, gameObjectId, props);
316
+ break;
317
+ case 'box-collider-2d':
318
+ this.addBoxCollider2D(objects, gameObjectId, props);
319
+ break;
320
+ case 'circle-collider-2d':
321
+ this.addCircleCollider2D(objects, gameObjectId, props);
322
+ break;
323
+ case 'audio-source':
324
+ this.addAudioSource(objects, gameObjectId, props);
325
+ break;
326
+ case 'animator':
327
+ this.addAnimator(objects, gameObjectId, props);
328
+ break;
329
+ case 'ui-text':
330
+ this.addUIText(objects, gameObjectId, props);
331
+ break;
332
+ case 'ui-image':
333
+ this.addUIImage(objects, gameObjectId, props);
334
+ break;
335
+ case 'ui-button':
336
+ this.addUIButton(objects, gameObjectId, props);
337
+ break;
338
+ case 'particle-system':
339
+ this.addParticleSystem(objects, gameObjectId, props);
340
+ break;
341
+ default:
342
+ this.addWarning('UNKNOWN_COMPONENT', `Unknown component type "${component.type}" on entity "${entity.name}"`, 'Component will be skipped');
343
+ }
344
+ }
345
+ // Add script component if entity has one
346
+ if (entity.scriptId) {
347
+ this.addScriptComponent(objects, gameObjectId, entity.scriptId);
348
+ }
349
+ }
350
+ /* ── Component Generators ───────────────────────────────────── */
351
+ addSpriteRenderer(objects, gameObjectId, props) {
352
+ var _a, _b;
353
+ const componentId = this.nextFileId();
354
+ const spriteId = props.spriteId;
355
+ objects.push({
356
+ fileID: componentId,
357
+ classID: 212, // SpriteRenderer
358
+ type: 'SpriteRenderer',
359
+ properties: {
360
+ m_GameObject: { fileID: gameObjectId },
361
+ m_Enabled: 1,
362
+ m_Sprite: spriteId
363
+ ? { fileID: 21300000, guid: this.guidMap.get(spriteId) || '', type: 3 }
364
+ : { fileID: 0 },
365
+ m_Color: this.parseColor((_a = props.color) !== null && _a !== void 0 ? _a : '#ffffff'),
366
+ m_FlipX: props.flipX ? 1 : 0,
367
+ m_FlipY: props.flipY ? 1 : 0,
368
+ m_SortingLayerID: 0,
369
+ m_SortingOrder: (_b = props.sortingOrder) !== null && _b !== void 0 ? _b : 0,
370
+ },
371
+ });
372
+ }
373
+ addRigidbody2D(objects, gameObjectId, props) {
374
+ var _a, _b, _c, _d;
375
+ const componentId = this.nextFileId();
376
+ objects.push({
377
+ fileID: componentId,
378
+ classID: 50, // Rigidbody2D
379
+ type: 'Rigidbody2D',
380
+ properties: {
381
+ m_GameObject: { fileID: gameObjectId },
382
+ m_BodyType: props.type === 'static' ? 2 : props.type === 'kinematic' ? 1 : 0,
383
+ m_Mass: (_a = props.mass) !== null && _a !== void 0 ? _a : 1,
384
+ m_LinearDrag: (_b = props.linearDrag) !== null && _b !== void 0 ? _b : 0,
385
+ m_AngularDrag: (_c = props.angularDrag) !== null && _c !== void 0 ? _c : 0.05,
386
+ m_GravityScale: (_d = props.gravityScale) !== null && _d !== void 0 ? _d : 1,
387
+ m_FreezeRotation: props.freezeRotation ? 1 : 0,
388
+ m_Interpolate: 0,
389
+ m_SleepingMode: 1,
390
+ m_CollisionDetection: 0,
391
+ },
392
+ });
393
+ }
394
+ addBoxCollider2D(objects, gameObjectId, props) {
395
+ var _a, _b, _c, _d;
396
+ const componentId = this.nextFileId();
397
+ objects.push({
398
+ fileID: componentId,
399
+ classID: 61, // BoxCollider2D
400
+ type: 'BoxCollider2D',
401
+ properties: {
402
+ m_GameObject: { fileID: gameObjectId },
403
+ m_IsTrigger: props.isTrigger ? 1 : 0,
404
+ m_Size: { x: (_a = props.width) !== null && _a !== void 0 ? _a : 1, y: (_b = props.height) !== null && _b !== void 0 ? _b : 1 },
405
+ m_Offset: { x: (_c = props.offsetX) !== null && _c !== void 0 ? _c : 0, y: (_d = props.offsetY) !== null && _d !== void 0 ? _d : 0 },
406
+ },
407
+ });
408
+ }
409
+ addCircleCollider2D(objects, gameObjectId, props) {
410
+ var _a, _b, _c;
411
+ const componentId = this.nextFileId();
412
+ objects.push({
413
+ fileID: componentId,
414
+ classID: 58, // CircleCollider2D
415
+ type: 'CircleCollider2D',
416
+ properties: {
417
+ m_GameObject: { fileID: gameObjectId },
418
+ m_IsTrigger: props.isTrigger ? 1 : 0,
419
+ m_Radius: (_a = props.radius) !== null && _a !== void 0 ? _a : 0.5,
420
+ m_Offset: { x: (_b = props.offsetX) !== null && _b !== void 0 ? _b : 0, y: (_c = props.offsetY) !== null && _c !== void 0 ? _c : 0 },
421
+ },
422
+ });
423
+ }
424
+ addAudioSource(objects, gameObjectId, props) {
425
+ var _a, _b, _c;
426
+ const componentId = this.nextFileId();
427
+ const audioClipId = props.clipId;
428
+ objects.push({
429
+ fileID: componentId,
430
+ classID: 82, // AudioSource
431
+ type: 'AudioSource',
432
+ properties: {
433
+ m_GameObject: { fileID: gameObjectId },
434
+ m_Enabled: 1,
435
+ m_AudioClip: audioClipId
436
+ ? { fileID: 8300000, guid: this.guidMap.get(audioClipId) || '', type: 3 }
437
+ : { fileID: 0 },
438
+ m_PlayOnAwake: props.playOnAwake ? 1 : 0,
439
+ m_Loop: props.loop ? 1 : 0,
440
+ m_Volume: (_a = props.volume) !== null && _a !== void 0 ? _a : 1,
441
+ m_Pitch: (_b = props.pitch) !== null && _b !== void 0 ? _b : 1,
442
+ m_SpatialBlend: (_c = props.spatialBlend) !== null && _c !== void 0 ? _c : 0,
443
+ },
444
+ });
445
+ }
446
+ addAnimator(objects, gameObjectId, props) {
447
+ var _a;
448
+ const componentId = this.nextFileId();
449
+ const controllerId = props.controllerId;
450
+ objects.push({
451
+ fileID: componentId,
452
+ classID: 95, // Animator
453
+ type: 'Animator',
454
+ properties: {
455
+ m_GameObject: { fileID: gameObjectId },
456
+ m_Enabled: 1,
457
+ m_Controller: controllerId
458
+ ? { fileID: 9100000, guid: this.guidMap.get(controllerId) || '', type: 2 }
459
+ : { fileID: 0 },
460
+ m_ApplyRootMotion: props.applyRootMotion ? 1 : 0,
461
+ m_UpdateMode: 0,
462
+ m_CullingMode: (_a = props.cullingMode) !== null && _a !== void 0 ? _a : 0,
463
+ },
464
+ });
465
+ }
466
+ addUIText(objects, gameObjectId, props) {
467
+ var _a, _b, _c;
468
+ const componentId = this.nextFileId();
469
+ // Using TextMeshProUGUI instead of legacy Text
470
+ objects.push({
471
+ fileID: componentId,
472
+ classID: 114, // MonoBehaviour (TextMeshProUGUI)
473
+ type: 'MonoBehaviour',
474
+ properties: {
475
+ m_GameObject: { fileID: gameObjectId },
476
+ m_Enabled: 1,
477
+ m_Script: { fileID: 11500000, guid: 'f4688fdb7df04437aeb418b961361dc5', type: 3 }, // TMP_Text
478
+ m_Text: (_a = props.text) !== null && _a !== void 0 ? _a : '',
479
+ m_FontSize: (_b = props.fontSize) !== null && _b !== void 0 ? _b : 24,
480
+ m_FontColor: this.parseColor((_c = props.color) !== null && _c !== void 0 ? _c : '#ffffff'),
481
+ m_TextAlignment: this.getTextAlignment(props.alignment),
482
+ },
483
+ });
484
+ }
485
+ addUIImage(objects, gameObjectId, props) {
486
+ var _a, _b;
487
+ const componentId = this.nextFileId();
488
+ const spriteId = props.spriteId;
489
+ objects.push({
490
+ fileID: componentId,
491
+ classID: 114, // Image
492
+ type: 'Image',
493
+ properties: {
494
+ m_GameObject: { fileID: gameObjectId },
495
+ m_Enabled: 1,
496
+ m_Sprite: spriteId
497
+ ? { fileID: 21300000, guid: this.guidMap.get(spriteId) || '', type: 3 }
498
+ : { fileID: 0 },
499
+ m_Color: this.parseColor((_a = props.color) !== null && _a !== void 0 ? _a : '#ffffff'),
500
+ m_RaycastTarget: props.raycastTarget !== false ? 1 : 0,
501
+ m_Type: (_b = props.imageType) !== null && _b !== void 0 ? _b : 0, // Simple
502
+ m_FillCenter: 1,
503
+ m_PreserveAspect: props.preserveAspect ? 1 : 0,
504
+ },
505
+ });
506
+ }
507
+ addUIButton(objects, gameObjectId, props) {
508
+ const componentId = this.nextFileId();
509
+ objects.push({
510
+ fileID: componentId,
511
+ classID: 114, // Button
512
+ type: 'Button',
513
+ properties: {
514
+ m_GameObject: { fileID: gameObjectId },
515
+ m_Enabled: 1,
516
+ m_Interactable: props.interactable !== false ? 1 : 0,
517
+ m_TargetGraphic: { fileID: 0 },
518
+ m_OnClick: { m_PersistentCalls: { m_Calls: [] } },
519
+ },
520
+ });
521
+ }
522
+ addParticleSystem(objects, gameObjectId, props) {
523
+ var _a, _b, _c, _d, _e, _f;
524
+ const componentId = this.nextFileId();
525
+ objects.push({
526
+ fileID: componentId,
527
+ classID: 198, // ParticleSystem
528
+ type: 'ParticleSystem',
529
+ properties: {
530
+ m_GameObject: { fileID: gameObjectId },
531
+ m_Duration: (_a = props.duration) !== null && _a !== void 0 ? _a : 5,
532
+ m_Looping: props.looping ? 1 : 0,
533
+ m_Prewarm: props.prewarm ? 1 : 0,
534
+ m_StartDelay: { value: (_b = props.startDelay) !== null && _b !== void 0 ? _b : 0 },
535
+ m_PlayOnAwake: props.playOnAwake !== false ? 1 : 0,
536
+ m_StartSpeed: { value: (_c = props.startSpeed) !== null && _c !== void 0 ? _c : 5 },
537
+ m_StartSize: { value: (_d = props.startSize) !== null && _d !== void 0 ? _d : 1 },
538
+ m_StartColor: this.parseColor((_e = props.startColor) !== null && _e !== void 0 ? _e : '#ffffff'),
539
+ m_MaxParticles: (_f = props.maxParticles) !== null && _f !== void 0 ? _f : 1000,
540
+ },
541
+ });
542
+ }
543
+ addScriptComponent(objects, gameObjectId, scriptId) {
544
+ const componentId = this.nextFileId();
545
+ const scriptGuid = this.guidMap.get(scriptId);
546
+ if (!scriptGuid) {
547
+ this.addWarning('SCRIPT_NOT_FOUND', `Script "${scriptId}" not found for entity`);
548
+ return;
549
+ }
550
+ objects.push({
551
+ fileID: componentId,
552
+ classID: 114, // MonoBehaviour
553
+ type: 'MonoBehaviour',
554
+ properties: {
555
+ m_GameObject: { fileID: gameObjectId },
556
+ m_Enabled: 1,
557
+ m_Script: { fileID: 11500000, guid: scriptGuid, type: 3 },
558
+ },
559
+ });
560
+ }
561
+ /* ── Tilemaps ───────────────────────────────────────────────── */
562
+ createTilemapGameObject(tilemap, objects, project) {
563
+ const gameObjectId = this.nextFileId();
564
+ const transformId = this.nextFileId();
565
+ const gridId = this.nextFileId();
566
+ // Grid GameObject (parent)
567
+ objects.push({
568
+ fileID: gameObjectId,
569
+ classID: 1,
570
+ type: 'GameObject',
571
+ properties: {
572
+ m_ObjectHideFlags: 0,
573
+ m_Name: tilemap.name,
574
+ m_IsActive: 1,
575
+ m_Layer: 0,
576
+ m_Tag: 'Untagged',
577
+ },
578
+ });
579
+ // Grid component
580
+ objects.push({
581
+ fileID: gridId,
582
+ classID: 156, // Grid
583
+ type: 'Grid',
584
+ properties: {
585
+ m_GameObject: { fileID: gameObjectId },
586
+ m_CellSize: { x: tilemap.tileSize, y: tilemap.tileSize, z: 0 },
587
+ m_CellGap: { x: 0, y: 0, z: 0 },
588
+ m_CellLayout: 0, // Rectangle
589
+ m_CellSwizzle: 0, // XYZ
590
+ },
591
+ });
592
+ // Transform for grid
593
+ objects.push({
594
+ fileID: transformId,
595
+ classID: 4,
596
+ type: 'Transform',
597
+ properties: {
598
+ m_GameObject: { fileID: gameObjectId },
599
+ m_LocalRotation: { x: 0, y: 0, z: 0, w: 1 },
600
+ m_LocalPosition: { x: 0, y: 0, z: 0 },
601
+ m_LocalScale: { x: 1, y: 1, z: 1 },
602
+ m_Children: [],
603
+ m_Father: { fileID: 0 },
604
+ m_RootOrder: 0,
605
+ },
606
+ });
607
+ // Create Tilemap layer objects
608
+ for (let i = 0; i < tilemap.layers.length; i++) {
609
+ this.createTilemapLayer(tilemap.layers[i], tilemap, objects, transformId, project);
610
+ }
611
+ }
612
+ createTilemapLayer(layer, tilemap, objects, parentTransformId, project) {
613
+ const gameObjectId = this.nextFileId();
614
+ const transformId = this.nextFileId();
615
+ const tilemapId = this.nextFileId();
616
+ const rendererId = this.nextFileId();
617
+ // Layer GameObject
618
+ objects.push({
619
+ fileID: gameObjectId,
620
+ classID: 1,
621
+ type: 'GameObject',
622
+ properties: {
623
+ m_Name: layer.name,
624
+ m_IsActive: layer.visible ? 1 : 0,
625
+ },
626
+ });
627
+ // Transform
628
+ objects.push({
629
+ fileID: transformId,
630
+ classID: 4,
631
+ type: 'Transform',
632
+ properties: {
633
+ m_GameObject: { fileID: gameObjectId },
634
+ m_Father: { fileID: parentTransformId },
635
+ },
636
+ });
637
+ // Tilemap component
638
+ objects.push({
639
+ fileID: tilemapId,
640
+ classID: 156, // Tilemap
641
+ type: 'Tilemap',
642
+ properties: {
643
+ m_GameObject: { fileID: gameObjectId },
644
+ m_Size: { x: tilemap.width, y: tilemap.height, z: 1 },
645
+ m_TileAssets: [], // Would reference TileBase assets
646
+ m_TileMatrixArray: [],
647
+ m_TileColorArray: [],
648
+ },
649
+ });
650
+ // TilemapRenderer
651
+ objects.push({
652
+ fileID: rendererId,
653
+ classID: 156, // TilemapRenderer
654
+ type: 'TilemapRenderer',
655
+ properties: {
656
+ m_GameObject: { fileID: gameObjectId },
657
+ m_Enabled: 1,
658
+ m_SortingLayerID: 0,
659
+ m_SortingOrder: 0,
660
+ m_ChunkSize: { x: 32, y: 32, z: 1 },
661
+ },
662
+ });
663
+ }
664
+ /* ── Materials ──────────────────────────────────────────────── */
665
+ async exportMaterials(project, options, unity) {
666
+ const materials = project.assets.filter((a) => a.type === 'material');
667
+ for (const material of materials) {
668
+ const matYaml = this.createMaterialYAML(material, unity === null || unity === void 0 ? void 0 : unity.useURP);
669
+ const path = `Assets/Materials/${this.sanitizeFileName(material.name)}.mat`;
670
+ this.addTextFile(path, matYaml);
671
+ this.addTextFile(`${path}.meta`, this.createMetaFile(material.id));
672
+ }
673
+ }
674
+ createMaterialYAML(material, useURP) {
675
+ var _a, _b;
676
+ const shaderGuid = useURP
677
+ ? '933532a4fcc9baf4fa0491de14d08ed7' // Universal Render Pipeline/Lit
678
+ : '0000000000000000f000000000000000'; // Standard
679
+ const color = (_b = (_a = material.metadata) === null || _a === void 0 ? void 0 : _a.color) !== null && _b !== void 0 ? _b : '#ffffff';
680
+ const rgba = this.parseColor(color);
681
+ return `%YAML 1.1
682
+ %TAG !u! tag:unity3d.com,2011:
683
+ --- !u!21 &2100000
684
+ Material:
685
+ serializedVersion: 8
686
+ m_ObjectHideFlags: 0
687
+ m_CorrespondingSourceObject: {fileID: 0}
688
+ m_PrefabInstance: {fileID: 0}
689
+ m_PrefabAsset: {fileID: 0}
690
+ m_Name: ${material.name}
691
+ m_Shader: {fileID: 46, guid: ${shaderGuid}, type: 2}
692
+ m_Parent: {fileID: 0}
693
+ m_Color: ${JSON.stringify(rgba)}`;
694
+ }
695
+ /* ── Assets ─────────────────────────────────────────────────── */
696
+ async exportAssets(project, options) {
697
+ for (const asset of project.assets) {
698
+ switch (asset.type) {
699
+ case 'sprite':
700
+ this.exportSpriteAsset(asset);
701
+ break;
702
+ case 'audio':
703
+ this.exportAudioAsset(asset);
704
+ break;
705
+ case 'font':
706
+ this.exportFontAsset(asset);
707
+ break;
708
+ case 'tileset':
709
+ this.exportTilesetAsset(asset);
710
+ break;
711
+ case 'animation':
712
+ this.exportAnimationAsset(asset);
713
+ break;
714
+ }
715
+ }
716
+ }
717
+ exportSpriteAsset(asset) {
718
+ // Create .meta file for sprite import settings
719
+ const meta = `fileFormatVersion: 2
720
+ guid: ${this.guidMap.get(asset.id)}
721
+ TextureImporter:
722
+ internalIDToNameTable: []
723
+ externalObjects: {}
724
+ serializedVersion: 12
725
+ mipmaps:
726
+ mipMapMode: 0
727
+ enableMipMap: 0
728
+ bumpmap:
729
+ convertToNormalMap: 0
730
+ isReadable: 0
731
+ streamingMipmaps: 0
732
+ spriteMode: 1
733
+ spriteExtrude: 1
734
+ spriteMeshType: 1
735
+ alignment: 0
736
+ spritePivot: {x: 0.5, y: 0.5}
737
+ spritePixelsToUnits: 100
738
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
739
+ spriteGenerateFallbackPhysicsShape: 1
740
+ alphaUsage: 1
741
+ alphaIsTransparency: 1
742
+ spriteTessellationDetail: -1
743
+ textureType: 8
744
+ textureShape: 1
745
+ filterMode: 0
746
+ maxTextureSize: 2048
747
+ textureCompression: 1`;
748
+ const path = `Assets/Sprites/${this.sanitizeFileName(asset.name)}`;
749
+ // Note: actual image file would be copied from source
750
+ this.addTextFile(`${path}.meta`, meta);
751
+ }
752
+ exportAudioAsset(asset) {
753
+ const meta = `fileFormatVersion: 2
754
+ guid: ${this.guidMap.get(asset.id)}
755
+ AudioImporter:
756
+ externalObjects: {}
757
+ serializedVersion: 7
758
+ defaultSettings:
759
+ loadType: 0
760
+ sampleRateSetting: 0
761
+ sampleRateOverride: 44100
762
+ compressionFormat: 1
763
+ quality: 1
764
+ conversionMode: 0
765
+ forceToMono: 0
766
+ normalize: 1
767
+ preloadAudioData: 1
768
+ loadInBackground: 0
769
+ ambisonic: 0
770
+ 3D: 1`;
771
+ const path = `Assets/Audio/${this.sanitizeFileName(asset.name)}`;
772
+ this.addTextFile(`${path}.meta`, meta);
773
+ }
774
+ exportFontAsset(asset) {
775
+ const meta = `fileFormatVersion: 2
776
+ guid: ${this.guidMap.get(asset.id)}
777
+ TrueTypeFontImporter:
778
+ externalObjects: {}
779
+ serializedVersion: 4
780
+ fontSize: 16
781
+ forceTextureCase: -2
782
+ characterSpacing: 0
783
+ characterPadding: 1
784
+ includeFontData: 1
785
+ fontNames:
786
+ - ${asset.name}
787
+ fallbackFontReferences: []
788
+ customCharacters:
789
+ fontRenderingMode: 0
790
+ ascentCalculationMode: 1`;
791
+ const path = `Assets/Fonts/${this.sanitizeFileName(asset.name)}`;
792
+ this.addTextFile(`${path}.meta`, meta);
793
+ }
794
+ exportTilesetAsset(asset) {
795
+ // Export as Tileset Palette
796
+ const palette = `%YAML 1.1
797
+ %TAG !u! tag:unity3d.com,2011:
798
+ --- !u!114 &11400000
799
+ MonoBehaviour:
800
+ m_ObjectHideFlags: 0
801
+ m_Name: ${asset.name}
802
+ m_EditorClassIdentifier:
803
+ m_Tileset: {fileID: 0}`;
804
+ const path = `Assets/Tilesets/${this.sanitizeFileName(asset.name)}.asset`;
805
+ this.addTextFile(path, palette);
806
+ this.addTextFile(`${path}.meta`, this.createMetaFile(asset.id));
807
+ }
808
+ exportAnimationAsset(asset) {
809
+ const meta = asset.metadata || {};
810
+ const frameRate = meta.frameRate || 12;
811
+ // Basic Animation Clip
812
+ const clip = `%YAML 1.1
813
+ %TAG !u! tag:unity3d.com,2011:
814
+ --- !u!74 &7400000
815
+ AnimationClip:
816
+ m_ObjectHideFlags: 0
817
+ m_Name: ${asset.name}
818
+ serializedVersion: 7
819
+ m_Legacy: 0
820
+ m_Compressed: 0
821
+ m_UseHighQualityCurve: 1
822
+ m_RotationCurves: []
823
+ m_CompressedRotationCurves: []
824
+ m_EulerCurves: []
825
+ m_PositionCurves: []
826
+ m_ScaleCurves: []
827
+ m_FloatCurves: []
828
+ m_PPtrCurves: []
829
+ m_SampleRate: ${frameRate}
830
+ m_WrapMode: 0
831
+ m_Bounds:
832
+ m_Center: {x: 0, y: 0, z: 0}
833
+ m_Extent: {x: 0, y: 0, z: 0}
834
+ m_ClipBindingConstant:
835
+ genericBindings: []
836
+ pptrCurveMapping: []
837
+ m_Events: []`;
838
+ const path = `Assets/Animations/${this.sanitizeFileName(asset.name)}.anim`;
839
+ this.addTextFile(path, clip);
840
+ this.addTextFile(`${path}.meta`, this.createMetaFile(asset.id));
841
+ }
842
+ /* ── Assembly Definition ────────────────────────────────────── */
843
+ exportAssemblyDefinition(projectName, namespace) {
844
+ const asmdef = {
845
+ name: namespace,
846
+ rootNamespace: namespace,
847
+ references: ['Unity.TextMeshPro', 'Unity.InputSystem'],
848
+ includePlatforms: [],
849
+ excludePlatforms: [],
850
+ allowUnsafeCode: false,
851
+ overrideReferences: false,
852
+ precompiledReferences: [],
853
+ autoReferenced: true,
854
+ defineConstraints: [],
855
+ versionDefines: [],
856
+ noEngineReferences: false,
857
+ };
858
+ const path = `Assets/Scripts/${namespace}.asmdef`;
859
+ this.addTextFile(path, JSON.stringify(asmdef, null, 2));
860
+ this.addTextFile(`${path}.meta`, this.createMetaFile('asmdef'));
861
+ }
862
+ /* ── Runtime Bridge ─────────────────────────────────────────── */
863
+ exportRuntimeBridge(namespace) {
864
+ const bridge = `using UnityEngine;
865
+ using System;
866
+ using System.Collections;
867
+ using System.Collections.Generic;
868
+
869
+ namespace ${namespace}.Runtime
870
+ {
871
+ /// <summary>
872
+ /// Bridge between Nice2Dev runtime and Unity systems.
873
+ /// Auto-generated by Nice2Dev export.
874
+ /// </summary>
875
+ public static class Nice2DevBridge
876
+ {
877
+ private static Dictionary<string, GameObject> _entityMap = new();
878
+ private static Dictionary<string, Action<object>> _eventHandlers = new();
879
+
880
+ /// <summary>
881
+ /// Register an entity for cross-reference.
882
+ /// </summary>
883
+ public static void RegisterEntity(string id, GameObject obj)
884
+ {
885
+ _entityMap[id] = obj;
886
+ }
887
+
888
+ /// <summary>
889
+ /// Get entity by ID.
890
+ /// </summary>
891
+ public static GameObject GetEntity(string id)
892
+ {
893
+ return _entityMap.TryGetValue(id, out var obj) ? obj : null;
894
+ }
895
+
896
+ /// <summary>
897
+ /// Emit a custom event.
898
+ /// </summary>
899
+ public static void EmitEvent(string eventName, object data = null)
900
+ {
901
+ if (_eventHandlers.TryGetValue(eventName, out var handler))
902
+ {
903
+ handler?.Invoke(data);
904
+ }
905
+ }
906
+
907
+ /// <summary>
908
+ /// Subscribe to a custom event.
909
+ /// </summary>
910
+ public static void OnEvent(string eventName, Action<object> handler)
911
+ {
912
+ if (!_eventHandlers.ContainsKey(eventName))
913
+ {
914
+ _eventHandlers[eventName] = handler;
915
+ }
916
+ else
917
+ {
918
+ _eventHandlers[eventName] += handler;
919
+ }
920
+ }
921
+
922
+ /// <summary>
923
+ /// Unsubscribe from a custom event.
924
+ /// </summary>
925
+ public static void OffEvent(string eventName, Action<object> handler)
926
+ {
927
+ if (_eventHandlers.ContainsKey(eventName))
928
+ {
929
+ _eventHandlers[eventName] -= handler;
930
+ }
931
+ }
932
+
933
+ /// <summary>
934
+ /// Wait for seconds (coroutine helper).
935
+ /// </summary>
936
+ public static IEnumerator Wait(float seconds)
937
+ {
938
+ yield return new WaitForSeconds(seconds);
939
+ }
940
+
941
+ /// <summary>
942
+ /// Spawn a prefab at position.
943
+ /// </summary>
944
+ public static GameObject Spawn(GameObject prefab, Vector2 position)
945
+ {
946
+ return UnityEngine.Object.Instantiate(prefab, new Vector3(position.x, position.y, 0), Quaternion.identity);
947
+ }
948
+
949
+ /// <summary>
950
+ /// Destroy an entity.
951
+ /// </summary>
952
+ public static void Destroy(GameObject obj, float delay = 0f)
953
+ {
954
+ if (delay > 0)
955
+ {
956
+ UnityEngine.Object.Destroy(obj, delay);
957
+ }
958
+ else
959
+ {
960
+ UnityEngine.Object.Destroy(obj);
961
+ }
962
+ }
963
+
964
+ /// <summary>
965
+ /// Play audio clip.
966
+ /// </summary>
967
+ public static void PlaySound(AudioClip clip, float volume = 1f)
968
+ {
969
+ AudioSource.PlayClipAtPoint(clip, Camera.main.transform.position, volume);
970
+ }
971
+
972
+ /// <summary>
973
+ /// Get input axis.
974
+ /// </summary>
975
+ public static float GetAxis(string axisName)
976
+ {
977
+ return Input.GetAxis(axisName);
978
+ }
979
+
980
+ /// <summary>
981
+ /// Check if key is pressed.
982
+ /// </summary>
983
+ public static bool IsKeyPressed(KeyCode key)
984
+ {
985
+ return Input.GetKey(key);
986
+ }
987
+
988
+ /// <summary>
989
+ /// Check if key was just pressed.
990
+ /// </summary>
991
+ public static bool IsKeyJustPressed(KeyCode key)
992
+ {
993
+ return Input.GetKeyDown(key);
994
+ }
995
+
996
+ /// <summary>
997
+ /// Get mouse position in world space.
998
+ /// </summary>
999
+ public static Vector2 GetMouseWorldPosition()
1000
+ {
1001
+ if (Camera.main == null) return Vector2.zero;
1002
+ return Camera.main.ScreenToWorldPoint(Input.mousePosition);
1003
+ }
1004
+
1005
+ /// <summary>
1006
+ /// Linear interpolation.
1007
+ /// </summary>
1008
+ public static float Lerp(float a, float b, float t)
1009
+ {
1010
+ return Mathf.Lerp(a, b, t);
1011
+ }
1012
+
1013
+ /// <summary>
1014
+ /// Random float between min and max.
1015
+ /// </summary>
1016
+ public static float Random(float min, float max)
1017
+ {
1018
+ return UnityEngine.Random.Range(min, max);
1019
+ }
1020
+
1021
+ /// <summary>
1022
+ /// Random int between min and max (exclusive).
1023
+ /// </summary>
1024
+ public static int RandomInt(int min, int max)
1025
+ {
1026
+ return UnityEngine.Random.Range(min, max);
1027
+ }
1028
+ }
1029
+ }`;
1030
+ const path = `Assets/Scripts/Runtime/Nice2DevBridge.cs`;
1031
+ this.addTextFile(path, bridge);
1032
+ this.addTextFile(`${path}.meta`, this.createScriptMetaFile('nice2dev-bridge'));
1033
+ }
1034
+ /* ── Package Manifest ───────────────────────────────────────── */
1035
+ exportPackageManifest(project) {
1036
+ // Create .unitypackage manifest
1037
+ const manifest = {
1038
+ packageName: project.name,
1039
+ version: project.version,
1040
+ exportedAt: new Date().toISOString(),
1041
+ files: this.files.map((f) => f.path),
1042
+ };
1043
+ this.addTextFile('package.json', JSON.stringify(manifest, null, 2));
1044
+ }
1045
+ /* ── YAML Serialization ─────────────────────────────────────── */
1046
+ serializeUnityYAML(yaml) {
1047
+ let output = `%YAML 1.1
1048
+ %TAG !u! tag:unity3d.com,2011:
1049
+ `;
1050
+ for (const obj of yaml.objects) {
1051
+ output += `--- !u!${obj.classID} &${obj.fileID}\n`;
1052
+ output += `${obj.type}:\n`;
1053
+ output += this.serializeYAMLObject(obj.properties, 1);
1054
+ }
1055
+ return output;
1056
+ }
1057
+ serializeYAMLObject(obj, indent) {
1058
+ const spaces = ' '.repeat(indent);
1059
+ let output = '';
1060
+ for (const [key, value] of Object.entries(obj)) {
1061
+ if (value === null || value === undefined) {
1062
+ output += `${spaces}${key}: \n`;
1063
+ }
1064
+ else if (typeof value === 'object' && !Array.isArray(value)) {
1065
+ const inner = value;
1066
+ if (Object.keys(inner).length === 0) {
1067
+ output += `${spaces}${key}: {}\n`;
1068
+ }
1069
+ else if ('fileID' in inner) {
1070
+ output += `${spaces}${key}: {fileID: ${inner.fileID}${inner.guid ? `, guid: ${inner.guid}` : ''}${inner.type ? `, type: ${inner.type}` : ''}}\n`;
1071
+ }
1072
+ else if ('x' in inner && 'y' in inner) {
1073
+ const z = 'z' in inner ? `, z: ${inner.z}` : '';
1074
+ const w = 'w' in inner ? `, w: ${inner.w}` : '';
1075
+ output += `${spaces}${key}: {x: ${inner.x}, y: ${inner.y}${z}${w}}\n`;
1076
+ }
1077
+ else if ('r' in inner && 'g' in inner) {
1078
+ output += `${spaces}${key}: {r: ${inner.r}, g: ${inner.g}, b: ${inner.b}, a: ${inner.a}}\n`;
1079
+ }
1080
+ else {
1081
+ output += `${spaces}${key}:\n`;
1082
+ output += this.serializeYAMLObject(inner, indent + 1);
1083
+ }
1084
+ }
1085
+ else if (Array.isArray(value)) {
1086
+ if (value.length === 0) {
1087
+ output += `${spaces}${key}: []\n`;
1088
+ }
1089
+ else {
1090
+ output += `${spaces}${key}:\n`;
1091
+ for (const item of value) {
1092
+ if (typeof item === 'object' && item !== null) {
1093
+ output += `${spaces}- `;
1094
+ const itemStr = this.serializeYAMLObject(item, indent + 1);
1095
+ output += itemStr.trim().replace(/\n/g, `\n${spaces} `) + '\n';
1096
+ }
1097
+ else {
1098
+ output += `${spaces}- ${item}\n`;
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ else {
1104
+ output += `${spaces}${key}: ${value}\n`;
1105
+ }
1106
+ }
1107
+ return output;
1108
+ }
1109
+ /* ── Utility Methods ────────────────────────────────────────── */
1110
+ generateGuids(project) {
1111
+ for (const script of project.scripts) {
1112
+ this.guidMap.set(script.id, this.generateGUID());
1113
+ }
1114
+ for (const asset of project.assets) {
1115
+ this.guidMap.set(asset.id, this.generateGUID());
1116
+ }
1117
+ for (const prefab of project.prefabs) {
1118
+ this.guidMap.set(prefab.id, this.generateGUID());
1119
+ }
1120
+ for (const scene of project.scenes) {
1121
+ this.guidMap.set(scene.id, this.generateGUID());
1122
+ }
1123
+ }
1124
+ generateGUID() {
1125
+ // Unity uses 32-character hex GUIDs
1126
+ return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));
1127
+ }
1128
+ nextFileId() {
1129
+ return this.fileIdCounter++;
1130
+ }
1131
+ createMetaFile(id) {
1132
+ const guid = this.guidMap.get(id) || this.generateGUID();
1133
+ return `fileFormatVersion: 2
1134
+ guid: ${guid}
1135
+ NativeFormatImporter:
1136
+ externalObjects: {}
1137
+ mainObjectFileID: 0`;
1138
+ }
1139
+ createScriptMetaFile(scriptId) {
1140
+ const guid = this.guidMap.get(scriptId) || this.generateGUID();
1141
+ return `fileFormatVersion: 2
1142
+ guid: ${guid}
1143
+ MonoImporter:
1144
+ externalObjects: {}
1145
+ serializedVersion: 2
1146
+ defaultReferences: []
1147
+ executionOrder: 0
1148
+ icon: {instanceID: 0}`;
1149
+ }
1150
+ parseColor(hex) {
1151
+ const clean = hex.replace('#', '');
1152
+ const r = parseInt(clean.slice(0, 2), 16) / 255;
1153
+ const g = parseInt(clean.slice(2, 4), 16) / 255;
1154
+ const b = parseInt(clean.slice(4, 6), 16) / 255;
1155
+ const a = clean.length > 6 ? parseInt(clean.slice(6, 8), 16) / 255 : 1;
1156
+ return { r, g, b, a };
1157
+ }
1158
+ sanitizeFileName(name) {
1159
+ return name.replace(/[^a-zA-Z0-9_-]/g, '_');
1160
+ }
1161
+ toValidNamespace(name) {
1162
+ return name.replace(/[^a-zA-Z0-9]/g, '').replace(/^[0-9]/, '_$&');
1163
+ }
1164
+ getTextAlignment(alignment) {
1165
+ switch (alignment) {
1166
+ case 'left':
1167
+ return 257;
1168
+ case 'center':
1169
+ return 258;
1170
+ case 'right':
1171
+ return 260;
1172
+ case 'top-left':
1173
+ return 257;
1174
+ case 'top-center':
1175
+ return 258;
1176
+ case 'top-right':
1177
+ return 260;
1178
+ case 'bottom-left':
1179
+ return 4097;
1180
+ case 'bottom-center':
1181
+ return 4098;
1182
+ case 'bottom-right':
1183
+ return 4100;
1184
+ default:
1185
+ return 258; // center
1186
+ }
1187
+ }
1188
+ }
1189
+
1190
+ export { UnityExporter };
1191
+ //# sourceMappingURL=UnityExporter.js.map