@directivegames/genesys.sdk 3.2.2
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 +43 -0
- package/dist/src/asset-pack/scripts/postinstall.js +64 -0
- package/dist/src/asset-pack/src/index.js +1 -0
- package/dist/src/core/cli.js +306 -0
- package/dist/src/core/common.js +324 -0
- package/dist/src/core/index.js +6 -0
- package/dist/src/core/tools/build-project.js +450 -0
- package/dist/src/core/tools/index.js +2 -0
- package/dist/src/core/tools/new-asset-pack.js +150 -0
- package/dist/src/core/tools/new-project.js +292 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/dependencies.js +82 -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 +441 -0
- package/dist/src/electron/backend/logging.js +41 -0
- package/dist/src/electron/backend/main.js +315 -0
- package/dist/src/electron/backend/menu.js +208 -0
- package/dist/src/electron/backend/state.js +201 -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 +261 -0
- package/dist/src/electron/backend/window.js +161 -0
- package/dist/src/templates/eslint.config.js +43 -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/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 +25 -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 +60 -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 +64 -0
- package/dist/src/templates/src/templates/fps/src/weapon.js +62 -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 +43 -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 +103 -0
- package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
- package/dist/src/templates/src/templates/sideScroller/src/player.js +105 -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 +63 -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 +189 -0
- package/dist/src/templates/src/templates/vehicle/src/player.js +102 -0
- package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +259 -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 +176 -0
- package/scripts/post-install.ts +143 -0
- package/src/asset-pack/.gitattributes +89 -0
- package/src/asset-pack/eslint.config.js +45 -0
- package/src/asset-pack/gitignore +11 -0
- package/src/asset-pack/scripts/postinstall.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 +86 -0
- package/src/templates/CLAUDE.md +1 -0
- package/src/templates/README.md +24 -0
- package/src/templates/eslint.config.js +45 -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/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 +30 -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 +63 -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 +69 -0
- package/src/templates/src/templates/fps/src/weapon.ts +54 -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 +45 -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 +122 -0
- package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
- package/src/templates/src/templates/sideScroller/src/player.ts +125 -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 +61 -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 +191 -0
- package/src/templates/src/templates/vehicle/src/player.ts +109 -0
- package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +266 -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,205 @@
|
|
|
1
|
+
import fs, { readFileSync } from 'fs';
|
|
2
|
+
import path, { resolve } from 'path';
|
|
3
|
+
import * as ENGINE from 'genesys.js';
|
|
4
|
+
import * as THREE from 'three';
|
|
5
|
+
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
6
|
+
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
7
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
8
|
+
import { mockBrowserEnvironment } from './mock.js';
|
|
9
|
+
mockBrowserEnvironment();
|
|
10
|
+
// Custom error types for better error handling
|
|
11
|
+
class GLBLoadError extends Error {
|
|
12
|
+
filePath;
|
|
13
|
+
constructor(message, filePath) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.filePath = filePath;
|
|
16
|
+
this.name = 'GLBLoadError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
class BoundingBoxCalculationError extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'BoundingBoxCalculationError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function verifyPath(path) {
|
|
26
|
+
if (path.startsWith(ENGINE.PROJECT_PATH_PREFIX) || path.startsWith(ENGINE.ENGINE_PATH_PREFIX)) {
|
|
27
|
+
throw new Error(`Expecting a valid path, not a project or engine path: ${path}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Helper function to load and parse a GLB file
|
|
32
|
+
* @param glbFilePath - Path to the GLB file
|
|
33
|
+
* @returns Promise resolving to the loaded GLTF scene
|
|
34
|
+
*/
|
|
35
|
+
async function loadGLBFile(glbFilePath) {
|
|
36
|
+
verifyPath(glbFilePath);
|
|
37
|
+
// Resolve the absolute path
|
|
38
|
+
const absolutePath = resolve(glbFilePath);
|
|
39
|
+
try {
|
|
40
|
+
// Read the GLB file
|
|
41
|
+
const glbData = readFileSync(absolutePath);
|
|
42
|
+
const arrayBuffer = glbData.buffer.slice(glbData.byteOffset, glbData.byteOffset + glbData.byteLength);
|
|
43
|
+
// Load the GLB using GLTFLoader
|
|
44
|
+
const loader = new GLTFLoader();
|
|
45
|
+
loader.setMeshoptDecoder(MeshoptDecoder);
|
|
46
|
+
const dracoLoader = new DRACOLoader();
|
|
47
|
+
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
|
|
48
|
+
loader.setDRACOLoader(dracoLoader);
|
|
49
|
+
const gltf = await loader.parseAsync(arrayBuffer, '');
|
|
50
|
+
if (!gltf.scene) {
|
|
51
|
+
throw new BoundingBoxCalculationError('No scene found in GLB file');
|
|
52
|
+
}
|
|
53
|
+
return gltf;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof Error) {
|
|
57
|
+
if (error.name === 'GLBLoadError' || error.name === 'BoundingBoxCalculationError') {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
throw new GLBLoadError(`Failed to load GLB file: ${error.message}`, glbFilePath);
|
|
61
|
+
}
|
|
62
|
+
throw new GLBLoadError('Unknown error loading GLB file', glbFilePath);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Helper function to extract bounding box data from a Three.js Box3
|
|
67
|
+
* @param boundingBox - Three.js Box3 object
|
|
68
|
+
* @returns BoundingBox interface object
|
|
69
|
+
*/
|
|
70
|
+
function extractBoundingBoxData(boundingBox) {
|
|
71
|
+
return ENGINE.DescriptionHelper.dumpBoundingBox(boundingBox);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Calculates the bounding box of a GLB mesh with applied transformations
|
|
75
|
+
* @param glbFilePath - Path to the GLB file
|
|
76
|
+
* @param transform - Transformation to apply (position, rotation, scale)
|
|
77
|
+
* @returns Promise resolving to the calculated bounding box
|
|
78
|
+
*/
|
|
79
|
+
async function calculateGLBBoundingBox(glbFilePath, transform) {
|
|
80
|
+
const gltf = await loadGLBFile(glbFilePath);
|
|
81
|
+
// Create a new object to apply transformations
|
|
82
|
+
const transformedObject = new THREE.Object3D();
|
|
83
|
+
transformedObject.add(gltf.scene);
|
|
84
|
+
// Apply transformations
|
|
85
|
+
transform.position && transformedObject.position.set(...transform.position);
|
|
86
|
+
transform.rotation && transformedObject.rotation.set(...transform.rotation);
|
|
87
|
+
transform.scale && transformedObject.scale.set(...transform.scale);
|
|
88
|
+
// Update world matrix to ensure transformations are applied
|
|
89
|
+
transformedObject.updateMatrixWorld(true);
|
|
90
|
+
const boundingBox = ENGINE.GLTFMeshComponent.calcBoundingBoxFromGLTF(gltf);
|
|
91
|
+
return extractBoundingBoxData(boundingBox);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Calculates the original bounding box of a GLB mesh without any transformations
|
|
95
|
+
* @param glbFilePath - Path to the GLB file
|
|
96
|
+
* @returns Promise resolving to the original mesh bounding box
|
|
97
|
+
*/
|
|
98
|
+
async function calculateGLBOriginalBoundingBox(glbFilePath) {
|
|
99
|
+
const gltf = await loadGLBFile(glbFilePath);
|
|
100
|
+
const boundingBox = ENGINE.GLTFMeshComponent.calcBoundingBoxFromGLTF(gltf);
|
|
101
|
+
return extractBoundingBoxData(boundingBox);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Helper function to create a default transform
|
|
105
|
+
*/
|
|
106
|
+
function createTransform(position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1]) {
|
|
107
|
+
return { position, rotation, scale };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Utility function to convert degrees to radians
|
|
111
|
+
*/
|
|
112
|
+
function degreesToRadians(degrees) {
|
|
113
|
+
return degrees * (Math.PI / 180);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Fetches the bounding box data from the manifest file, and returns the bounding box data
|
|
117
|
+
* It internally keeps a bounding box manifest as a cache, and only recalculates the bounding box data if the file has been modified since last calculation
|
|
118
|
+
* @param manifestFile - Path to the manifest JSON file, must be a valid path, not `@project` or `@engine` path
|
|
119
|
+
* @param gltfPaths - Dictionary of gltf key to GLTF file paths, key in theory can be any ID of a gltf mesh.
|
|
120
|
+
*/
|
|
121
|
+
async function fetchBoundingBoxData(manifestFile, gltfPaths) {
|
|
122
|
+
verifyPath(manifestFile);
|
|
123
|
+
manifestFile = resolve(manifestFile);
|
|
124
|
+
try {
|
|
125
|
+
// Read existing manifest or create empty one
|
|
126
|
+
let manifest = {};
|
|
127
|
+
try {
|
|
128
|
+
if (fs.existsSync(manifestFile)) {
|
|
129
|
+
const manifestContent = fs.readFileSync(manifestFile, 'utf-8');
|
|
130
|
+
manifest = JSON.parse(manifestContent);
|
|
131
|
+
console.log(`Loaded existing manifest with ${Object.keys(manifest).length} entries`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log('Creating new manifest file');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.warn(`Failed to read existing manifest, starting fresh: ${error instanceof Error ? error.message : String(error)}`);
|
|
139
|
+
manifest = {};
|
|
140
|
+
}
|
|
141
|
+
// Process each GLTF file
|
|
142
|
+
const updatedManifest = { ...manifest };
|
|
143
|
+
let processedCount = 0;
|
|
144
|
+
let skippedCount = 0;
|
|
145
|
+
for (const [key, gltfPath] of Object.entries(gltfPaths)) {
|
|
146
|
+
try {
|
|
147
|
+
// Resolve absolute path for consistent comparison
|
|
148
|
+
const absolutePath = resolve(gltfPath);
|
|
149
|
+
// Check if file exists
|
|
150
|
+
if (!fs.existsSync(absolutePath)) {
|
|
151
|
+
console.warn(`Warning: File not found: ${gltfPath}`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
// Get file stats to check modification time
|
|
155
|
+
const stats = fs.statSync(absolutePath);
|
|
156
|
+
const currentTimestamp = stats.mtime.toISOString();
|
|
157
|
+
// Check if we need to update this file
|
|
158
|
+
const existingEntry = manifest[key];
|
|
159
|
+
if (existingEntry && existingEntry.timestamp === currentTimestamp) {
|
|
160
|
+
console.log(`Skipping ${gltfPath} (unchanged)`);
|
|
161
|
+
skippedCount++;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
// Calculate bounding box for new/modified file
|
|
165
|
+
console.log(`Processing ${gltfPath}...`);
|
|
166
|
+
const boundingBox = await calculateGLBOriginalBoundingBox(absolutePath);
|
|
167
|
+
// Update manifest entry
|
|
168
|
+
updatedManifest[key] = {
|
|
169
|
+
bounding_box: boundingBox,
|
|
170
|
+
timestamp: currentTimestamp
|
|
171
|
+
};
|
|
172
|
+
processedCount++;
|
|
173
|
+
console.log(`✓ Updated bounding box for ${gltfPath}`);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
177
|
+
console.error(`Failed to process ${gltfPath}: ${errorMessage}`);
|
|
178
|
+
// Continue processing other files even if one fails
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Save updated manifest if any changes were made
|
|
182
|
+
if (processedCount > 0) {
|
|
183
|
+
// Ensure directory exists
|
|
184
|
+
const manifestDir = path.dirname(manifestFile);
|
|
185
|
+
if (!fs.existsSync(manifestDir)) {
|
|
186
|
+
fs.mkdirSync(manifestDir, { recursive: true });
|
|
187
|
+
}
|
|
188
|
+
// Write manifest with pretty formatting
|
|
189
|
+
fs.writeFileSync(manifestFile, JSON.stringify(updatedManifest, null, 2), 'utf-8');
|
|
190
|
+
console.log(`\n✓ Manifest updated: ${processedCount} files processed, ${skippedCount} files skipped`);
|
|
191
|
+
console.log(`Manifest saved to: ${manifestFile}`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
console.log(`\n✓ No updates needed: ${skippedCount} files already up to date`);
|
|
195
|
+
}
|
|
196
|
+
return Object.fromEntries(Object.entries(gltfPaths).map(([key, absPath]) => [key, updatedManifest[key].bounding_box]));
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
200
|
+
throw new Error(`Failed to update bounding box manifest: ${errorMessage}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Export the main functions for use as a module
|
|
204
|
+
export { calculateGLBBoundingBox, calculateGLBOriginalBoundingBox, createTransform, degreesToRadians, fetchBoundingBoxData, extractBoundingBoxData, GLBLoadError, BoundingBoxCalculationError };
|
|
205
|
+
export { BoundingBoxSchema } from 'genesys.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export const isDev = process.env.NODE_ENV === 'development' ||
|
|
6
|
+
process.env.NODE_ENV === 'dev' ||
|
|
7
|
+
process.argv.includes('--dev');
|
|
8
|
+
export function mockEsModule() {
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
global.__filename = __filename;
|
|
12
|
+
global.__dirname = __dirname;
|
|
13
|
+
}
|
|
14
|
+
mockEsModule();
|
|
15
|
+
export function getProjectRoot() {
|
|
16
|
+
let currentDir = __dirname;
|
|
17
|
+
while (true) {
|
|
18
|
+
if (fs.existsSync(path.join(currentDir, 'package.json'))) {
|
|
19
|
+
return currentDir;
|
|
20
|
+
}
|
|
21
|
+
const parentDir = path.dirname(currentDir);
|
|
22
|
+
if (parentDir === currentDir) {
|
|
23
|
+
throw new Error('Project root not found');
|
|
24
|
+
}
|
|
25
|
+
currentDir = parentDir;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export const TransformSchema = z.object({
|
|
29
|
+
position: z.array(z.number()).length(3).optional().describe('Position as [x, y, z]'),
|
|
30
|
+
rotation: z.array(z.number()).length(3).optional().describe('Rotation in radians as [x, y, z]'),
|
|
31
|
+
scale: z.array(z.number()).length(3).optional().describe('Scale as [x, y, z], use this to scale the actor up or down'),
|
|
32
|
+
});
|
|
33
|
+
export const ActorInfoSchema = z.object({
|
|
34
|
+
displayName: z.string().describe('Display name of the actor'),
|
|
35
|
+
description: z.string().optional().describe('Description of the actor, including its purpose, how to use it, etc.'),
|
|
36
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// MUST be kept in sync with https://github.com/directivegames/genesys.ai/blob/develop/src/const.ts
|
|
2
|
+
export const SCENE_EXTENSION = '.genesys-scene';
|
|
3
|
+
export const PUBLIC_FOLDER = 'public';
|
|
4
|
+
export const PROJECT_PREFIX = '@project';
|
|
5
|
+
export const ENGINE_PREFIX = '@engine';
|
|
6
|
+
export const DEFAULT_GAME_NAME = 'game.ts';
|
|
7
|
+
export const DEFAULT_GAME_BUNDLE_NAME = 'game.js';
|
|
8
|
+
export const BUILT_PROJECT_FOLDER = '.dist';
|
|
9
|
+
export const JS_CLASSES_DIR_NAME = '@js-classes';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as ENGINE from 'genesys.js';
|
|
2
|
+
import { defaultWorldOptions } from '../mcp/utils.js';
|
|
3
|
+
function main() {
|
|
4
|
+
const world = new ENGINE.World(defaultWorldOptions);
|
|
5
|
+
ENGINE.GameBuilder.createDefaultEditorScene(world);
|
|
6
|
+
console.log(JSON.stringify(world.asExportedObject(), null, 2));
|
|
7
|
+
}
|
|
8
|
+
main();
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// pnpm exec tsx ./scripts/genesys/dev/generate-manifest.ts
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as ENGINE from 'genesys.js';
|
|
5
|
+
import { ManifestPath } from './storage-provider.js';
|
|
6
|
+
/**
|
|
7
|
+
* Recursively scans a directory and returns file information
|
|
8
|
+
*/
|
|
9
|
+
function scanDirectory(dirPath, basePath = '') {
|
|
10
|
+
const items = [];
|
|
11
|
+
if (!fs.existsSync(dirPath)) {
|
|
12
|
+
return items;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
18
|
+
const relativePath = basePath ? path.join(basePath, entry.name) : entry.name;
|
|
19
|
+
const stats = fs.statSync(fullPath);
|
|
20
|
+
const item = {
|
|
21
|
+
name: entry.name,
|
|
22
|
+
path: relativePath.replace(/\\/g, '/'), // Normalize to forward slashes
|
|
23
|
+
size: stats.size,
|
|
24
|
+
modifiedTime: stats.mtime,
|
|
25
|
+
isDirectory: entry.isDirectory(),
|
|
26
|
+
contentType: getContentType(entry.name)
|
|
27
|
+
};
|
|
28
|
+
items.push(item);
|
|
29
|
+
// Recursively scan subdirectories
|
|
30
|
+
if (entry.isDirectory()) {
|
|
31
|
+
const subItems = scanDirectory(fullPath, relativePath);
|
|
32
|
+
items.push(...subItems);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.warn(`Failed to scan directory ${dirPath}:`, error);
|
|
38
|
+
}
|
|
39
|
+
return items;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Gets content type based on file extension
|
|
43
|
+
*/
|
|
44
|
+
function getContentType(fileName) {
|
|
45
|
+
const ext = path.extname(fileName).toLowerCase();
|
|
46
|
+
const contentTypes = {
|
|
47
|
+
'.json': 'application/json',
|
|
48
|
+
'.js': 'application/javascript',
|
|
49
|
+
'.ts': 'application/typescript',
|
|
50
|
+
'.html': 'text/html',
|
|
51
|
+
'.css': 'text/css',
|
|
52
|
+
'.png': 'image/png',
|
|
53
|
+
'.jpg': 'image/jpeg',
|
|
54
|
+
'.jpeg': 'image/jpeg',
|
|
55
|
+
'.gif': 'image/gif',
|
|
56
|
+
'.webp': 'image/webp',
|
|
57
|
+
'.svg': 'image/svg+xml',
|
|
58
|
+
'.glb': 'model/gltf-binary',
|
|
59
|
+
'.gltf': 'model/gltf+json',
|
|
60
|
+
'.wav': 'audio/wav',
|
|
61
|
+
'.mp3': 'audio/mpeg',
|
|
62
|
+
'.ogg': 'audio/ogg',
|
|
63
|
+
'.genesys-scene': 'application/json',
|
|
64
|
+
'.genesys-project': 'application/json'
|
|
65
|
+
};
|
|
66
|
+
return contentTypes[ext];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Groups files by directory path for efficient lookup
|
|
70
|
+
*/
|
|
71
|
+
function groupFilesByDirectory(files) {
|
|
72
|
+
const grouped = {};
|
|
73
|
+
// Add root directory
|
|
74
|
+
grouped[''] = [];
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
const dir = path.dirname(file.path).replace(/\\/g, '/');
|
|
77
|
+
const normalizedDir = dir === '.' ? '' : dir;
|
|
78
|
+
if (!grouped[normalizedDir]) {
|
|
79
|
+
grouped[normalizedDir] = [];
|
|
80
|
+
}
|
|
81
|
+
grouped[normalizedDir].push(file);
|
|
82
|
+
}
|
|
83
|
+
return grouped;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generates the file manifest
|
|
87
|
+
*/
|
|
88
|
+
export async function generateManifest() {
|
|
89
|
+
console.log('Generating file manifest...');
|
|
90
|
+
const manifest = {
|
|
91
|
+
generated: new Date().toISOString(),
|
|
92
|
+
projectFiles: {},
|
|
93
|
+
engineFiles: {}
|
|
94
|
+
};
|
|
95
|
+
// Scan project files
|
|
96
|
+
console.log('Scanning project files...');
|
|
97
|
+
const projectRoot = process.cwd();
|
|
98
|
+
const builtProjectRoot = path.join(projectRoot, ENGINE.BUILT_PROJECT_FOLDER);
|
|
99
|
+
const projectFiles = scanDirectory(builtProjectRoot);
|
|
100
|
+
manifest.projectFiles = groupFilesByDirectory(projectFiles);
|
|
101
|
+
// Scan engine files
|
|
102
|
+
console.log('Scanning engine files...');
|
|
103
|
+
const engineAssetsRoot = path.join(projectRoot, 'node_modules', 'genesys.js', 'assets');
|
|
104
|
+
if (fs.existsSync(engineAssetsRoot)) {
|
|
105
|
+
const engineFiles = scanDirectory(engineAssetsRoot, 'assets');
|
|
106
|
+
manifest.engineFiles = groupFilesByDirectory(engineFiles);
|
|
107
|
+
console.log(`Engine files: ${Object.values(manifest.engineFiles).flat().length}`);
|
|
108
|
+
}
|
|
109
|
+
// Write manifest to public directory so it's accessible to the dev server
|
|
110
|
+
const manifestPath = path.join(projectRoot, ManifestPath);
|
|
111
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
112
|
+
console.log(`File manifest generated: ${manifestPath}`);
|
|
113
|
+
console.log(`Project files: ${Object.values(manifest.projectFiles).flat().length}`);
|
|
114
|
+
console.log(`Engine files: ${Object.values(manifest.engineFiles).flat().length}`);
|
|
115
|
+
}
|
|
116
|
+
generateManifest().catch(console.error);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as ENGINE from 'genesys.js';
|
|
2
|
+
import { DevStorageProvider } from './storage-provider.js';
|
|
3
|
+
// Ensure process is available globally with minimal implementation
|
|
4
|
+
if (typeof globalThis.process === 'undefined') {
|
|
5
|
+
globalThis.process = {
|
|
6
|
+
cwd: () => '/',
|
|
7
|
+
env: {},
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
// Initialize the game - can be called manually
|
|
11
|
+
export async function launchGame() {
|
|
12
|
+
const container = document.getElementById('game-container');
|
|
13
|
+
if (!container) {
|
|
14
|
+
console.error('Game container not found!');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
// Create the storage provider for Vite dev environment
|
|
19
|
+
const storageProvider = new DevStorageProvider();
|
|
20
|
+
ENGINE.projectContext({
|
|
21
|
+
project: 'dev-game',
|
|
22
|
+
storageProvider,
|
|
23
|
+
});
|
|
24
|
+
// Create the game runtime
|
|
25
|
+
const gameRuntime = new ENGINE.GameRuntime({
|
|
26
|
+
provider: storageProvider,
|
|
27
|
+
container: container,
|
|
28
|
+
gameId: 'dev-game',
|
|
29
|
+
buildProject: false,
|
|
30
|
+
skipClearGameClasses: false
|
|
31
|
+
});
|
|
32
|
+
console.log('Starting game runtime...');
|
|
33
|
+
// Start the game with the default scene
|
|
34
|
+
await gameRuntime.startGame();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error('Failed to initialize game:', error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as ENGINE from 'genesys.js';
|
|
2
|
+
export const ManifestPath = 'dist/file-manifest.json';
|
|
3
|
+
export class DevStorageProvider {
|
|
4
|
+
manifestCache = null;
|
|
5
|
+
manifestPromise = null;
|
|
6
|
+
async loadManifest() {
|
|
7
|
+
if (this.manifestCache) {
|
|
8
|
+
return this.manifestCache;
|
|
9
|
+
}
|
|
10
|
+
if (this.manifestPromise) {
|
|
11
|
+
return this.manifestPromise;
|
|
12
|
+
}
|
|
13
|
+
this.manifestPromise = this.fetchManifest();
|
|
14
|
+
this.manifestCache = await this.manifestPromise;
|
|
15
|
+
this.manifestPromise = null;
|
|
16
|
+
return this.manifestCache;
|
|
17
|
+
}
|
|
18
|
+
async fetchManifest() {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`/${ManifestPath}`);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Failed to load manifest: ${response.status} ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
return await response.json();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.warn('Failed to load file manifest, falling back to empty manifest:', error);
|
|
28
|
+
return {
|
|
29
|
+
generated: new Date().toISOString(),
|
|
30
|
+
projectFiles: {},
|
|
31
|
+
engineFiles: {}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async resolvePath(path, expiry) {
|
|
36
|
+
if (path.isResolved()) {
|
|
37
|
+
return path;
|
|
38
|
+
}
|
|
39
|
+
let resolvedUrl;
|
|
40
|
+
if (path.initialPath.startsWith(ENGINE.PROJECT_PATH_PREFIX)) {
|
|
41
|
+
resolvedUrl = path.initialPath.replace(ENGINE.PROJECT_PATH_PREFIX, ENGINE.BUILT_PROJECT_FOLDER);
|
|
42
|
+
}
|
|
43
|
+
else if (path.initialPath.startsWith(ENGINE.ENGINE_PATH_PREFIX)) {
|
|
44
|
+
resolvedUrl = path.initialPath.replace(ENGINE.ENGINE_PATH_PREFIX, '/node_modules/genesys.js');
|
|
45
|
+
}
|
|
46
|
+
else if (path.initialPath.startsWith('/')) {
|
|
47
|
+
resolvedUrl = `/node_modules/genesys.js${path.initialPath}`;
|
|
48
|
+
}
|
|
49
|
+
else if (path.initialPath.startsWith('http') || path.initialPath.startsWith('https')) {
|
|
50
|
+
resolvedUrl = path.initialPath;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Paths without prefix are treated as engine paths
|
|
54
|
+
resolvedUrl = `/node_modules/genesys.js/${path.initialPath}`;
|
|
55
|
+
}
|
|
56
|
+
path.resolvePath(resolvedUrl, ENGINE.AssetPathEncodeState.Unknown);
|
|
57
|
+
return path;
|
|
58
|
+
}
|
|
59
|
+
async downloadFileAsBuffer(path) {
|
|
60
|
+
const resolvedPath = await this.resolvePath(path);
|
|
61
|
+
const response = await fetch(resolvedPath.getResolvedPath());
|
|
62
|
+
this.checkResponse(path, response);
|
|
63
|
+
return response.arrayBuffer();
|
|
64
|
+
}
|
|
65
|
+
async downloadFileAsJson(path) {
|
|
66
|
+
const resolvedPath = await this.resolvePath(path);
|
|
67
|
+
const response = await fetch(resolvedPath.getResolvedPath());
|
|
68
|
+
this.checkResponse(path, response);
|
|
69
|
+
return response.json();
|
|
70
|
+
}
|
|
71
|
+
async downloadFileAsText(path) {
|
|
72
|
+
const resolvedPath = await this.resolvePath(path);
|
|
73
|
+
const response = await fetch(resolvedPath.getResolvedPath());
|
|
74
|
+
this.checkResponse(path, response);
|
|
75
|
+
return response.text();
|
|
76
|
+
}
|
|
77
|
+
async uploadFile(path, content, options) {
|
|
78
|
+
throw new Error('ViteDevStorageProvider does not support uploading files.');
|
|
79
|
+
}
|
|
80
|
+
async listFiles(path, recursive, includeHiddenFiles) {
|
|
81
|
+
try {
|
|
82
|
+
const manifest = await this.loadManifest();
|
|
83
|
+
const initialPath = path.initialPath;
|
|
84
|
+
const targetPath = this.normalizePathForManifest(initialPath);
|
|
85
|
+
// Determine which file collection to use
|
|
86
|
+
// Paths without prefix are treated as engine assets
|
|
87
|
+
const isEngineAsset = initialPath.startsWith(ENGINE.ENGINE_PATH_PREFIX);
|
|
88
|
+
const isProjectAsset = initialPath.startsWith(ENGINE.PROJECT_PATH_PREFIX);
|
|
89
|
+
if (!isEngineAsset && !isProjectAsset) {
|
|
90
|
+
throw new Error(`Invalid path: ${path}`);
|
|
91
|
+
}
|
|
92
|
+
const fileCollection = isEngineAsset ? manifest.engineFiles : manifest.projectFiles;
|
|
93
|
+
const files = [];
|
|
94
|
+
const directories = [];
|
|
95
|
+
if (recursive) {
|
|
96
|
+
// For recursive listing, include all files that start with the target path
|
|
97
|
+
for (const [dirPath, items] of Object.entries(fileCollection)) {
|
|
98
|
+
if (dirPath === targetPath || dirPath.startsWith(targetPath + '/') || (targetPath === '' && !dirPath.includes('/'))) {
|
|
99
|
+
for (const item of items) {
|
|
100
|
+
const engineFileItem = this.convertToEngineFileItem(item, isEngineAsset);
|
|
101
|
+
if (!includeHiddenFiles && item.name.startsWith('.')) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (item.isDirectory) {
|
|
105
|
+
directories.push(engineFileItem);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
files.push(engineFileItem);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// For non-recursive listing, only include direct children
|
|
116
|
+
const directItems = fileCollection[targetPath] || [];
|
|
117
|
+
for (const item of directItems) {
|
|
118
|
+
const engineFileItem = this.convertToEngineFileItem(item, isEngineAsset);
|
|
119
|
+
if (!includeHiddenFiles && item.name.startsWith('.')) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Only include direct children (not nested)
|
|
123
|
+
const itemDirPath = item.path.substring(0, item.path.lastIndexOf('/'));
|
|
124
|
+
const normalizedItemDirPath = itemDirPath === '.' || itemDirPath === '' ? '' : itemDirPath;
|
|
125
|
+
if (normalizedItemDirPath === targetPath) {
|
|
126
|
+
if (item.isDirectory) {
|
|
127
|
+
directories.push(engineFileItem);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
files.push(engineFileItem);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { files, directories };
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.warn(`Failed to list files for path ${path.initialPath}:`, error);
|
|
139
|
+
return { files: [], directories: [] };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async exists(path) {
|
|
143
|
+
try {
|
|
144
|
+
const resolvedPath = await this.resolvePath(path);
|
|
145
|
+
const response = await fetch(resolvedPath.getResolvedPath(), { method: 'HEAD' });
|
|
146
|
+
return response.ok;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async buildCurrentProject(runTsc) {
|
|
153
|
+
// For development, we don't need to build the project
|
|
154
|
+
// Vite handles the compilation
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
normalizePathForManifest(pathStr) {
|
|
158
|
+
// Remove @project/ or @engine/ prefix
|
|
159
|
+
let normalized = pathStr.replace(ENGINE.PROJECT_PATH_PREFIX, '').replace(ENGINE.ENGINE_PATH_PREFIX, '');
|
|
160
|
+
// Remove leading slash if present
|
|
161
|
+
if (normalized.startsWith('/')) {
|
|
162
|
+
normalized = normalized.substring(1);
|
|
163
|
+
}
|
|
164
|
+
// Remove trailing slash if present
|
|
165
|
+
if (normalized.endsWith('/')) {
|
|
166
|
+
normalized = normalized.substring(0, normalized.length - 1);
|
|
167
|
+
}
|
|
168
|
+
return normalized;
|
|
169
|
+
}
|
|
170
|
+
convertToEngineFileItem(manifestItem, isEngineAsset) {
|
|
171
|
+
const prefix = isEngineAsset ? ENGINE.ENGINE_PATH_PREFIX : ENGINE.PROJECT_PATH_PREFIX;
|
|
172
|
+
const path = `${prefix}/${manifestItem.path}`;
|
|
173
|
+
return {
|
|
174
|
+
name: manifestItem.name,
|
|
175
|
+
path: path,
|
|
176
|
+
absolutePath: path,
|
|
177
|
+
size: manifestItem.size,
|
|
178
|
+
modifiedTime: new Date(manifestItem.modifiedTime),
|
|
179
|
+
isDirectory: manifestItem.isDirectory,
|
|
180
|
+
contentType: manifestItem.contentType
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
checkResponse(path, response) {
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
throw new Error(`Failed to fetch ${path.initialPath}: ${response.status} ${response.statusText}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { SCENE_EXTENSION } from '../const.js';
|
|
4
|
+
import { loadWorld } from '../mcp/utils.js';
|
|
5
|
+
import { mockBrowserEnvironment } from '../mock.js';
|
|
6
|
+
// Mock browser environment as required by the engine
|
|
7
|
+
mockBrowserEnvironment();
|
|
8
|
+
async function findGenesysSceneFiles(dir) {
|
|
9
|
+
const sceneFiles = [];
|
|
10
|
+
try {
|
|
11
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
12
|
+
for (const item of items) {
|
|
13
|
+
const fullPath = path.join(dir, item.name);
|
|
14
|
+
if (item.isDirectory()) {
|
|
15
|
+
// Recursively search subdirectories
|
|
16
|
+
const subFiles = await findGenesysSceneFiles(fullPath);
|
|
17
|
+
sceneFiles.push(...subFiles);
|
|
18
|
+
}
|
|
19
|
+
else if (item.isFile() && item.name.endsWith(SCENE_EXTENSION)) {
|
|
20
|
+
sceneFiles.push(fullPath);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error(`Error reading directory ${dir}:`, error);
|
|
26
|
+
}
|
|
27
|
+
return sceneFiles;
|
|
28
|
+
}
|
|
29
|
+
async function updateSceneFile(sceneFilePath) {
|
|
30
|
+
console.log(`Processing: ${sceneFilePath}`);
|
|
31
|
+
try {
|
|
32
|
+
// Use the loadWorld utility with proper disposal using 'using' keyword
|
|
33
|
+
using worldResource = await loadWorld(sceneFilePath, {
|
|
34
|
+
readonly: false, // Allow saving changes
|
|
35
|
+
skipLoadingGLTF: true // Skip GLTF loading for faster processing
|
|
36
|
+
});
|
|
37
|
+
console.log(`✓ Successfully updated: ${sceneFilePath}`);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(`✗ Failed to update ${sceneFilePath}:`, error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function main() {
|
|
44
|
+
console.log('Searching for .genesys-scene files in src folder...');
|
|
45
|
+
const srcDir = path.join(process.cwd(), 'src');
|
|
46
|
+
if (!fs.existsSync(srcDir)) {
|
|
47
|
+
console.error('src directory not found');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const sceneFiles = await findGenesysSceneFiles(srcDir);
|
|
51
|
+
if (sceneFiles.length === 0) {
|
|
52
|
+
console.log('No .genesys-scene files found in src folder');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.log(`Found ${sceneFiles.length} .genesys-scene files:`);
|
|
56
|
+
sceneFiles.forEach(file => console.log(` - ${path.relative(process.cwd(), file)}`));
|
|
57
|
+
console.log('\nUpdating scene files...');
|
|
58
|
+
// Process each scene file
|
|
59
|
+
for (const sceneFile of sceneFiles) {
|
|
60
|
+
await updateSceneFile(sceneFile);
|
|
61
|
+
}
|
|
62
|
+
console.log('\nScene update process completed!');
|
|
63
|
+
}
|
|
64
|
+
main().catch(error => {
|
|
65
|
+
console.error('Script failed:', error);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|