@gnsx/genesys.sdk 4.2.9
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 +60 -0
- package/dist/src/asset-pack/eslint.config.js +58 -0
- package/dist/src/asset-pack/scripts/post-install.js +64 -0
- package/dist/src/asset-pack/src/index.js +1 -0
- package/dist/src/core/cli.js +303 -0
- package/dist/src/core/common.js +325 -0
- package/dist/src/core/index.js +6 -0
- package/dist/src/core/tools/build-project.js +456 -0
- package/dist/src/core/tools/index.js +2 -0
- package/dist/src/core/tools/new-asset-pack.js +153 -0
- package/dist/src/core/tools/new-project.js +293 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/dependencies.js +84 -0
- package/dist/src/electron/IpcSerializableError.js +38 -0
- package/dist/src/electron/api.js +7 -0
- package/dist/src/electron/backend/actions.js +56 -0
- package/dist/src/electron/backend/handler.js +452 -0
- package/dist/src/electron/backend/logging.js +41 -0
- package/dist/src/electron/backend/main.js +369 -0
- package/dist/src/electron/backend/menu.js +196 -0
- package/dist/src/electron/backend/state.js +201 -0
- package/dist/src/electron/backend/telemetry.js +9 -0
- package/dist/src/electron/backend/tools/const.js +9 -0
- package/dist/src/electron/backend/tools/file-server.js +383 -0
- package/dist/src/electron/backend/tools/open-project.js +249 -0
- package/dist/src/electron/backend/window.js +161 -0
- package/dist/src/templates/eslint.config.js +58 -0
- package/dist/src/templates/scripts/genesys/build-project.js +42 -0
- package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
- package/dist/src/templates/scripts/genesys/common.js +36 -0
- package/dist/src/templates/scripts/genesys/const.js +9 -0
- package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
- package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
- package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
- package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
- package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
- package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
- package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
- package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
- package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
- package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
- package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
- package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
- package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
- package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
- package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
- package/dist/src/templates/scripts/genesys/migrate-scenes-and-prefabs.js +252 -0
- package/dist/src/templates/scripts/genesys/misc.js +32 -0
- package/dist/src/templates/scripts/genesys/mock.js +5 -0
- package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
- package/dist/src/templates/scripts/genesys/post-install.js +33 -0
- package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
- package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
- package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
- package/dist/src/templates/src/index.js +20 -0
- package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
- package/dist/src/templates/src/templates/firstPerson/src/player.js +55 -0
- package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/fps/src/game.js +30 -0
- package/dist/src/templates/src/templates/fps/src/player.js +60 -0
- package/dist/src/templates/src/templates/fps/src/weapon.js +54 -0
- package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
- package/dist/src/templates/src/templates/freeCamera/src/player.js +38 -0
- package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
- package/dist/src/templates/src/templates/sideScroller/src/game.js +102 -0
- package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
- package/dist/src/templates/src/templates/sideScroller/src/player.js +100 -0
- package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
- package/dist/src/templates/src/templates/thirdPerson/src/player.js +58 -0
- package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
- package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
- package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +188 -0
- package/dist/src/templates/src/templates/vehicle/src/player.js +97 -0
- package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +258 -0
- package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
- package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
- package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
- package/dist/src/templates/vite.config.js +46 -0
- package/package.json +181 -0
- package/scripts/post-install.ts +143 -0
- package/src/asset-pack/.gitattributes +89 -0
- package/src/asset-pack/.github/workflows/publish.yml +90 -0
- package/src/asset-pack/eslint.config.js +59 -0
- package/src/asset-pack/gitignore +11 -0
- package/src/asset-pack/scripts/post-install.ts +81 -0
- package/src/asset-pack/src/index.ts +0 -0
- package/src/asset-pack/tsconfig.json +34 -0
- package/src/templates/.cursor/mcp.json +20 -0
- package/src/templates/.cursorignore +2 -0
- package/src/templates/.gitattributes +89 -0
- package/src/templates/.vscode/settings.json +6 -0
- package/src/templates/AGENTS.md +104 -0
- package/src/templates/CLAUDE.md +1 -0
- package/src/templates/README.md +24 -0
- package/src/templates/eslint.config.js +60 -0
- package/src/templates/gitignore +11 -0
- package/src/templates/index.html +34 -0
- package/src/templates/pnpm-lock.yaml +3676 -0
- package/src/templates/scripts/genesys/build-project.ts +51 -0
- package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
- package/src/templates/scripts/genesys/common.ts +46 -0
- package/src/templates/scripts/genesys/const.ts +9 -0
- package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
- package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
- package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
- package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
- package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
- package/src/templates/scripts/genesys/doc-server.ts +16 -0
- package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
- package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
- package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
- package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
- package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
- package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
- package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
- package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
- package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
- package/src/templates/scripts/genesys/migrate-scenes-and-prefabs.ts +301 -0
- package/src/templates/scripts/genesys/misc.ts +42 -0
- package/src/templates/scripts/genesys/mock.ts +6 -0
- package/src/templates/scripts/genesys/place-actors.ts +179 -0
- package/src/templates/scripts/genesys/post-install.ts +39 -0
- package/src/templates/scripts/genesys/prefab.schema.json +85 -0
- package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
- package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
- package/src/templates/scripts/genesys/storageProvider.ts +182 -0
- package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
- package/src/templates/src/index.ts +22 -0
- package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
- package/src/templates/src/templates/firstPerson/src/player.ts +59 -0
- package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
- package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/fps/src/game.ts +39 -0
- package/src/templates/src/templates/fps/src/player.ts +66 -0
- package/src/templates/src/templates/fps/src/weapon.ts +47 -0
- package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
- package/src/templates/src/templates/freeCamera/src/player.ts +40 -0
- package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
- package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
- package/src/templates/src/templates/sideScroller/src/game.ts +121 -0
- package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
- package/src/templates/src/templates/sideScroller/src/player.ts +123 -0
- package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
- package/src/templates/src/templates/thirdPerson/src/player.ts +58 -0
- package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
- package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
- package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
- package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
- package/src/templates/src/templates/vehicle/src/game.ts +43 -0
- package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +189 -0
- package/src/templates/src/templates/vehicle/src/player.ts +106 -0
- package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +264 -0
- package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
- package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
- package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
- package/src/templates/src/templates/vr-game/src/game.ts +66 -0
- package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
- package/src/templates/tsconfig.json +35 -0
- package/src/templates/vite.config.ts +52 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration script for Genesys scene, prefab, and material files.
|
|
3
|
+
*
|
|
4
|
+
* Migration order: Scenes → Prefabs → Materials
|
|
5
|
+
* This order is important because the engine cannot load new prefab data with old scene data.
|
|
6
|
+
*
|
|
7
|
+
* The migration runs TWICE:
|
|
8
|
+
* - Pass 1: Updates all files to the new format
|
|
9
|
+
* - Pass 2: Re-processes all files to ensure prefab instances in scenes are saved correctly
|
|
10
|
+
* (prefab instances are only serialized properly when both the prefab and scene
|
|
11
|
+
* data are at the same version)
|
|
12
|
+
*
|
|
13
|
+
* Usage: pnpm migrate (requires running `pnpm build` first to compile game classes)
|
|
14
|
+
*/
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import * as ENGINE from '@gnsx/genesys.js';
|
|
18
|
+
import { getProjectRoot } from './common.js';
|
|
19
|
+
import { mockBrowserEnvironment } from './mock.js';
|
|
20
|
+
import { StorageProvider } from './storageProvider.js';
|
|
21
|
+
// Import game module to register game classes (tsx compiles TypeScript on the fly)
|
|
22
|
+
import '../../src/game.js';
|
|
23
|
+
// Set up browser environment for Node.js (provides document, window, etc.)
|
|
24
|
+
mockBrowserEnvironment();
|
|
25
|
+
// Set up storage provider for file operations
|
|
26
|
+
const storageProvider = new StorageProvider();
|
|
27
|
+
ENGINE.projectContext({ project: 'local-project', storageProvider: storageProvider });
|
|
28
|
+
const defaultWorldOptions = {
|
|
29
|
+
rendererDomElement: document.createElement('div'),
|
|
30
|
+
gameContainer: document.createElement('div'),
|
|
31
|
+
backgroundColor: 0x2E2E2E,
|
|
32
|
+
physicsOptions: {
|
|
33
|
+
engine: ENGINE.PhysicsEngine.Rapier,
|
|
34
|
+
gravity: ENGINE.MathHelpers.makeVector({ up: -9.81 }),
|
|
35
|
+
},
|
|
36
|
+
navigationOptions: {
|
|
37
|
+
engine: ENGINE.NavigationEngine.RecastNavigation,
|
|
38
|
+
},
|
|
39
|
+
useManifold: true
|
|
40
|
+
};
|
|
41
|
+
function findScenesAndPrefabs(dir, files = []) {
|
|
42
|
+
const entries = fs.readdirSync(dir);
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const fullPath = path.join(dir, entry);
|
|
45
|
+
const stat = fs.statSync(fullPath);
|
|
46
|
+
if (stat.isDirectory()) {
|
|
47
|
+
// Skip common directories that shouldn't be processed
|
|
48
|
+
if (entry === 'node_modules' || entry === 'dist' || entry === '.git' || entry === '.engine') {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
findScenesAndPrefabs(fullPath, files);
|
|
52
|
+
}
|
|
53
|
+
else if (entry.endsWith('.genesys-scene')) {
|
|
54
|
+
files.push({ path: fullPath, type: 'scene' });
|
|
55
|
+
}
|
|
56
|
+
else if (entry.endsWith('.prefab.json')) {
|
|
57
|
+
files.push({ path: fullPath, type: 'prefab' });
|
|
58
|
+
}
|
|
59
|
+
else if (entry.endsWith('.material.json')) {
|
|
60
|
+
files.push({ path: fullPath, type: 'material' });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return files;
|
|
64
|
+
}
|
|
65
|
+
async function migrateSceneFile(data, filePath, relativePath) {
|
|
66
|
+
// Create a world and load into it
|
|
67
|
+
const world = new ENGINE.World(defaultWorldOptions);
|
|
68
|
+
if (ENGINE.isLegacyData(data)) {
|
|
69
|
+
// Use WorldSerializer for legacy data
|
|
70
|
+
await ENGINE.WorldSerializer.loadWorld(world, data);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Use Loader for new format
|
|
74
|
+
const loader = new ENGINE.Loader();
|
|
75
|
+
await loader.loadToInstanceAsync(data, world);
|
|
76
|
+
}
|
|
77
|
+
// Dump the world
|
|
78
|
+
const dumper = new ENGINE.Dumper();
|
|
79
|
+
const newData = dumper.dump(world);
|
|
80
|
+
// Write back to file
|
|
81
|
+
const newContent = JSON.stringify(newData, null, 2);
|
|
82
|
+
fs.writeFileSync(filePath, newContent, 'utf-8');
|
|
83
|
+
console.log(`✅ ${relativePath}`);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
async function migratePrefabFile(data, filePath, relativePath) {
|
|
87
|
+
let instance;
|
|
88
|
+
if (ENGINE.isLegacyData(data)) {
|
|
89
|
+
// Use WorldSerializer for legacy data
|
|
90
|
+
console.log(`🔍 Migrating legacy prefab: ${relativePath}`);
|
|
91
|
+
instance = await ENGINE.WorldSerializer.loadActor(data);
|
|
92
|
+
console.log(`✅ ${relativePath}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Use Loader for new format
|
|
96
|
+
const loader = new ENGINE.Loader();
|
|
97
|
+
instance = await loader.loadAsync(data);
|
|
98
|
+
}
|
|
99
|
+
if (!instance) {
|
|
100
|
+
console.log(`⚠️ ${relativePath}: Loaded instance is null, skipping`);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
// Dump using Dumper
|
|
104
|
+
const dumper = new ENGINE.Dumper({ flags: ENGINE.DumperFlags.AsPrefab });
|
|
105
|
+
const newData = dumper.dump(instance);
|
|
106
|
+
// Write back to file
|
|
107
|
+
const newContent = JSON.stringify(newData, null, 2);
|
|
108
|
+
fs.writeFileSync(filePath, newContent, 'utf-8');
|
|
109
|
+
console.log(`✅ ${relativePath}`);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
async function migrateMaterialFile(data, filePath, relativePath) {
|
|
113
|
+
let material;
|
|
114
|
+
if (ENGINE.isLegacyData(data)) {
|
|
115
|
+
console.log(`🔍 Migrated legacy material: ${relativePath}`);
|
|
116
|
+
material = ENGINE.WorldSerializer.importObject(data);
|
|
117
|
+
console.log(`✅ ${relativePath}`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const loader = new ENGINE.Loader();
|
|
121
|
+
material = await loader.loadAsync(data);
|
|
122
|
+
}
|
|
123
|
+
if (!material) {
|
|
124
|
+
console.log(`⚠️ ${relativePath}: Loaded material is null, skipping`);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
// Dump using Dumper
|
|
128
|
+
const dumper = new ENGINE.Dumper({ flags: ENGINE.DumperFlags.AsPrefab });
|
|
129
|
+
const newData = dumper.dump(material);
|
|
130
|
+
// Write back to file
|
|
131
|
+
const newContent = JSON.stringify(newData, null, 2);
|
|
132
|
+
fs.writeFileSync(filePath, newContent, 'utf-8');
|
|
133
|
+
console.log(`✅ ${relativePath}`);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
async function migrateFile(fileInfo) {
|
|
137
|
+
const { path: filePath, type } = fileInfo;
|
|
138
|
+
const relativePath = path.relative(getProjectRoot(), filePath);
|
|
139
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
140
|
+
const data = JSON.parse(content);
|
|
141
|
+
// if (ENGINE.isUpdateToDateData(data)) {
|
|
142
|
+
// console.log(`ℹ️ ${relativePath}: Already up to date, skipping`);
|
|
143
|
+
// // return 'skipped';
|
|
144
|
+
// }
|
|
145
|
+
try {
|
|
146
|
+
if (type === 'scene') {
|
|
147
|
+
return await migrateSceneFile(data, filePath, relativePath) ? 'success' : 'failure';
|
|
148
|
+
}
|
|
149
|
+
else if (type === 'prefab') {
|
|
150
|
+
return await migratePrefabFile(data, filePath, relativePath) ? 'success' : 'failure';
|
|
151
|
+
}
|
|
152
|
+
else if (type === 'material') {
|
|
153
|
+
return await migrateMaterialFile(data, filePath, relativePath) ? 'success' : 'failure';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
console.error(`❌ ${relativePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
158
|
+
return 'failure';
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
console.log('');
|
|
162
|
+
}
|
|
163
|
+
return 'skipped';
|
|
164
|
+
}
|
|
165
|
+
async function runMigrationPass(sceneFiles, prefabFiles, materialFiles, passNumber) {
|
|
166
|
+
let successCount = 0;
|
|
167
|
+
let failCount = 0;
|
|
168
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
169
|
+
console.log(`Migration Pass ${passNumber}`);
|
|
170
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
171
|
+
// Migrate scenes first (must be done before prefabs to ensure engine can load new prefab data)
|
|
172
|
+
if (sceneFiles.length > 0) {
|
|
173
|
+
console.log('🌍 Migrating scenes...\n');
|
|
174
|
+
for (const fileInfo of sceneFiles) {
|
|
175
|
+
const success = await migrateFile(fileInfo);
|
|
176
|
+
if (success) {
|
|
177
|
+
successCount++;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
failCount++;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Then migrate prefabs
|
|
185
|
+
if (prefabFiles.length > 0) {
|
|
186
|
+
console.log('\n📦 Migrating prefabs...\n');
|
|
187
|
+
for (const fileInfo of prefabFiles) {
|
|
188
|
+
const success = await migrateFile(fileInfo);
|
|
189
|
+
if (success) {
|
|
190
|
+
successCount++;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
failCount++;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Finally migrate materials
|
|
198
|
+
if (materialFiles.length > 0) {
|
|
199
|
+
console.log('\n🎨 Migrating materials...\n');
|
|
200
|
+
for (const fileInfo of materialFiles) {
|
|
201
|
+
const success = await migrateFile(fileInfo);
|
|
202
|
+
if (success) {
|
|
203
|
+
successCount++;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
failCount++;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return { successCount, failCount };
|
|
211
|
+
}
|
|
212
|
+
async function main() {
|
|
213
|
+
// Game classes are registered via the top-level import of dist/src/game.js
|
|
214
|
+
// Make sure to run `pnpm build` first!
|
|
215
|
+
const projectRoot = getProjectRoot();
|
|
216
|
+
const assetsFolder = path.join(projectRoot, 'assets');
|
|
217
|
+
console.log(`📁 Scanning for scene and prefab files in: ${assetsFolder}\n`);
|
|
218
|
+
// Find all scene and prefab files in the assets folder
|
|
219
|
+
const files = findScenesAndPrefabs(assetsFolder);
|
|
220
|
+
if (files.length === 0) {
|
|
221
|
+
console.log('⚠️ No scene or prefab files found.');
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const prefabFiles = files.filter(f => f.type === 'prefab');
|
|
225
|
+
const sceneFiles = files.filter(f => f.type === 'scene');
|
|
226
|
+
const materialFiles = files.filter(f => f.type === 'material');
|
|
227
|
+
console.log(`Found ${files.length} files to migrate:`);
|
|
228
|
+
console.log(` - ${sceneFiles.length} scene file(s)`);
|
|
229
|
+
console.log(` - ${prefabFiles.length} prefab file(s)`);
|
|
230
|
+
console.log(` - ${materialFiles.length} material file(s)`);
|
|
231
|
+
// Run migration twice to ensure prefab instances in scenes are saved properly
|
|
232
|
+
// (prefab instances are only saved correctly when both prefab and scene data are the same version)
|
|
233
|
+
const pass1 = await runMigrationPass(sceneFiles, prefabFiles, materialFiles, 1);
|
|
234
|
+
const pass2 = await runMigrationPass(sceneFiles, prefabFiles, materialFiles, 2);
|
|
235
|
+
const totalSuccess = pass1.successCount + pass2.successCount;
|
|
236
|
+
const totalFail = pass1.failCount + pass2.failCount;
|
|
237
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
238
|
+
console.log('Migration Summary:');
|
|
239
|
+
console.log(` Total files per pass: ${files.length}`);
|
|
240
|
+
console.log(` Pass 1 - Successful: ${pass1.successCount}, Failed: ${pass1.failCount}`);
|
|
241
|
+
console.log(` Pass 2 - Successful: ${pass2.successCount}, Failed: ${pass2.failCount}`);
|
|
242
|
+
console.log(` Total - Successful: ${totalSuccess}, Failed: ${totalFail}`);
|
|
243
|
+
console.log(`${'='.repeat(60)}`);
|
|
244
|
+
if (totalFail > 0) {
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
main().catch((error) => {
|
|
249
|
+
console.error('Unexpected error:', error);
|
|
250
|
+
console.error('Stack trace:', error.stack);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import * as ENGINE from '@gnsx/genesys.js';
|
|
3
|
+
import { getProjectRoot } from './common.js';
|
|
4
|
+
import { isSubclass } from './mcp/utils.js';
|
|
5
|
+
import { fixUpClassName, registerGameClasses } from './mcp/utils.js';
|
|
6
|
+
import { StorageProvider } from './storageProvider.js';
|
|
7
|
+
export async function generateCode(className, filePath, baseClassName) {
|
|
8
|
+
try {
|
|
9
|
+
baseClassName = fixUpClassName(baseClassName);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
// if the base class name is not found, register all game classes and try again
|
|
13
|
+
await registerGameClasses();
|
|
14
|
+
baseClassName = fixUpClassName(baseClassName);
|
|
15
|
+
}
|
|
16
|
+
using context = ENGINE.scopedProjectContext({ project: 'mcp-project', storageProvider: new StorageProvider() });
|
|
17
|
+
const testIsSubclass = (childName, parent) => {
|
|
18
|
+
const child = ENGINE.ClassRegistry.getRegistry().get(childName);
|
|
19
|
+
if (!child) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return isSubclass(child, parent);
|
|
23
|
+
};
|
|
24
|
+
const fullFilePath = path.isAbsolute(filePath) ? filePath : path.join(getProjectRoot(), filePath);
|
|
25
|
+
let fileGenerated = false;
|
|
26
|
+
const isSubclassOfActor = testIsSubclass(baseClassName, ENGINE.Actor);
|
|
27
|
+
if (isSubclassOfActor) {
|
|
28
|
+
await ENGINE.WorldCommands.generateActorTemplateFile(className, fullFilePath, baseClassName);
|
|
29
|
+
fileGenerated = true;
|
|
30
|
+
}
|
|
31
|
+
return fileGenerated;
|
|
32
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as ENGINE from '@gnsx/genesys.js';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { ThreeEulerSchema, ThreeVector3Schema } from './mcp/search-actors.js';
|
|
4
|
+
import { loadWorld, registerGameClassesIfAnyNotRegistered } from './mcp/utils.js';
|
|
5
|
+
import { mockBrowserEnvironment } from './mock.js';
|
|
6
|
+
import '../src/game.js';
|
|
7
|
+
mockBrowserEnvironment();
|
|
8
|
+
function convertConstructorParams(value) {
|
|
9
|
+
// If not an object, return as is
|
|
10
|
+
if (!value || typeof value !== 'object') {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
// Check if it's a Vector3
|
|
14
|
+
const vector3Result = ThreeVector3Schema.safeParse(value);
|
|
15
|
+
if (vector3Result.success) {
|
|
16
|
+
return new THREE.Vector3(vector3Result.data.x, vector3Result.data.y, vector3Result.data.z);
|
|
17
|
+
}
|
|
18
|
+
// Check if it's an Euler
|
|
19
|
+
const eulerResult = ThreeEulerSchema.safeParse(value);
|
|
20
|
+
if (eulerResult.success) {
|
|
21
|
+
return new THREE.Euler(eulerResult.data.x, eulerResult.data.y, eulerResult.data.z);
|
|
22
|
+
}
|
|
23
|
+
// Handle arrays
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return value.map(convertConstructorParams);
|
|
26
|
+
}
|
|
27
|
+
// Handle objects
|
|
28
|
+
const result = {};
|
|
29
|
+
for (const [key, val] of Object.entries(value)) {
|
|
30
|
+
result[key] = convertConstructorParams(val);
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
export async function placePrimitive(args) {
|
|
35
|
+
using worldResource = await loadWorld(args.sceneName, { skipLoadingGLTF: true });
|
|
36
|
+
const actors = ENGINE.WorldCommands.placePrimitives({
|
|
37
|
+
world: worldResource.world,
|
|
38
|
+
primitiveActors: args.primitiveActors,
|
|
39
|
+
});
|
|
40
|
+
return actors.map(actor => actor.uuid);
|
|
41
|
+
}
|
|
42
|
+
export async function removeActors(args) {
|
|
43
|
+
using worldResource = await loadWorld(args.sceneName, { skipLoadingGLTF: true });
|
|
44
|
+
ENGINE.WorldCommands.removeActorsByUuids({
|
|
45
|
+
world: worldResource.world,
|
|
46
|
+
actorIds: args.actorIds,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
export async function addGltf(args) {
|
|
50
|
+
using worldResource = await loadWorld(args.sceneName, { skipLoadingGLTF: true });
|
|
51
|
+
const actors = await ENGINE.WorldCommands.placeGltfs({
|
|
52
|
+
world: worldResource.world,
|
|
53
|
+
gltfs: args.gltfs
|
|
54
|
+
});
|
|
55
|
+
return actors.map(actor => actor.uuid);
|
|
56
|
+
}
|
|
57
|
+
export async function placePrefab(args) {
|
|
58
|
+
using worldResource = await loadWorld(args.sceneName, { skipLoadingGLTF: true });
|
|
59
|
+
const actors = await ENGINE.WorldCommands.placePrefabs({
|
|
60
|
+
world: worldResource.world,
|
|
61
|
+
prefabs: args.prefabs
|
|
62
|
+
});
|
|
63
|
+
return actors.map(actor => actor.uuid);
|
|
64
|
+
}
|
|
65
|
+
export async function placeJsClassActor(args) {
|
|
66
|
+
await registerGameClassesIfAnyNotRegistered(args.jsClasses.map(jsClass => jsClass.className));
|
|
67
|
+
using worldResource = await loadWorld(args.sceneName, { skipLoadingGLTF: true });
|
|
68
|
+
const actors = [];
|
|
69
|
+
for (const { className, constructorParams, actorInfo } of args.jsClasses) {
|
|
70
|
+
try {
|
|
71
|
+
// Convert constructor parameters if they exist
|
|
72
|
+
const convertedParams = constructorParams ? convertConstructorParams(constructorParams) : [];
|
|
73
|
+
const actor = ENGINE.ClassRegistry.constructObject(className, false, ...convertedParams);
|
|
74
|
+
if (actorInfo) {
|
|
75
|
+
Object.assign(actor.editorData, actorInfo);
|
|
76
|
+
}
|
|
77
|
+
actors.push(actor);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
console.error(`Error constructing object ${className}`, e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
worldResource.world.addActors(...actors);
|
|
84
|
+
return actors.map(actor => actor.uuid);
|
|
85
|
+
}
|
|
86
|
+
export async function updateActors(args) {
|
|
87
|
+
const readonly = args.actorsToUpdate.length == 0;
|
|
88
|
+
using worldResource = await loadWorld(args.sceneName, { readonly, skipLoadingGLTF: true });
|
|
89
|
+
let count = 0;
|
|
90
|
+
for (const { uuid, transform, actorInfo } of args.actorsToUpdate) {
|
|
91
|
+
const actor = worldResource.world.getActorByUuid(uuid);
|
|
92
|
+
if (!actor) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (transform) {
|
|
96
|
+
if (transform.position) {
|
|
97
|
+
actor.setWorldPosition(transform.position);
|
|
98
|
+
}
|
|
99
|
+
if (transform.rotation) {
|
|
100
|
+
actor.setWorldRotation(transform.rotation);
|
|
101
|
+
}
|
|
102
|
+
if (transform.scale) {
|
|
103
|
+
actor.setWorldScale(transform.scale);
|
|
104
|
+
}
|
|
105
|
+
if (actorInfo) {
|
|
106
|
+
Object.assign(actor.editorData, actorInfo);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
count += 1;
|
|
110
|
+
}
|
|
111
|
+
return count;
|
|
112
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getProjectRoot } from './common.js';
|
|
4
|
+
async function main() {
|
|
5
|
+
const engineInstallFolder = path.join(getProjectRoot(), 'node_modules/@gnsx/genesys.js');
|
|
6
|
+
if (!fs.existsSync(engineInstallFolder)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const copiedEngineFolder = path.join(getProjectRoot(), '.engine');
|
|
10
|
+
if (fs.existsSync(copiedEngineFolder)) {
|
|
11
|
+
fs.rmdirSync(copiedEngineFolder, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
fs.mkdirSync(copiedEngineFolder, { recursive: true });
|
|
14
|
+
const foldersToCopy = [
|
|
15
|
+
'games/examples',
|
|
16
|
+
'src'
|
|
17
|
+
];
|
|
18
|
+
for (const folder of foldersToCopy) {
|
|
19
|
+
const engineFolderPath = path.join(engineInstallFolder, folder);
|
|
20
|
+
const localFolderPath = path.join(copiedEngineFolder, folder);
|
|
21
|
+
fs.cpSync(engineFolderPath, localFolderPath, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
// copy all *.md files
|
|
24
|
+
const files = fs.readdirSync(engineInstallFolder);
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
if (file.endsWith('.md')) {
|
|
27
|
+
const engineFilePath = path.join(engineInstallFolder, file);
|
|
28
|
+
const localFilePath = path.join(copiedEngineFolder, file);
|
|
29
|
+
fs.copyFileSync(engineFilePath, localFilePath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
main();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { readdir, readFile, stat, writeFile } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Recursively finds all TypeScript files in a directory
|
|
6
|
+
*/
|
|
7
|
+
async function findTsFiles(dir) {
|
|
8
|
+
const files = [];
|
|
9
|
+
try {
|
|
10
|
+
const entries = await readdir(dir);
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
const fullPath = join(dir, entry);
|
|
13
|
+
const stats = await stat(fullPath);
|
|
14
|
+
if (stats.isDirectory()) {
|
|
15
|
+
const subFiles = await findTsFiles(fullPath);
|
|
16
|
+
files.push(...subFiles);
|
|
17
|
+
}
|
|
18
|
+
else if (entry.endsWith('.ts') || entry.endsWith('.tsx')) {
|
|
19
|
+
files.push(fullPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.warn(`Warning: Could not read directory ${dir}:`, error);
|
|
25
|
+
}
|
|
26
|
+
return files;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Removes comments from TypeScript code using regex
|
|
30
|
+
*/
|
|
31
|
+
function removeComments(code) {
|
|
32
|
+
const originalLength = code.length;
|
|
33
|
+
// Remove single-line comments (// comments)
|
|
34
|
+
// This regex handles // comments but preserves URLs and string literals
|
|
35
|
+
let cleaned = code.replace(/^(\s*)\/\/.*$/gm, '$1');
|
|
36
|
+
// Remove multi-line comments (/* ... */ and /** ... */)
|
|
37
|
+
// This regex handles nested quotes and preserves strings
|
|
38
|
+
cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
39
|
+
// Clean up multiple consecutive empty lines (replace with single empty line)
|
|
40
|
+
cleaned = cleaned.replace(/\n\s*\n\s*\n/g, '\n\n');
|
|
41
|
+
// Trim trailing whitespace on each line
|
|
42
|
+
cleaned = cleaned.replace(/[ \t]+$/gm, '');
|
|
43
|
+
const hadComments = cleaned.length !== originalLength || cleaned !== code;
|
|
44
|
+
return { cleaned, hadComments };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Removes comments from a TypeScript file
|
|
48
|
+
*/
|
|
49
|
+
async function removeCommentsFromFile(filePath) {
|
|
50
|
+
try {
|
|
51
|
+
const content = await readFile(filePath, 'utf8');
|
|
52
|
+
const { cleaned, hadComments } = removeComments(content);
|
|
53
|
+
if (!hadComments) {
|
|
54
|
+
return false; // No comments to remove
|
|
55
|
+
}
|
|
56
|
+
await writeFile(filePath, cleaned, 'utf8');
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error(`Error processing file ${filePath}:`, error);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function main() {
|
|
65
|
+
const engineDir = '.engine';
|
|
66
|
+
console.log(`Searching for TypeScript files in ${engineDir}...`);
|
|
67
|
+
console.log(`Current working directory: ${process.cwd()}`);
|
|
68
|
+
try {
|
|
69
|
+
const tsFiles = await findTsFiles(engineDir);
|
|
70
|
+
console.log(`Found ${tsFiles.length} TypeScript files.`);
|
|
71
|
+
if (tsFiles.length > 0) {
|
|
72
|
+
console.log('First few files:');
|
|
73
|
+
tsFiles.slice(0, 5).forEach(file => console.log(` - ${file}`));
|
|
74
|
+
}
|
|
75
|
+
if (tsFiles.length === 0) {
|
|
76
|
+
console.log('No TypeScript files found in .engine folder.');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
let processedCount = 0;
|
|
80
|
+
let modifiedCount = 0;
|
|
81
|
+
for (const filePath of tsFiles) {
|
|
82
|
+
console.log(`Processing: ${filePath}`);
|
|
83
|
+
try {
|
|
84
|
+
const wasModified = await removeCommentsFromFile(filePath);
|
|
85
|
+
processedCount++;
|
|
86
|
+
if (wasModified) {
|
|
87
|
+
modifiedCount++;
|
|
88
|
+
console.log(' ✓ Comments removed');
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.log(' - No comments found');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
console.error(` ✗ Error: ${error}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
console.log('\nCompleted:');
|
|
99
|
+
console.log(`- Files processed: ${processedCount}`);
|
|
100
|
+
console.log(`- Files modified: ${modifiedCount}`);
|
|
101
|
+
console.log(`- Files skipped: ${processedCount - modifiedCount}`);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error('Error:', error);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Always run main if this file is executed directly
|
|
109
|
+
main().catch((error) => {
|
|
110
|
+
console.error('Unexpected error:', error);
|
|
111
|
+
console.error('Stack trace:', error.stack);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
});
|