@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,261 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { app, dialog } from 'electron';
|
|
4
|
+
import * as ENGINE from 'genesys.js';
|
|
5
|
+
import { copySharedTemplateToProject, createGenesysProjectFile, getEngineVersion, getProjectFolderAndFile, getProjectNameFromPath, getProjectRoot, IgnoredFiles, projectFiles, runCommandAsync } from '../../../core/index.js';
|
|
6
|
+
import { getTemplatePath as getTemplatePathImpl } from '../../../core/tools/new-project.js';
|
|
7
|
+
import { deletedTemplateItems, sharedTemplateItems } from '../../../templates/src/index.js';
|
|
8
|
+
import { logger } from '../logging.js';
|
|
9
|
+
import { mainWindow } from '../main.js';
|
|
10
|
+
import { DefaultGameFilePath, } from './const.js';
|
|
11
|
+
function getTemplatePath() {
|
|
12
|
+
return getTemplatePathImpl(app.isPackaged, process.resourcesPath, getProjectRoot());
|
|
13
|
+
}
|
|
14
|
+
async function updateProject(projectPath, onBeginVerifyProject, onEndVerifyProject, onBeginUpdateProject, onEndUpdateProject) {
|
|
15
|
+
try {
|
|
16
|
+
onBeginVerifyProject();
|
|
17
|
+
const projectName = getProjectNameFromPath(projectPath);
|
|
18
|
+
const expectedPackageJson = projectFiles.packageJson;
|
|
19
|
+
const projectPackageJsonPath = path.join(projectPath, 'package.json');
|
|
20
|
+
if (!fs.existsSync(projectPackageJsonPath)) {
|
|
21
|
+
onEndVerifyProject();
|
|
22
|
+
throw new Error(`Missing ${projectPackageJsonPath}`);
|
|
23
|
+
}
|
|
24
|
+
const updateItems = [];
|
|
25
|
+
let projectPackageJson;
|
|
26
|
+
try {
|
|
27
|
+
projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`Failed to parse package.json: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
function updateSettings(key) {
|
|
33
|
+
const expectedSettings = expectedPackageJson[key];
|
|
34
|
+
const currentSettings = projectPackageJson[key] ?? {};
|
|
35
|
+
for (const [name, expectedValue] of Object.entries(expectedSettings)) {
|
|
36
|
+
const currentValue = currentSettings[name];
|
|
37
|
+
if (currentValue !== expectedValue) {
|
|
38
|
+
updateItems.push(`Update ${name} from ${currentValue} to ${expectedValue}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!projectPackageJson.name) {
|
|
43
|
+
updateItems.push(`Set project name to ${projectName}`);
|
|
44
|
+
projectPackageJson.name = projectName;
|
|
45
|
+
}
|
|
46
|
+
if (!projectPackageJson.version) {
|
|
47
|
+
updateItems.push(`Set project version to ${expectedPackageJson.version}`);
|
|
48
|
+
projectPackageJson.version = expectedPackageJson.version;
|
|
49
|
+
}
|
|
50
|
+
updateSettings('dependencies');
|
|
51
|
+
updateSettings('devDependencies');
|
|
52
|
+
updateSettings('scripts');
|
|
53
|
+
for (const deletedItem of deletedTemplateItems) {
|
|
54
|
+
const filePath = path.join(projectPath, deletedItem);
|
|
55
|
+
if (fs.existsSync(filePath)) {
|
|
56
|
+
updateItems.push(`Delete ${deletedItem}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// gather all the files that are not in the project source
|
|
60
|
+
const templatePackagePath = getTemplatePath();
|
|
61
|
+
for (const sharedItem of sharedTemplateItems) {
|
|
62
|
+
const sourcePath = path.join(templatePackagePath, sharedItem);
|
|
63
|
+
// _gitignore is renamed to .gitignore when copied to the project
|
|
64
|
+
const destinationName = sharedItem === '_gitignore' ? '.gitignore' : sharedItem;
|
|
65
|
+
const destinatePath = path.join(projectPath, destinationName);
|
|
66
|
+
if (!fs.existsSync(sourcePath)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
if (fs.statSync(sourcePath).isDirectory()) {
|
|
71
|
+
const projectSourceFiles = fs.readdirSync(sourcePath, { recursive: true });
|
|
72
|
+
for (const file of projectSourceFiles) {
|
|
73
|
+
const sourceFilePath = path.join(sourcePath, file);
|
|
74
|
+
if (fs.statSync(sourceFilePath).isDirectory()) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const destinationFilePath = path.join(destinatePath, file);
|
|
78
|
+
if (!fs.existsSync(destinationFilePath)) {
|
|
79
|
+
updateItems.push(`Add ${file}`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const sourceContent = fs.readFileSync(sourceFilePath, 'utf8');
|
|
84
|
+
const destContent = fs.readFileSync(destinationFilePath, 'utf8');
|
|
85
|
+
if (sourceContent !== destContent) {
|
|
86
|
+
updateItems.push(`Update ${file}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
logger.log(`Warning: Failed to compare file ${file}: ${error.message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
if (!fs.existsSync(destinatePath)) {
|
|
96
|
+
updateItems.push(`Add ${destinationName}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
try {
|
|
100
|
+
const sourceContent = fs.readFileSync(sourcePath, 'utf8');
|
|
101
|
+
const destContent = fs.readFileSync(destinatePath, 'utf8');
|
|
102
|
+
if (sourceContent !== destContent) {
|
|
103
|
+
updateItems.push(`Update ${destinationName}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
logger.log(`Warning: Failed to compare file ${destinationName}: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
logger.log(`Warning: Failed to process ${destinationName}: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
onEndVerifyProject();
|
|
117
|
+
if (updateItems.length > 0) {
|
|
118
|
+
// Make dialog non-blocking by not awaiting it
|
|
119
|
+
dialog.showMessageBox(mainWindow, {
|
|
120
|
+
type: 'info',
|
|
121
|
+
buttons: ['Update', 'Ignore'],
|
|
122
|
+
title: 'Project Update Required',
|
|
123
|
+
message: 'The project requires the following updates: ',
|
|
124
|
+
detail: updateItems.join('\n'),
|
|
125
|
+
}).then(async ({ response }) => {
|
|
126
|
+
if (response === 0) {
|
|
127
|
+
onBeginUpdateProject();
|
|
128
|
+
try {
|
|
129
|
+
await performProjectUpdate(projectPath, projectPackageJson, expectedPackageJson, projectPackageJsonPath);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
logger.log(`Error updating project: ${error.message}`);
|
|
133
|
+
// dialog.showMessageBox(mainWindow!, {
|
|
134
|
+
// type: 'error',
|
|
135
|
+
// buttons: ['OK'],
|
|
136
|
+
// title: 'Project Update Failed',
|
|
137
|
+
// message: 'Failed to update the project',
|
|
138
|
+
// detail: (error as Error).message,
|
|
139
|
+
// }).catch((dialogError) => {
|
|
140
|
+
// logger.log(`Error showing update dialog: ${(dialogError as Error).message}`);
|
|
141
|
+
// });
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
onEndUpdateProject();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}).catch((error) => {
|
|
148
|
+
logger.log(`Error showing update dialog: ${error.message}`);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
onEndVerifyProject();
|
|
154
|
+
logger.log(`Error in updateProject: ${error.message}`);
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** Performs the actual project update operations */
|
|
159
|
+
async function performProjectUpdate(projectPath, projectPackageJson, expectedPackageJson, projectPackageJsonPath) {
|
|
160
|
+
try {
|
|
161
|
+
// Copy shared template files first
|
|
162
|
+
const templatePackagePath = getTemplatePath();
|
|
163
|
+
await copySharedTemplateToProject(projectPath, templatePackagePath, logger);
|
|
164
|
+
// Update package.json with proper merging
|
|
165
|
+
projectPackageJson.dependencies = {
|
|
166
|
+
...projectPackageJson.dependencies,
|
|
167
|
+
...expectedPackageJson.dependencies
|
|
168
|
+
};
|
|
169
|
+
projectPackageJson.devDependencies = {
|
|
170
|
+
...projectPackageJson.devDependencies,
|
|
171
|
+
...expectedPackageJson.devDependencies
|
|
172
|
+
};
|
|
173
|
+
projectPackageJson.scripts = {
|
|
174
|
+
...projectPackageJson.scripts,
|
|
175
|
+
...expectedPackageJson.scripts
|
|
176
|
+
};
|
|
177
|
+
// Write package.json with error handling
|
|
178
|
+
try {
|
|
179
|
+
fs.writeFileSync(projectPackageJsonPath, JSON.stringify(projectPackageJson, null, 2));
|
|
180
|
+
logger.log(`${projectPackageJsonPath} updated`);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new Error(`Failed to write package.json: ${error.message}`);
|
|
184
|
+
}
|
|
185
|
+
logger.log('Running pnpm install and pnpm build...');
|
|
186
|
+
// Run commands asynchronously for better performance
|
|
187
|
+
await runCommandAsync('pnpm install', projectPath, logger);
|
|
188
|
+
await runCommandAsync('pnpm build', projectPath, logger);
|
|
189
|
+
logger.log('Project updated successfully');
|
|
190
|
+
// Show success dialog
|
|
191
|
+
dialog.showMessageBox(mainWindow, {
|
|
192
|
+
type: 'info',
|
|
193
|
+
buttons: ['OK'],
|
|
194
|
+
title: 'Project Updated',
|
|
195
|
+
message: 'The project has been updated successfully',
|
|
196
|
+
}).catch((error) => {
|
|
197
|
+
logger.log(`Error showing success dialog: ${error.message}`);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
logger.log(`Error in performProjectUpdate: ${error.message}`);
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
export async function openProject(projectFileOrFolderPath, onBeginOpenProject, onEndOpenProject, onBeginVerifyProject, onEndVerifyProject, onBeginUpdateProject, onEndUpdateProject) {
|
|
206
|
+
const { folder: folderPath, file: projectFileName } = getProjectFolderAndFile(projectFileOrFolderPath, logger);
|
|
207
|
+
return await openProjectImpl(folderPath, projectFileName, onBeginOpenProject, onEndOpenProject, onBeginVerifyProject, onEndVerifyProject, onBeginUpdateProject, onEndUpdateProject);
|
|
208
|
+
}
|
|
209
|
+
async function openProjectImpl(projectFolderPath, projectFileName, onBeginOpenProject, onEndOpenProject, onBeginVerifyProject, onEndVerifyProject, onBeginUpdateProject, onEndUpdateProject) {
|
|
210
|
+
logger.log(`Opening project at ${projectFolderPath}` + (projectFileName ? ` with file ${projectFileName}` : ''));
|
|
211
|
+
if (!fs.existsSync(path.join(projectFolderPath, 'node_modules'))) {
|
|
212
|
+
logger.log('Project node_modules not found, running pnpm install...');
|
|
213
|
+
await runCommandAsync('pnpm install', projectFolderPath, logger);
|
|
214
|
+
}
|
|
215
|
+
let projectPath = path.join(projectFolderPath, projectFileName);
|
|
216
|
+
const existingFiles = fs.readdirSync(projectFolderPath).filter(file => !IgnoredFiles.includes(file));
|
|
217
|
+
if (existingFiles.length) {
|
|
218
|
+
// only check the files if the project is not empty
|
|
219
|
+
const gameFilePath = path.join(projectFolderPath, DefaultGameFilePath);
|
|
220
|
+
if (!fs.existsSync(gameFilePath)) {
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
message: `Project ${projectFolderPath} is not a valid Genesys project, missing ${gameFilePath}`,
|
|
224
|
+
path: projectFolderPath
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
onBeginOpenProject();
|
|
228
|
+
try {
|
|
229
|
+
if (!projectFileName) {
|
|
230
|
+
projectPath = await createGenesysProjectFile(projectFolderPath);
|
|
231
|
+
}
|
|
232
|
+
await updateProject(projectFolderPath, onBeginVerifyProject, onEndVerifyProject, onBeginUpdateProject, onEndUpdateProject);
|
|
233
|
+
{
|
|
234
|
+
// update the engine version in the project file
|
|
235
|
+
const projectSettings = JSON.parse(fs.readFileSync(projectPath, 'utf8'));
|
|
236
|
+
projectSettings[ENGINE.ENGINE_VERSION_KEY] = getEngineVersion();
|
|
237
|
+
fs.writeFileSync(projectPath, JSON.stringify(projectSettings, null, 2));
|
|
238
|
+
}
|
|
239
|
+
if (!fs.existsSync(path.join(projectFolderPath, 'node_modules'))) {
|
|
240
|
+
await runCommandAsync('pnpm install', projectFolderPath, logger);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
console.error(error);
|
|
245
|
+
return {
|
|
246
|
+
success: false,
|
|
247
|
+
message: `Failed to open project ${projectFolderPath}`,
|
|
248
|
+
path: projectPath,
|
|
249
|
+
error: error,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
onEndOpenProject();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
success: true,
|
|
258
|
+
message: `Project ${projectPath} opened`,
|
|
259
|
+
path: projectPath
|
|
260
|
+
};
|
|
261
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { BrowserWindow, screen } from 'electron';
|
|
2
|
+
import { AppStateKey } from '../api.js';
|
|
3
|
+
import { appState } from './state.js';
|
|
4
|
+
/** Helper function to get the display that contains the window */
|
|
5
|
+
const getDisplayForWindow = (window) => {
|
|
6
|
+
const windowBounds = window.getBounds();
|
|
7
|
+
const displays = screen.getAllDisplays();
|
|
8
|
+
return displays.find(display => {
|
|
9
|
+
const { x, y, width, height } = display.bounds;
|
|
10
|
+
const windowCenterX = windowBounds.x + windowBounds.width / 2;
|
|
11
|
+
const windowCenterY = windowBounds.y + windowBounds.height / 2;
|
|
12
|
+
return windowCenterX >= x && windowCenterX < x + width &&
|
|
13
|
+
windowCenterY >= y && windowCenterY < y + height;
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
/** Debounce helper function */
|
|
17
|
+
const debounce = (func, delay) => {
|
|
18
|
+
let timeoutId;
|
|
19
|
+
return (...args) => {
|
|
20
|
+
clearTimeout(timeoutId);
|
|
21
|
+
timeoutId = setTimeout(() => func(...args), delay);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new window with the given options.
|
|
26
|
+
* @param name - The name of the window.
|
|
27
|
+
* @param options - The options for the window.
|
|
28
|
+
* @returns The created window.
|
|
29
|
+
*/
|
|
30
|
+
export function createWindow(name, options) {
|
|
31
|
+
const defaultSize = {
|
|
32
|
+
width: options.width ?? 1920,
|
|
33
|
+
height: options.height ?? 900
|
|
34
|
+
};
|
|
35
|
+
let window;
|
|
36
|
+
const getState = () => {
|
|
37
|
+
return appState.getState(AppStateKey.WindowState) ?? { ...defaultSize, maximized: true };
|
|
38
|
+
};
|
|
39
|
+
const getCurrentPosition = () => {
|
|
40
|
+
const position = window.getPosition();
|
|
41
|
+
const size = window.getSize();
|
|
42
|
+
return {
|
|
43
|
+
x: position[0],
|
|
44
|
+
y: position[1],
|
|
45
|
+
width: size[0],
|
|
46
|
+
height: size[1],
|
|
47
|
+
maximized: window.isMaximized()
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const windowWithinBounds = (windowState, bounds) => {
|
|
51
|
+
if (windowState.x != null && windowState.y != null) {
|
|
52
|
+
return (windowState.x >= bounds.x &&
|
|
53
|
+
windowState.y >= bounds.y &&
|
|
54
|
+
windowState.x + windowState.width <= bounds.x + bounds.width &&
|
|
55
|
+
windowState.y + windowState.height <= bounds.y + bounds.height);
|
|
56
|
+
}
|
|
57
|
+
if (windowState.x === undefined && windowState.y === undefined) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
62
|
+
const resetToDefaults = () => {
|
|
63
|
+
return {
|
|
64
|
+
...defaultSize,
|
|
65
|
+
maximized: true
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
const ensureVisibleOnSomeDisplay = (windowState) => {
|
|
69
|
+
const displays = screen.getAllDisplays();
|
|
70
|
+
// If we have a saved display ID, try to find that display
|
|
71
|
+
if (windowState.displayId) {
|
|
72
|
+
const savedDisplay = displays.find(d => d.id === windowState.displayId);
|
|
73
|
+
if (savedDisplay) {
|
|
74
|
+
// Check if the window would be visible on the saved display
|
|
75
|
+
if (windowWithinBounds(windowState, savedDisplay.bounds)) {
|
|
76
|
+
return windowState;
|
|
77
|
+
}
|
|
78
|
+
// If not visible, center it on the saved display
|
|
79
|
+
return {
|
|
80
|
+
...windowState,
|
|
81
|
+
x: savedDisplay.bounds.x + (savedDisplay.bounds.width - windowState.width) / 2,
|
|
82
|
+
y: savedDisplay.bounds.y + (savedDisplay.bounds.height - windowState.height) / 2
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Fallback to existing logic
|
|
87
|
+
const visible = !!windowState.maximized || displays.some(display => {
|
|
88
|
+
return windowWithinBounds(windowState, display.bounds);
|
|
89
|
+
});
|
|
90
|
+
if (!visible) {
|
|
91
|
+
return resetToDefaults();
|
|
92
|
+
}
|
|
93
|
+
return windowState;
|
|
94
|
+
};
|
|
95
|
+
const saveState = () => {
|
|
96
|
+
const maximized = window.isMaximized();
|
|
97
|
+
const currentDisplay = getDisplayForWindow(window);
|
|
98
|
+
if (maximized) {
|
|
99
|
+
appState.setState(AppStateKey.WindowState, {
|
|
100
|
+
...getState(),
|
|
101
|
+
maximized: true,
|
|
102
|
+
displayId: currentDisplay?.id
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else if (!window.isMinimized()) {
|
|
106
|
+
const state = getCurrentPosition();
|
|
107
|
+
appState.setState(AppStateKey.WindowState, {
|
|
108
|
+
...state,
|
|
109
|
+
displayId: currentDisplay?.id
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const debouncedSaveState = debounce(saveState, 1000);
|
|
114
|
+
const { maximized, ...windowState } = ensureVisibleOnSomeDisplay(getState());
|
|
115
|
+
window = new BrowserWindow({ ...options, ...windowState });
|
|
116
|
+
if (maximized) {
|
|
117
|
+
window.maximize();
|
|
118
|
+
}
|
|
119
|
+
// Save state on window changes with debounce
|
|
120
|
+
window.on('resize', debouncedSaveState);
|
|
121
|
+
window.on('move', debouncedSaveState);
|
|
122
|
+
window.on('maximize', debouncedSaveState);
|
|
123
|
+
window.on('unmaximize', debouncedSaveState);
|
|
124
|
+
// Save immediately on close (no debounce needed)
|
|
125
|
+
window.on('close', saveState);
|
|
126
|
+
return window;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parses the features string into a set of options.
|
|
130
|
+
* @param features - The features string to parse.
|
|
131
|
+
* @returns The parsed options.
|
|
132
|
+
*/
|
|
133
|
+
export function parseFeatures(features) {
|
|
134
|
+
const options = {};
|
|
135
|
+
if (!features)
|
|
136
|
+
return options; // Return empty object if no features provided
|
|
137
|
+
// Split features string and process each key-value pair
|
|
138
|
+
features.split(',').forEach(feature => {
|
|
139
|
+
const [key, ...valueParts] = feature.trim().split('=');
|
|
140
|
+
const value = valueParts.join('='); // Rejoin in case value contains '='
|
|
141
|
+
if (!key)
|
|
142
|
+
return; // Skip invalid pairs
|
|
143
|
+
switch (key.toLowerCase()) {
|
|
144
|
+
case 'width':
|
|
145
|
+
options.width = parseInt(value, 10) || 1920;
|
|
146
|
+
break;
|
|
147
|
+
case 'height':
|
|
148
|
+
options.height = parseInt(value, 10) || 1080;
|
|
149
|
+
break;
|
|
150
|
+
case 'fullscreen':
|
|
151
|
+
options.fullscreen = value === '1' || value === 'true';
|
|
152
|
+
break;
|
|
153
|
+
case 'title':
|
|
154
|
+
options.title = value;
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
console.log(`Unsupported feature: ${key}`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
return options;
|
|
161
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import tsParser from '@typescript-eslint/parser';
|
|
2
|
+
import noDefaultClassFields from './node_modules/genesys.js/eslint-rules/no-default-class-fields.js';
|
|
3
|
+
import defaultGetterReturnType from './node_modules/genesys.js/eslint-rules/default-getter-return-type.js';
|
|
4
|
+
import constructorTypeConsistency from './node_modules/genesys.js/eslint-rules/constructor-type-consistency.js';
|
|
5
|
+
import noOverrideMethods from './node_modules/genesys.js/eslint-rules/no-override-methods.js';
|
|
6
|
+
export default [
|
|
7
|
+
{
|
|
8
|
+
ignores: ['dist/**', '.engine/**', 'node_modules/**']
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
parser: tsParser,
|
|
14
|
+
parserOptions: {
|
|
15
|
+
project: ['./tsconfig.json']
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
plugins: {
|
|
19
|
+
'custom': {
|
|
20
|
+
rules: {
|
|
21
|
+
'no-override-methods': noOverrideMethods,
|
|
22
|
+
'no-default-class-fields': noDefaultClassFields,
|
|
23
|
+
'default-getter-return-type': defaultGetterReturnType,
|
|
24
|
+
'constructor-type-consistency': constructorTypeConsistency,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
'custom/no-override-methods': 'error',
|
|
30
|
+
'custom/no-default-class-fields': 'error',
|
|
31
|
+
'custom/default-getter-return-type': 'error',
|
|
32
|
+
'custom/constructor-type-consistency': 'error',
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
files: ['games/**/*.ts', 'games/**/*.tsx'],
|
|
37
|
+
rules: {
|
|
38
|
+
'no-restricted-imports': ['error', {
|
|
39
|
+
patterns: ['../src/**', '!../src/index.js']
|
|
40
|
+
}]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { getProjectRoot, isDev } from './common.js';
|
|
2
|
+
const fileServerPort = !isDev ? 4000 : 4001;
|
|
3
|
+
async function main() {
|
|
4
|
+
try {
|
|
5
|
+
const rootResponse = await fetch(`http://localhost:${fileServerPort}/`);
|
|
6
|
+
if (!rootResponse.ok) {
|
|
7
|
+
console.log('❌ Failed to talk to the Genesys SDK App, please make sure it is running and open the project in it!');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const projectPath = getProjectRoot();
|
|
11
|
+
console.log(`🔨 Building project: ${projectPath} ...`);
|
|
12
|
+
const buildResponse = await fetch(`http://localhost:${fileServerPort}/api/build-project`, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
},
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
projectPath,
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
const responseJson = await buildResponse.json();
|
|
22
|
+
if (!buildResponse.ok) {
|
|
23
|
+
console.log('❌ Failed to build project, please check the console for errors!');
|
|
24
|
+
console.log(responseJson);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
/*
|
|
28
|
+
success: result.success,
|
|
29
|
+
message: result.message,
|
|
30
|
+
error: result.error
|
|
31
|
+
*/
|
|
32
|
+
if (!responseJson.success) {
|
|
33
|
+
console.log(`❌ Failed to build project:\n - ${responseJson.error ?? responseJson.message}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(`✅ ${responseJson.message}`);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.log('❌ Failed to talk to the Genesys SDK App, please make sure it is running and open the project in it!');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
main();
|