@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,135 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
import { readdir, readFile, stat, writeFile } from 'fs/promises';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Recursively finds all TypeScript files in a directory
|
|
8
|
+
*/
|
|
9
|
+
async function findTsFiles(dir: string): Promise<string[]> {
|
|
10
|
+
const files: string[] = [];
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const entries = await readdir(dir);
|
|
14
|
+
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const fullPath = join(dir, entry);
|
|
17
|
+
const stats = await stat(fullPath);
|
|
18
|
+
|
|
19
|
+
if (stats.isDirectory()) {
|
|
20
|
+
const subFiles = await findTsFiles(fullPath);
|
|
21
|
+
files.push(...subFiles);
|
|
22
|
+
} else if (entry.endsWith('.ts') || entry.endsWith('.tsx')) {
|
|
23
|
+
files.push(fullPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.warn(`Warning: Could not read directory ${dir}:`, error);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return files;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Removes comments from TypeScript code using regex
|
|
35
|
+
*/
|
|
36
|
+
function removeComments(code: string): { cleaned: string; hadComments: boolean } {
|
|
37
|
+
const originalLength = code.length;
|
|
38
|
+
|
|
39
|
+
// Remove single-line comments (// comments)
|
|
40
|
+
// This regex handles // comments but preserves URLs and string literals
|
|
41
|
+
let cleaned = code.replace(/^(\s*)\/\/.*$/gm, '$1');
|
|
42
|
+
|
|
43
|
+
// Remove multi-line comments (/* ... */ and /** ... */)
|
|
44
|
+
// This regex handles nested quotes and preserves strings
|
|
45
|
+
cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
46
|
+
|
|
47
|
+
// Clean up multiple consecutive empty lines (replace with single empty line)
|
|
48
|
+
cleaned = cleaned.replace(/\n\s*\n\s*\n/g, '\n\n');
|
|
49
|
+
|
|
50
|
+
// Trim trailing whitespace on each line
|
|
51
|
+
cleaned = cleaned.replace(/[ \t]+$/gm, '');
|
|
52
|
+
|
|
53
|
+
const hadComments = cleaned.length !== originalLength || cleaned !== code;
|
|
54
|
+
|
|
55
|
+
return { cleaned, hadComments };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Removes comments from a TypeScript file
|
|
60
|
+
*/
|
|
61
|
+
async function removeCommentsFromFile(filePath: string): Promise<boolean> {
|
|
62
|
+
try {
|
|
63
|
+
const content = await readFile(filePath, 'utf8');
|
|
64
|
+
const { cleaned, hadComments } = removeComments(content);
|
|
65
|
+
|
|
66
|
+
if (!hadComments) {
|
|
67
|
+
return false; // No comments to remove
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await writeFile(filePath, cleaned, 'utf8');
|
|
71
|
+
return true;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(`Error processing file ${filePath}:`, error);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function main() {
|
|
79
|
+
const engineDir = '.engine';
|
|
80
|
+
|
|
81
|
+
console.log(`Searching for TypeScript files in ${engineDir}...`);
|
|
82
|
+
console.log(`Current working directory: ${process.cwd()}`);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const tsFiles = await findTsFiles(engineDir);
|
|
86
|
+
|
|
87
|
+
console.log(`Found ${tsFiles.length} TypeScript files.`);
|
|
88
|
+
if (tsFiles.length > 0) {
|
|
89
|
+
console.log('First few files:');
|
|
90
|
+
tsFiles.slice(0, 5).forEach(file => console.log(` - ${file}`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (tsFiles.length === 0) {
|
|
94
|
+
console.log('No TypeScript files found in .engine folder.');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let processedCount = 0;
|
|
99
|
+
let modifiedCount = 0;
|
|
100
|
+
|
|
101
|
+
for (const filePath of tsFiles) {
|
|
102
|
+
console.log(`Processing: ${filePath}`);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const wasModified = await removeCommentsFromFile(filePath);
|
|
106
|
+
processedCount++;
|
|
107
|
+
|
|
108
|
+
if (wasModified) {
|
|
109
|
+
modifiedCount++;
|
|
110
|
+
console.log(' ✓ Comments removed');
|
|
111
|
+
} else {
|
|
112
|
+
console.log(' - No comments found');
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(` ✗ Error: ${error}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log('\nCompleted:');
|
|
120
|
+
console.log(`- Files processed: ${processedCount}`);
|
|
121
|
+
console.log(`- Files modified: ${modifiedCount}`);
|
|
122
|
+
console.log(`- Files skipped: ${processedCount - modifiedCount}`);
|
|
123
|
+
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Error:', error);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Always run main if this file is executed directly
|
|
131
|
+
main().catch((error) => {
|
|
132
|
+
console.error('Unexpected error:', error);
|
|
133
|
+
console.error('Stack trace:', error.stack);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
});
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import * as ENGINE from '@gnsx/genesys.js';
|
|
5
|
+
import { AssetPath, AssetPathEncodeState } from '@gnsx/genesys.js';
|
|
6
|
+
|
|
7
|
+
import { getProjectRoot } from './common.js';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export class StorageProvider implements ENGINE.IStorageProvider {
|
|
11
|
+
public async resolvePath(assetPath: AssetPath, expiry?: number): Promise<AssetPath> {
|
|
12
|
+
if (assetPath.isResolved()) {
|
|
13
|
+
return assetPath;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
assetPath.resolvePath(this.getFullPath(assetPath.initialPath), AssetPathEncodeState.Decoded);
|
|
17
|
+
return assetPath;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public getFullPath(filePath: string): string {
|
|
21
|
+
let fullPath = filePath;
|
|
22
|
+
let rootPath = undefined;
|
|
23
|
+
|
|
24
|
+
if (filePath.startsWith(ENGINE.PROJECT_PATH_PREFIX)) {
|
|
25
|
+
filePath = filePath.slice(ENGINE.PROJECT_PATH_PREFIX.length);
|
|
26
|
+
rootPath = getProjectRoot();
|
|
27
|
+
}
|
|
28
|
+
else if (filePath.startsWith(ENGINE.ENGINE_PATH_PREFIX)) {
|
|
29
|
+
filePath = filePath.slice(ENGINE.ENGINE_PATH_PREFIX.length);
|
|
30
|
+
rootPath = path.join(getProjectRoot(), 'node_modules', 'genesys.js');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (rootPath !== undefined) {
|
|
34
|
+
fullPath = AssetPath.join(rootPath, filePath);
|
|
35
|
+
}
|
|
36
|
+
return fullPath;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public async downloadFileAsBuffer(
|
|
40
|
+
assetPath: AssetPath,
|
|
41
|
+
): Promise<ArrayBuffer> {
|
|
42
|
+
assetPath = await this.resolvePath(assetPath);
|
|
43
|
+
const fullPath = getResolvedPath(assetPath);
|
|
44
|
+
if (!fs.existsSync(fullPath)) {
|
|
45
|
+
return new ArrayBuffer(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const data = fs.readFileSync(fullPath);
|
|
49
|
+
const arrayBuffer = data.buffer.slice(
|
|
50
|
+
data.byteOffset,
|
|
51
|
+
data.byteOffset + data.byteLength
|
|
52
|
+
);
|
|
53
|
+
return arrayBuffer;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public async downloadFileAsJson<T>(assetPath: AssetPath): Promise<T> {
|
|
57
|
+
assetPath = await this.resolvePath(assetPath);
|
|
58
|
+
const fullPath = getResolvedPath(assetPath);
|
|
59
|
+
if (!fs.existsSync(fullPath)) {
|
|
60
|
+
return {} as T;
|
|
61
|
+
}
|
|
62
|
+
return JSON.parse(fs.readFileSync(fullPath, 'utf8'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async downloadFileAsText(assetPath: AssetPath): Promise<string> {
|
|
66
|
+
assetPath = await this.resolvePath(assetPath);
|
|
67
|
+
const fullPath = getResolvedPath(assetPath);
|
|
68
|
+
if (!fs.existsSync(fullPath)) {
|
|
69
|
+
return '';
|
|
70
|
+
}
|
|
71
|
+
return fs.readFileSync(fullPath, 'utf8');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public async exists(assetPath: AssetPath): Promise<boolean> {
|
|
75
|
+
assetPath = await this.resolvePath(assetPath);
|
|
76
|
+
const fullPath = getResolvedPath(assetPath);
|
|
77
|
+
return fs.existsSync(fullPath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async buildCurrentProject(runTsc: boolean): Promise<boolean> {
|
|
81
|
+
throw new Error('Not implemented');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public async uploadFile(assetPath: AssetPath, content: Blob | File | string | ArrayBuffer, options?: ENGINE.FileUploadOptions): Promise<{
|
|
85
|
+
path: string;
|
|
86
|
+
name: string;
|
|
87
|
+
}>
|
|
88
|
+
{
|
|
89
|
+
assetPath = await this.resolvePath(assetPath);
|
|
90
|
+
const fullPath = getResolvedPath(assetPath);
|
|
91
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
92
|
+
|
|
93
|
+
if (typeof content === 'string') {
|
|
94
|
+
fs.writeFileSync(fullPath, content);
|
|
95
|
+
} else {
|
|
96
|
+
throw new Error(`Unsupported content type: ${typeof content}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
path: fullPath,
|
|
101
|
+
name: path.basename(fullPath)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public async deleteFile(assetPath: AssetPath): Promise<void> {
|
|
106
|
+
assetPath = await this.resolvePath(assetPath);
|
|
107
|
+
const fullPath = getResolvedPath(assetPath);
|
|
108
|
+
if (fs.existsSync(fullPath)) {
|
|
109
|
+
fs.unlinkSync(fullPath);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public async listFiles(assetPath: AssetPath, recursive?: boolean, includeHiddenFiles?: boolean): Promise<ENGINE.FileListResult> {
|
|
114
|
+
assetPath = await this.resolvePath(assetPath);
|
|
115
|
+
const fullPath = getResolvedPath(assetPath);
|
|
116
|
+
|
|
117
|
+
if (!fs.existsSync(fullPath)) {
|
|
118
|
+
return { files: [], directories: [] };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const files: ENGINE.FileItem[] = [];
|
|
122
|
+
const directories: ENGINE.FileItem[] = [];
|
|
123
|
+
|
|
124
|
+
const processDirectory = (dirPath: string, basePath: string = '') => {
|
|
125
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
126
|
+
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
// Skip hidden files if not requested
|
|
129
|
+
if (!includeHiddenFiles && entry.name.startsWith('.')) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const fullEntryPath = path.join(dirPath, entry.name);
|
|
134
|
+
const relativePath = basePath ? path.join(basePath, entry.name) : entry.name;
|
|
135
|
+
const stats = fs.statSync(fullEntryPath);
|
|
136
|
+
|
|
137
|
+
const fileItem: ENGINE.FileItem = {
|
|
138
|
+
name: entry.name,
|
|
139
|
+
path: relativePath,
|
|
140
|
+
absolutePath: fullEntryPath,
|
|
141
|
+
size: stats.size,
|
|
142
|
+
modifiedTime: stats.mtime,
|
|
143
|
+
isDirectory: entry.isDirectory()
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (entry.isDirectory()) {
|
|
147
|
+
directories.push(fileItem);
|
|
148
|
+
|
|
149
|
+
// Recursively process subdirectories if requested
|
|
150
|
+
if (recursive) {
|
|
151
|
+
processDirectory(fullEntryPath, relativePath);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
files.push(fileItem);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Check if the path is a directory
|
|
160
|
+
const stats = fs.statSync(fullPath);
|
|
161
|
+
if (stats.isDirectory()) {
|
|
162
|
+
processDirectory(fullPath);
|
|
163
|
+
} else {
|
|
164
|
+
// If it's a file, return just that file
|
|
165
|
+
const fileItem: ENGINE.FileItem = {
|
|
166
|
+
name: path.basename(fullPath),
|
|
167
|
+
path: path.basename(fullPath),
|
|
168
|
+
absolutePath: fullPath,
|
|
169
|
+
size: stats.size,
|
|
170
|
+
modifiedTime: stats.mtime,
|
|
171
|
+
isDirectory: false
|
|
172
|
+
};
|
|
173
|
+
files.push(fileItem);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { files, directories };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function getResolvedPath(assetPath: ENGINE.AssetPath): string {
|
|
181
|
+
return assetPath.getResolvedPath(false);
|
|
182
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import Ajv, { type ErrorObject } from 'ajv';
|
|
5
|
+
|
|
6
|
+
import { getProjectRoot } from './common.js';
|
|
7
|
+
|
|
8
|
+
interface ValidationError {
|
|
9
|
+
file: string;
|
|
10
|
+
errors: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function findPrefabFiles(dir: string, prefabFiles: string[] = []): string[] {
|
|
14
|
+
const files = fs.readdirSync(dir);
|
|
15
|
+
|
|
16
|
+
for (const file of files) {
|
|
17
|
+
const filePath = path.join(dir, file);
|
|
18
|
+
const stat = fs.statSync(filePath);
|
|
19
|
+
|
|
20
|
+
if (stat.isDirectory()) {
|
|
21
|
+
// Skip node_modules and other common directories that shouldn't contain prefabs
|
|
22
|
+
if (file === 'node_modules' || file === 'dist' || file === '.git') {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
findPrefabFiles(filePath, prefabFiles);
|
|
26
|
+
} else if (file.endsWith('.prefab.json')) {
|
|
27
|
+
prefabFiles.push(filePath);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return prefabFiles;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function validatePrefabs() {
|
|
35
|
+
const projectRoot = getProjectRoot();
|
|
36
|
+
const schemaPath = path.join(__dirname, 'prefab.schema.json');
|
|
37
|
+
|
|
38
|
+
// Load the schema
|
|
39
|
+
let schema: any;
|
|
40
|
+
try {
|
|
41
|
+
const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
|
|
42
|
+
schema = JSON.parse(schemaContent);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(`❌ Failed to load schema from ${schemaPath}`);
|
|
45
|
+
console.error(error);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Initialize Ajv
|
|
50
|
+
const ajv = new (Ajv as any)({
|
|
51
|
+
allErrors: true,
|
|
52
|
+
validateSchema: false // Don't validate the schema itself
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Process $ref in the schema to use proper format
|
|
56
|
+
const processedSchema = JSON.parse(JSON.stringify(schema), (key, value) => {
|
|
57
|
+
if (key === '$ref' && typeof value === 'string' && !value.startsWith('#')) {
|
|
58
|
+
return `#/definitions/${value}`;
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const validate = ajv.compile(processedSchema);
|
|
64
|
+
|
|
65
|
+
// Find all prefab files
|
|
66
|
+
const prefabFiles = findPrefabFiles(projectRoot);
|
|
67
|
+
|
|
68
|
+
if (prefabFiles.length === 0) {
|
|
69
|
+
console.log('⚠️ No prefab files found in the project.');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(`Found ${prefabFiles.length} prefab file(s) to validate:\n`);
|
|
74
|
+
|
|
75
|
+
const validationErrors: ValidationError[] = [];
|
|
76
|
+
let validCount = 0;
|
|
77
|
+
|
|
78
|
+
// Validate each prefab file
|
|
79
|
+
for (const prefabPath of prefabFiles) {
|
|
80
|
+
const relativePath = path.relative(projectRoot, prefabPath);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const prefabContent = fs.readFileSync(prefabPath, 'utf-8');
|
|
84
|
+
const prefabData = JSON.parse(prefabContent);
|
|
85
|
+
|
|
86
|
+
const valid = validate(prefabData);
|
|
87
|
+
|
|
88
|
+
if (valid) {
|
|
89
|
+
console.log(`✅ ${relativePath}`);
|
|
90
|
+
validCount++;
|
|
91
|
+
} else {
|
|
92
|
+
console.log(`❌ ${relativePath}`);
|
|
93
|
+
const errors = validate.errors?.map((err: ErrorObject) => {
|
|
94
|
+
const path = (err as any).instancePath ?? '/';
|
|
95
|
+
const message = err.message ?? 'unknown error';
|
|
96
|
+
return ` - ${path}: ${message}`;
|
|
97
|
+
}) ?? [];
|
|
98
|
+
validationErrors.push({
|
|
99
|
+
file: relativePath,
|
|
100
|
+
errors
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.log(`❌ ${relativePath} (parse error)`);
|
|
105
|
+
validationErrors.push({
|
|
106
|
+
file: relativePath,
|
|
107
|
+
errors: [`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Print summary
|
|
113
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
114
|
+
console.log('Validation Summary:');
|
|
115
|
+
console.log(` Total files: ${prefabFiles.length}`);
|
|
116
|
+
console.log(` Valid: ${validCount}`);
|
|
117
|
+
console.log(` Invalid: ${validationErrors.length}`);
|
|
118
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
119
|
+
|
|
120
|
+
// Print detailed errors if any
|
|
121
|
+
if (validationErrors.length > 0) {
|
|
122
|
+
console.log('Validation Errors:\n');
|
|
123
|
+
for (const { file, errors } of validationErrors) {
|
|
124
|
+
console.log(`${file}:`);
|
|
125
|
+
for (const error of errors) {
|
|
126
|
+
console.log(error);
|
|
127
|
+
}
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
process.exit(1);
|
|
131
|
+
} else {
|
|
132
|
+
console.log('🎉 All prefab files are valid!');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Run validation
|
|
137
|
+
validatePrefabs();
|
|
138
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// which items will be copied to the new project, includes files and folders
|
|
2
|
+
export const sharedTemplateItems: string[] = [
|
|
3
|
+
'.cursor',
|
|
4
|
+
'.vscode',
|
|
5
|
+
'scripts/genesys',
|
|
6
|
+
'gitignore', // npm excludes .gitignore files from packages, so we rename it when copying
|
|
7
|
+
'.gitattributes',
|
|
8
|
+
'.cursorignore',
|
|
9
|
+
'eslint.config.js',
|
|
10
|
+
'tsconfig.json',
|
|
11
|
+
'AGENTS.md',
|
|
12
|
+
'CLAUDE.md',
|
|
13
|
+
'index.html',
|
|
14
|
+
'vite.config.ts',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
// which items will be deleted from the project, if exists
|
|
18
|
+
export const deletedTemplateItems: string[] = [
|
|
19
|
+
'.cursorrules'
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export * as ENGINE from '@gnsx/genesys.js';
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$version": 0,
|
|
3
|
+
"class": "ENGINE.World",
|
|
4
|
+
"uuid": "c0ae85792bc3b946",
|
|
5
|
+
"ctor": {
|
|
6
|
+
"backgroundColor": 3026478,
|
|
7
|
+
"navigationOptions": {
|
|
8
|
+
"engine": "recast-navigation",
|
|
9
|
+
"debug": false,
|
|
10
|
+
"generateOnStartUp": false
|
|
11
|
+
},
|
|
12
|
+
"physicsOptions": {
|
|
13
|
+
"gravity": [
|
|
14
|
+
0,
|
|
15
|
+
-9.81,
|
|
16
|
+
0,
|
|
17
|
+
"v"
|
|
18
|
+
],
|
|
19
|
+
"engine": "rapier"
|
|
20
|
+
},
|
|
21
|
+
"useManifold": true
|
|
22
|
+
},
|
|
23
|
+
"actors": [
|
|
24
|
+
{
|
|
25
|
+
"uuid": "9a86d389088b361c",
|
|
26
|
+
"class": "ENGINE.Actor",
|
|
27
|
+
"properties": {
|
|
28
|
+
"editorData": {
|
|
29
|
+
"displayName": "Directional Light",
|
|
30
|
+
"hidden": false
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"ctor": {
|
|
34
|
+
"rootComponent": {
|
|
35
|
+
"class": "ENGINE.DirectionalLightComponent",
|
|
36
|
+
"uuid": "cfe05433-9edc-4dfe-a535-c71f33e92d78",
|
|
37
|
+
"ctor": {
|
|
38
|
+
"color": 16777215,
|
|
39
|
+
"intensity": 1,
|
|
40
|
+
"castShadow": true,
|
|
41
|
+
"shadowMapSize": 2048,
|
|
42
|
+
"shadowBias": 0,
|
|
43
|
+
"shadowNormalBias": 0,
|
|
44
|
+
"shadowNear": 0.1,
|
|
45
|
+
"shadowFar": 100
|
|
46
|
+
},
|
|
47
|
+
"properties": {
|
|
48
|
+
"position": [
|
|
49
|
+
10,
|
|
50
|
+
50,
|
|
51
|
+
-10,
|
|
52
|
+
"v"
|
|
53
|
+
],
|
|
54
|
+
"castShadow": true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"uuid": "9d428f2a16e5374a",
|
|
61
|
+
"class": "ENGINE.Actor",
|
|
62
|
+
"properties": {
|
|
63
|
+
"editorData": {
|
|
64
|
+
"displayName": "Ground",
|
|
65
|
+
"hidden": false
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"ctor": {
|
|
69
|
+
"rootComponent": {
|
|
70
|
+
"class": "ENGINE.MeshComponent",
|
|
71
|
+
"uuid": "71caea24-62d7-4e45-a76e-4c7519de2c3c",
|
|
72
|
+
"ctor": {
|
|
73
|
+
"geometry": {
|
|
74
|
+
"class": "THREE.BoxGeometry",
|
|
75
|
+
"ctor": [
|
|
76
|
+
500,
|
|
77
|
+
0.1,
|
|
78
|
+
500
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"material": {
|
|
82
|
+
"@external": "DefaultMaterial"
|
|
83
|
+
},
|
|
84
|
+
"uvScaleTilesPerUnit": 0.2,
|
|
85
|
+
"physicsOptions": {
|
|
86
|
+
"enabled": true,
|
|
87
|
+
"motionType": "static",
|
|
88
|
+
"collisionProfile": "BlockAll"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"properties": {
|
|
92
|
+
"position": [
|
|
93
|
+
0,
|
|
94
|
+
-0.9,
|
|
95
|
+
0,
|
|
96
|
+
"v"
|
|
97
|
+
],
|
|
98
|
+
"receiveShadow": true
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"uuid": "b87cbc5e60a2e54c",
|
|
105
|
+
"class": "ENGINE.PlayerStart",
|
|
106
|
+
"properties": {
|
|
107
|
+
"editorData": {
|
|
108
|
+
"displayName": "Player Start",
|
|
109
|
+
"hidden": false
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"ctor": {
|
|
113
|
+
"rootComponent": {
|
|
114
|
+
"class": "ENGINE.SceneComponent",
|
|
115
|
+
"uuid": "b4d5f8f7-2512-45e1-9157-c7ff6772402d",
|
|
116
|
+
"ctor": {},
|
|
117
|
+
"properties": {
|
|
118
|
+
"position": [
|
|
119
|
+
0,
|
|
120
|
+
0.9,
|
|
121
|
+
0,
|
|
122
|
+
"v"
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"uuid": "0ba1f4677e8370d1",
|
|
130
|
+
"class": "ENGINE.Actor",
|
|
131
|
+
"properties": {
|
|
132
|
+
"editorData": {
|
|
133
|
+
"displayName": "Skybox",
|
|
134
|
+
"hidden": false
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"ctor": {
|
|
138
|
+
"rootComponent": {
|
|
139
|
+
"class": "ENGINE.SceneComponent",
|
|
140
|
+
"uuid": "195e88df-73ff-4f4b-82ae-7fb58671463d",
|
|
141
|
+
"ctor": {},
|
|
142
|
+
"properties": {},
|
|
143
|
+
"children": [
|
|
144
|
+
{
|
|
145
|
+
"class": "ENGINE.SkyboxComponent",
|
|
146
|
+
"uuid": "f7e33ae7d5ac74f9",
|
|
147
|
+
"ctor": {
|
|
148
|
+
"textureUrl": "@engine/assets/textures/skybox/citrus_orchard_road_puresky_2k.hdr",
|
|
149
|
+
"width": 2048,
|
|
150
|
+
"height": 1024,
|
|
151
|
+
"bottomColor": "#E6F3FF",
|
|
152
|
+
"middleColor": "#4A90E2",
|
|
153
|
+
"topColor": "#0F1B3C",
|
|
154
|
+
"envMapIntensity": 1
|
|
155
|
+
},
|
|
156
|
+
"properties": {}
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"properties": {
|
|
164
|
+
"editorData": {}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
import * as ENGINE from '@gnsx/genesys.js';
|
|
3
|
+
import * as THREE from 'three';
|
|
4
|
+
|
|
5
|
+
import { FirstPersonPlayer } from './player.js';
|
|
6
|
+
import './auto-imports.js';
|
|
7
|
+
|
|
8
|
+
class FirstPersonGame extends ENGINE.BaseGameLoop {
|
|
9
|
+
private pawn: FirstPersonPlayer | null = null;
|
|
10
|
+
private controller: ENGINE.PlayerController | null = null;
|
|
11
|
+
|
|
12
|
+
protected override createLoadingScreen(): ENGINE.ILoadingScreen | null {
|
|
13
|
+
// enable the default loading screen
|
|
14
|
+
return new ENGINE.DefaultLoadingScreen();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
protected override async preStart(): Promise<void> {
|
|
18
|
+
// default spawn location
|
|
19
|
+
const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT / 2, 0);
|
|
20
|
+
|
|
21
|
+
// now create the pawn
|
|
22
|
+
this.pawn = FirstPersonPlayer.create({ position });
|
|
23
|
+
|
|
24
|
+
// create the controller and possess the pawn
|
|
25
|
+
this.controller = ENGINE.PlayerController.create();
|
|
26
|
+
this.controller.possess(this.pawn);
|
|
27
|
+
|
|
28
|
+
// add both to the world
|
|
29
|
+
this.world.addActors(this.pawn, this.controller);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function main(container: HTMLElement, gameId: string): ENGINE.IGameLoop {
|
|
34
|
+
const game = new FirstPersonGame(container, {
|
|
35
|
+
...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
|
|
36
|
+
gameId
|
|
37
|
+
});
|
|
38
|
+
return game;
|
|
39
|
+
}
|