From 599a7cdd1bfaa4e0cb8b836bc31c9780e4000c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Fri, 16 Feb 2024 21:40:21 +0100 Subject: [PATCH 1/6] First solution for storing ScriptAccounts --- app/StorageModel.ts | 12 ++++ app/main.ts | 71 ++++++++++++++++++- src/app/app.component.ts | 11 +++ .../script-account-editor.component.html | 2 + .../script-account-editor.component.ts | 9 +++ src/app/game-model/GameModel.ts | 14 ++++ src/app/game-model/SaveComponent.ts | 4 +- src/app/game-model/StorageModel.ts | 12 ++++ src/app/game-model/gamesystems/Gamesystem.ts | 2 +- .../scriptAccounts/ScriptAccount.ts | 5 +- .../script-accounts/Luftfeuchtigkeit.json | 8 +++ testModel/script-accounts/Temperature.json | 8 +++ testModel/scriptAccounts/Temperature.json | 8 +++ 13 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 app/StorageModel.ts create mode 100644 src/app/game-model/StorageModel.ts create mode 100644 testModel/script-accounts/Luftfeuchtigkeit.json create mode 100644 testModel/script-accounts/Temperature.json create mode 100644 testModel/scriptAccounts/Temperature.json diff --git a/app/StorageModel.ts b/app/StorageModel.ts new file mode 100644 index 0000000..392016a --- /dev/null +++ b/app/StorageModel.ts @@ -0,0 +1,12 @@ +class StorageModel { + jsonString: string + fileName: string + storageDir: string + + + constructor(jsonString: string, fileName: string, storageDir: string) { + this.jsonString = jsonString; + this.fileName = fileName; + this.storageDir = storageDir; + } +} diff --git a/app/main.ts b/app/main.ts index 0668026..5a25dde 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1,11 +1,14 @@ -import {app, BrowserWindow, screen, Menu, ipcMain} from 'electron'; +import {app, BrowserWindow, screen, Menu, ipcMain, ipcRenderer} from 'electron'; import * as path from 'path'; import * as fs from 'fs'; +import {json} from "node:stream/consumers"; +import {StorageModel} from "../src/app/game-model/StorageModel"; let win: BrowserWindow | null = null; const args = process.argv.slice(1), serve = args.some(val => val === '--serve'); +let projectDirectory = "testModel" function createWindow(): BrowserWindow { const size = screen.getPrimaryDisplay().workAreaSize; @@ -90,6 +93,56 @@ function createWindow(): BrowserWindow { contextMenu.popup({ window: win!, x: params.x, y: params.y }); }) + ipcMain.on('save-model', (event, storageModels: StorageModel[]) => { + const directoryPath = 'testModel/' + if(!fs.existsSync(directoryPath)) { + fs.mkdirSync(directoryPath, {recursive: true}); + } + + storageModels.forEach(storageModel => { + const modelDir = path.join(directoryPath, storageModel.storageDir); + if(!fs.existsSync(modelDir)) { + fs.mkdirSync(modelDir, {recursive: true}); + } + + const filePath = path.join(directoryPath, storageModel.storageDir, storageModel.fileName + ".json"); + fs.writeFile(filePath, storageModel.jsonString ,'utf-8', (err) => { + if (err) { + console.error('Error writing JSON to file:', err); + } else { + console.log('JSON file saved successfully:', filePath); + } + }) + }) + }) + + const menuTemplate = [ + { + label: 'File', + submenu: [ + { + label: "New Project", + click: () => { + createNewProject(); + } + }, + { + label: "Open Project", + click: () => { + openProject() + } + }, + { + label: "Save", + click: () => { + saveProject(); + } + } + ] + } + ] + const menu = Menu.buildFromTemplate(menuTemplate); + Menu.setApplicationMenu(menu) return win; } @@ -118,7 +171,23 @@ try { } }); + + } catch (e) { // Catch Error // throw e; } + + +function createNewProject() { + +} + +function openProject() { + +} + +function saveProject() { + console.log("Clicked SaveProject") + win!.webContents.send('get-project-data') +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 95cb454..0b766a6 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -50,11 +50,22 @@ export class AppComponent implements OnInit{ this.onContextMenuMessageRecieved(message); }); }) + + electronService.ipcRenderer.on('get-project-data', (event: any, message: string) => { + this.zone.run(() => { + this.saveGameModel(); + }) + }) } else { console.log('Run in browser'); } } + saveGameModel() { + const storageModels = this.gameModel!.save() + this.electronService.ipcRenderer.send('save-model', storageModels) + } + onContextMenuMessageRecieved(message: string) { if(message == "edit") { this.onEditModelComponent(); diff --git a/src/app/editor/script-account-editor/script-account-editor.component.html b/src/app/editor/script-account-editor/script-account-editor.component.html index 2b36b86..0935334 100644 --- a/src/app/editor/script-account-editor/script-account-editor.component.html +++ b/src/app/editor/script-account-editor/script-account-editor.component.html @@ -10,4 +10,6 @@ Please enter a valid number! + + diff --git a/src/app/editor/script-account-editor/script-account-editor.component.ts b/src/app/editor/script-account-editor/script-account-editor.component.ts index bdf6bc2..271352a 100644 --- a/src/app/editor/script-account-editor/script-account-editor.component.ts +++ b/src/app/editor/script-account-editor/script-account-editor.component.ts @@ -6,6 +6,7 @@ import {MatInput} from "@angular/material/input"; import {FormControl, FormGroupDirective, FormsModule, NgForm, Validators} from "@angular/forms"; import {NgIf} from "@angular/common"; import {ErrorStateMatcher} from "@angular/material/core"; +import {ElectronService} from "../../core/services"; export class MyErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { @@ -24,6 +25,9 @@ export class ScriptAccountEditorComponent implements OnInit{ minCtrl: FormControl = new FormControl(0, [Validators.required, Validators.pattern('^[0-9]*$')]); maxCtrl: FormControl = new FormControl(100, [Validators.required, Validators.pattern('^[0-9]*$')]); matcher = new MyErrorStateMatcher(); + + constructor(private electronService: ElectronService) { + } ngOnInit() { this.minCtrl.setValue(this.scriptAccount!.minValue); this.maxCtrl.setValue(this.scriptAccount!.maxValue); @@ -46,4 +50,9 @@ export class ScriptAccountEditorComponent implements OnInit{ this.scriptAccount!.maxValue = Number(this.maxCtrl.value); this.scriptAccount!.onModifyContent(); } + + save() { + const jsonString = JSON.stringify(this.scriptAccount!, null, 4); + this.electronService.ipcRenderer.send('save-json', jsonString, this.scriptAccount!.componentName + ".json"); + } } diff --git a/src/app/game-model/GameModel.ts b/src/app/game-model/GameModel.ts index ac4d355..2c6a350 100644 --- a/src/app/game-model/GameModel.ts +++ b/src/app/game-model/GameModel.ts @@ -4,6 +4,7 @@ import {Transition} from "./gamesystems/Transition"; import {State} from "./gamesystems/State"; import {ProductGamesystem} from "./gamesystems/ProductGamesystem"; import {SimpleGamesystem} from "./gamesystems/SimpleGamesystem"; +import {StorageModel} from "./StorageModel"; export class GameModel { private readonly _gameModelName: string @@ -90,4 +91,17 @@ export class GameModel { } } + save() { + const storageModels: StorageModel[] = []; + this.scriptAccounts.forEach(scriptAccount => { + const scriptAccountJson = scriptAccount.save(); + storageModels.push({ + fileName: scriptAccount.componentName, + jsonString: scriptAccountJson, + storageDir: "script-accounts" + }) + }) + + return storageModels; + } } diff --git a/src/app/game-model/SaveComponent.ts b/src/app/game-model/SaveComponent.ts index 473f0c5..631c529 100644 --- a/src/app/game-model/SaveComponent.ts +++ b/src/app/game-model/SaveComponent.ts @@ -1,6 +1,8 @@ export abstract class SaveComponent { unsaved: boolean = false; + static JSON_INDENT = 4; + onModifyContent() { this.unsaved = true; } @@ -9,5 +11,5 @@ export abstract class SaveComponent { this.unsaved = false; } - abstract save(): void; + abstract save(): string; } diff --git a/src/app/game-model/StorageModel.ts b/src/app/game-model/StorageModel.ts new file mode 100644 index 0000000..35b06c5 --- /dev/null +++ b/src/app/game-model/StorageModel.ts @@ -0,0 +1,12 @@ +export class StorageModel { + jsonString: string + fileName: string + storageDir: string + + + constructor(jsonString: string, fileName: string, storageDir: string) { + this.jsonString = jsonString; + this.fileName = fileName; + this.storageDir = storageDir; + } +} diff --git a/src/app/game-model/gamesystems/Gamesystem.ts b/src/app/game-model/gamesystems/Gamesystem.ts index 2625649..505a830 100644 --- a/src/app/game-model/gamesystems/Gamesystem.ts +++ b/src/app/game-model/gamesystems/Gamesystem.ts @@ -27,7 +27,7 @@ export abstract class Gamesystem extends ModelComponent{ save() { - + return JSON.stringify(this); } } diff --git a/src/app/game-model/scriptAccounts/ScriptAccount.ts b/src/app/game-model/scriptAccounts/ScriptAccount.ts index f47f3c7..57556e7 100644 --- a/src/app/game-model/scriptAccounts/ScriptAccount.ts +++ b/src/app/game-model/scriptAccounts/ScriptAccount.ts @@ -1,5 +1,6 @@ import {ModelComponent} from "../ModelComponent"; import {ModelComponentType} from "../ModelComponentType"; +import {SaveComponent} from "../SaveComponent"; export class ScriptAccount extends ModelComponent{ minValue: number = 0; @@ -8,7 +9,7 @@ export class ScriptAccount extends ModelComponent{ super(componentName, componentDescription, ModelComponentType.SCRIPTACCOUNT); } - save(): void { + save(): string { + return JSON.stringify(this, null, SaveComponent.JSON_INDENT) } - } diff --git a/testModel/script-accounts/Luftfeuchtigkeit.json b/testModel/script-accounts/Luftfeuchtigkeit.json new file mode 100644 index 0000000..b948f4b --- /dev/null +++ b/testModel/script-accounts/Luftfeuchtigkeit.json @@ -0,0 +1,8 @@ +{ + "unsaved": false, + "componentName": "Luftfeuchtigkeit", + "componentDescription": "", + "type": 0, + "minValue": 0, + "maxValue": 100 +} \ No newline at end of file diff --git a/testModel/script-accounts/Temperature.json b/testModel/script-accounts/Temperature.json new file mode 100644 index 0000000..c53736b --- /dev/null +++ b/testModel/script-accounts/Temperature.json @@ -0,0 +1,8 @@ +{ + "unsaved": false, + "componentName": "Temperature", + "componentDescription": "", + "type": 0, + "minValue": 0, + "maxValue": 100 +} \ No newline at end of file diff --git a/testModel/scriptAccounts/Temperature.json b/testModel/scriptAccounts/Temperature.json new file mode 100644 index 0000000..c53736b --- /dev/null +++ b/testModel/scriptAccounts/Temperature.json @@ -0,0 +1,8 @@ +{ + "unsaved": false, + "componentName": "Temperature", + "componentDescription": "", + "type": 0, + "minValue": 0, + "maxValue": 100 +} \ No newline at end of file From d56166b24565e534b0b917b43cf319b203a223fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 17 Feb 2024 07:30:29 +0100 Subject: [PATCH 2/6] Restructure Saving Logic to extra class and save on Strg+S + display changed savestatus in editor --- app/SaveProject.js | 30 +++++++++++++++++ app/SaveProject.ts | 29 +++++++++++++++++ app/main.ts | 32 ++++++------------- src/app/editor/editor.component.html | 2 +- src/app/game-model/GameModel.ts | 2 ++ .../scriptAccounts/ScriptAccount.ts | 1 + testModel/script-accounts/Temperature.json | 2 +- testModel/scriptAccounts/Temperature.json | 8 ----- 8 files changed, 73 insertions(+), 33 deletions(-) create mode 100644 app/SaveProject.js create mode 100644 app/SaveProject.ts delete mode 100644 testModel/scriptAccounts/Temperature.json diff --git a/app/SaveProject.js b/app/SaveProject.js new file mode 100644 index 0000000..6e6d440 --- /dev/null +++ b/app/SaveProject.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SaveProject = void 0; +const fs = require("fs"); +const path = require("node:path"); +class SaveProject { + static saveProject(projectDir, storageModels) { + const directoryPath = 'testModel/'; + if (!fs.existsSync(directoryPath)) { + fs.mkdirSync(directoryPath, { recursive: true }); + } + storageModels.forEach(storageModel => { + const modelDir = path.join(directoryPath, storageModel.storageDir); + if (!fs.existsSync(modelDir)) { + fs.mkdirSync(modelDir, { recursive: true }); + } + const filePath = path.join(directoryPath, storageModel.storageDir, storageModel.fileName + ".json"); + fs.writeFile(filePath, storageModel.jsonString, 'utf-8', (err) => { + if (err) { + console.error('Error writing JSON to file:', err); + } + else { + console.log('JSON file saved successfully:', filePath); + } + }); + }); + } +} +exports.SaveProject = SaveProject; +//# sourceMappingURL=SaveProject.js.map \ No newline at end of file diff --git a/app/SaveProject.ts b/app/SaveProject.ts new file mode 100644 index 0000000..9368adc --- /dev/null +++ b/app/SaveProject.ts @@ -0,0 +1,29 @@ +import {StorageModel} from "../src/app/game-model/StorageModel"; +import * as fs from "fs"; +import * as path from "node:path"; + + +export class SaveProject { + static saveProject(projectDir: string, storageModels: StorageModel[]) { + const directoryPath = 'testModel/' + if(!fs.existsSync(directoryPath)) { + fs.mkdirSync(directoryPath, {recursive: true}); + } + + storageModels.forEach(storageModel => { + const modelDir = path.join(directoryPath, storageModel.storageDir); + if(!fs.existsSync(modelDir)) { + fs.mkdirSync(modelDir, {recursive: true}); + } + + const filePath = path.join(directoryPath, storageModel.storageDir, storageModel.fileName + ".json"); + fs.writeFile(filePath, storageModel.jsonString ,'utf-8', (err) => { + if (err) { + console.error('Error writing JSON to file:', err); + } else { + console.log('JSON file saved successfully:', filePath); + } + }) + }) + } +} diff --git a/app/main.ts b/app/main.ts index 5a25dde..d27f239 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1,8 +1,9 @@ -import {app, BrowserWindow, screen, Menu, ipcMain, ipcRenderer} from 'electron'; +import {app, BrowserWindow, screen, Menu, ipcMain, ipcRenderer, globalShortcut} from 'electron'; import * as path from 'path'; import * as fs from 'fs'; import {json} from "node:stream/consumers"; import {StorageModel} from "../src/app/game-model/StorageModel"; +import {SaveProject} from "./SaveProject"; let win: BrowserWindow | null = null; const args = process.argv.slice(1), @@ -94,26 +95,8 @@ function createWindow(): BrowserWindow { }) ipcMain.on('save-model', (event, storageModels: StorageModel[]) => { - const directoryPath = 'testModel/' - if(!fs.existsSync(directoryPath)) { - fs.mkdirSync(directoryPath, {recursive: true}); - } - - storageModels.forEach(storageModel => { - const modelDir = path.join(directoryPath, storageModel.storageDir); - if(!fs.existsSync(modelDir)) { - fs.mkdirSync(modelDir, {recursive: true}); - } - - const filePath = path.join(directoryPath, storageModel.storageDir, storageModel.fileName + ".json"); - fs.writeFile(filePath, storageModel.jsonString ,'utf-8', (err) => { - if (err) { - console.error('Error writing JSON to file:', err); - } else { - console.log('JSON file saved successfully:', filePath); - } - }) - }) + console.log("Save Model") + SaveProject.saveProject(projectDirectory, storageModels); }) const menuTemplate = [ @@ -171,7 +154,11 @@ try { } }); - + app.whenReady().then(() => { + globalShortcut.register('CommandOrControl+S', () => { + saveProject(); + }) + }) } catch (e) { // Catch Error @@ -188,6 +175,5 @@ function openProject() { } function saveProject() { - console.log("Clicked SaveProject") win!.webContents.send('get-project-data') } diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index 59dcd6f..b43ce41 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -10,7 +10,7 @@ - diff --git a/src/app/game-model/GameModel.ts b/src/app/game-model/GameModel.ts index 2c6a350..a396a92 100644 --- a/src/app/game-model/GameModel.ts +++ b/src/app/game-model/GameModel.ts @@ -100,6 +100,8 @@ export class GameModel { jsonString: scriptAccountJson, storageDir: "script-accounts" }) + + console.log(scriptAccount) }) return storageModels; diff --git a/src/app/game-model/scriptAccounts/ScriptAccount.ts b/src/app/game-model/scriptAccounts/ScriptAccount.ts index 57556e7..62b0636 100644 --- a/src/app/game-model/scriptAccounts/ScriptAccount.ts +++ b/src/app/game-model/scriptAccounts/ScriptAccount.ts @@ -10,6 +10,7 @@ export class ScriptAccount extends ModelComponent{ } save(): string { + this.unsaved = false; return JSON.stringify(this, null, SaveComponent.JSON_INDENT) } } diff --git a/testModel/script-accounts/Temperature.json b/testModel/script-accounts/Temperature.json index c53736b..56a6930 100644 --- a/testModel/script-accounts/Temperature.json +++ b/testModel/script-accounts/Temperature.json @@ -1,7 +1,7 @@ { "unsaved": false, "componentName": "Temperature", - "componentDescription": "", + "componentDescription": "ddada", "type": 0, "minValue": 0, "maxValue": 100 diff --git a/testModel/scriptAccounts/Temperature.json b/testModel/scriptAccounts/Temperature.json deleted file mode 100644 index c53736b..0000000 --- a/testModel/scriptAccounts/Temperature.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "unsaved": false, - "componentName": "Temperature", - "componentDescription": "", - "type": 0, - "minValue": 0, - "maxValue": 100 -} \ No newline at end of file From 78a264aa26b9e3a5316cedf5d68d1c89c784a4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 17 Feb 2024 08:45:22 +0100 Subject: [PATCH 3/6] Load ScriptAccounts --- app/LoadModel.js | 11 +++++ app/LoadModel.ts | 12 ++++++ app/LoadedProject.js | 11 +++++ app/LoadedProject.ts | 12 ++++++ app/SaveProject.js | 32 +++++++++++--- app/SaveProject.ts | 42 ++++++++++++++++--- app/main.ts | 14 ++++++- src/app/app.component.ts | 11 ++++- src/app/game-model/GameModel.ts | 4 ++ src/app/game-model/fs/ProcessLoadedProject.ts | 30 +++++++++++++ testModel/script-accounts/Temperature.json | 2 +- 11 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 app/LoadModel.js create mode 100644 app/LoadModel.ts create mode 100644 app/LoadedProject.js create mode 100644 app/LoadedProject.ts create mode 100644 src/app/game-model/fs/ProcessLoadedProject.ts diff --git a/app/LoadModel.js b/app/LoadModel.js new file mode 100644 index 0000000..a376e51 --- /dev/null +++ b/app/LoadModel.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LoadModel = void 0; +class LoadModel { + constructor(jsonString, modelType) { + this.jsonString = jsonString; + this.modelType = modelType; + } +} +exports.LoadModel = LoadModel; +//# sourceMappingURL=LoadModel.js.map \ No newline at end of file diff --git a/app/LoadModel.ts b/app/LoadModel.ts new file mode 100644 index 0000000..9effb8d --- /dev/null +++ b/app/LoadModel.ts @@ -0,0 +1,12 @@ +import {ModelComponentType} from "../src/app/game-model/ModelComponentType"; + +export class LoadModel { + jsonString: string + modelType: ModelComponentType + + + constructor(jsonString: string, modelType: ModelComponentType) { + this.jsonString = jsonString; + this.modelType = modelType; + } +} diff --git a/app/LoadedProject.js b/app/LoadedProject.js new file mode 100644 index 0000000..66d4596 --- /dev/null +++ b/app/LoadedProject.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LoadedProject = void 0; +class LoadedProject { + constructor(projectName, loadedModels) { + this.projectName = projectName; + this.loadedModels = loadedModels; + } +} +exports.LoadedProject = LoadedProject; +//# sourceMappingURL=LoadedProject.js.map \ No newline at end of file diff --git a/app/LoadedProject.ts b/app/LoadedProject.ts new file mode 100644 index 0000000..be710b8 --- /dev/null +++ b/app/LoadedProject.ts @@ -0,0 +1,12 @@ +import {LoadModel} from "./LoadModel"; + +export class LoadedProject { + projectName: string + loadedModels: LoadModel[] + + + constructor(projectName: string, loadedModels: LoadModel[]) { + this.projectName = projectName; + this.loadedModels = loadedModels; + } +} diff --git a/app/SaveProject.js b/app/SaveProject.js index 6e6d440..41ad558 100644 --- a/app/SaveProject.js +++ b/app/SaveProject.js @@ -3,18 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.SaveProject = void 0; const fs = require("fs"); const path = require("node:path"); +const ModelComponentType_1 = require("../src/app/game-model/ModelComponentType"); +const LoadedProject_1 = require("./LoadedProject"); class SaveProject { static saveProject(projectDir, storageModels) { - const directoryPath = 'testModel/'; - if (!fs.existsSync(directoryPath)) { - fs.mkdirSync(directoryPath, { recursive: true }); + if (!fs.existsSync(projectDir)) { + fs.mkdirSync(projectDir, { recursive: true }); } storageModels.forEach(storageModel => { - const modelDir = path.join(directoryPath, storageModel.storageDir); + const modelDir = path.join(projectDir, storageModel.storageDir); if (!fs.existsSync(modelDir)) { fs.mkdirSync(modelDir, { recursive: true }); } - const filePath = path.join(directoryPath, storageModel.storageDir, storageModel.fileName + ".json"); + const filePath = path.join(modelDir, storageModel.fileName + ".json"); fs.writeFile(filePath, storageModel.jsonString, 'utf-8', (err) => { if (err) { console.error('Error writing JSON to file:', err); @@ -25,6 +26,27 @@ class SaveProject { }); }); } + static loadProject(projectDir) { + const loadedScriptAccounts = SaveProject.loadScriptAccounts(projectDir); + return new LoadedProject_1.LoadedProject(path.basename(projectDir), loadedScriptAccounts); + } + static loadScriptAccounts(projectDir) { + const scriptAccountDir = path.join(projectDir, "script-accounts"); + if (!fs.existsSync(scriptAccountDir)) { + return []; + } + const loadedScriptAccounts = []; + const scriptAccountFileNames = fs.readdirSync(scriptAccountDir); + scriptAccountFileNames.forEach(scriptAccountFileName => { + const scriptAccountFile = path.join(scriptAccountDir, scriptAccountFileName); + const scriptAccountData = fs.readFileSync(scriptAccountFile, 'utf-8'); + loadedScriptAccounts.push({ + modelType: ModelComponentType_1.ModelComponentType.SCRIPTACCOUNT, + jsonString: scriptAccountData + }); + }); + return loadedScriptAccounts; + } } exports.SaveProject = SaveProject; //# sourceMappingURL=SaveProject.js.map \ No newline at end of file diff --git a/app/SaveProject.ts b/app/SaveProject.ts index 9368adc..4175a16 100644 --- a/app/SaveProject.ts +++ b/app/SaveProject.ts @@ -1,22 +1,25 @@ import {StorageModel} from "../src/app/game-model/StorageModel"; import * as fs from "fs"; import * as path from "node:path"; +import {LoadModel} from "./LoadModel"; +import {ModelComponentType} from "../src/app/game-model/ModelComponentType"; +import {BrowserWindow} from "electron"; +import {LoadedProject} from "./LoadedProject"; export class SaveProject { static saveProject(projectDir: string, storageModels: StorageModel[]) { - const directoryPath = 'testModel/' - if(!fs.existsSync(directoryPath)) { - fs.mkdirSync(directoryPath, {recursive: true}); + if(!fs.existsSync(projectDir)) { + fs.mkdirSync(projectDir, {recursive: true}); } storageModels.forEach(storageModel => { - const modelDir = path.join(directoryPath, storageModel.storageDir); + const modelDir = path.join(projectDir, storageModel.storageDir); if(!fs.existsSync(modelDir)) { fs.mkdirSync(modelDir, {recursive: true}); } - const filePath = path.join(directoryPath, storageModel.storageDir, storageModel.fileName + ".json"); + const filePath = path.join(modelDir, storageModel.fileName + ".json"); fs.writeFile(filePath, storageModel.jsonString ,'utf-8', (err) => { if (err) { console.error('Error writing JSON to file:', err); @@ -26,4 +29,33 @@ export class SaveProject { }) }) } + + static loadProject(projectDir: string) { + const loadedScriptAccounts: LoadModel[] = SaveProject.loadScriptAccounts(projectDir) + + return new LoadedProject(path.basename(projectDir), loadedScriptAccounts); + } + + static loadScriptAccounts(projectDir: string): LoadModel[] { + const scriptAccountDir = path.join(projectDir, "script-accounts"); + if (!fs.existsSync(scriptAccountDir)) { + return []; + } + + const loadedScriptAccounts: LoadModel[] = []; + + const scriptAccountFileNames = fs.readdirSync(scriptAccountDir); + scriptAccountFileNames.forEach(scriptAccountFileName => { + const scriptAccountFile = path.join(scriptAccountDir, scriptAccountFileName) + const scriptAccountData: string = fs.readFileSync(scriptAccountFile, 'utf-8'); + + loadedScriptAccounts.push({ + modelType: ModelComponentType.SCRIPTACCOUNT, + jsonString: scriptAccountData + }); + }) + + return loadedScriptAccounts; + } + } diff --git a/app/main.ts b/app/main.ts index d27f239..20acbd8 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1,4 +1,4 @@ -import {app, BrowserWindow, screen, Menu, ipcMain, ipcRenderer, globalShortcut} from 'electron'; +import {app, BrowserWindow, screen, Menu, ipcMain, dialog, globalShortcut} from 'electron'; import * as path from 'path'; import * as fs from 'fs'; import {json} from "node:stream/consumers"; @@ -171,7 +171,19 @@ function createNewProject() { } function openProject() { + const selectedPaths = dialog.showOpenDialogSync(win!, { + title: "Open Game-Model", + properties: [ + "openDirectory", + ] + }) + if(selectedPaths != undefined) { + projectDirectory = selectedPaths[0]; + console.log("Open Project-Directory: ", projectDirectory) + const loadedProject = SaveProject.loadProject(projectDirectory) + win!.webContents.send("open-project", loadedProject) + } } function saveProject() { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0b766a6..ec551fe 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -17,6 +17,9 @@ import {GamescriptOverviewComponent} from "./side-overviews/gamescript-overview/ import {SimpleGamesystem} from "./game-model/gamesystems/SimpleGamesystem"; import {ProductGamesystem} from "./game-model/gamesystems/ProductGamesystem"; import {ProductState} from "./game-model/gamesystems/ProductState"; +import {LoadModel} from "../../app/LoadModel"; +import {LoadedProject} from "../../app/LoadedProject"; +import {ProcessLoadedProject} from "./game-model/fs/ProcessLoadedProject"; @Component({ selector: 'app-root', @@ -56,6 +59,10 @@ export class AppComponent implements OnInit{ this.saveGameModel(); }) }) + + electronService.ipcRenderer.on('open-project', (event: any, loadedProject: LoadedProject) => { + this.gameModel = ProcessLoadedProject.processLoadedProject(loadedProject) + }) } else { console.log('Run in browser'); } @@ -153,7 +160,7 @@ export class AppComponent implements OnInit{ } ngOnInit() { - this.gameModel = new GameModel("No More"); + /*this.gameModel = new GameModel("No More"); this.gameModel.createScriptAccount("Temperature"); this.gameModel.createScriptAccount("Luftfeuchtigkeit"); @@ -175,7 +182,7 @@ export class AppComponent implements OnInit{ weather_season.createState([springState!, sunnyState!]); - this.gameModel.addGamesystem(weather_season); + this.gameModel.addGamesystem(weather_season);*/ } openScriptAccountsOverview() { diff --git a/src/app/game-model/GameModel.ts b/src/app/game-model/GameModel.ts index a396a92..bf928e0 100644 --- a/src/app/game-model/GameModel.ts +++ b/src/app/game-model/GameModel.ts @@ -106,4 +106,8 @@ export class GameModel { return storageModels; } + + addScriptAccount(scriptAccount: ScriptAccount) { + this.scriptAccounts.push(scriptAccount); + } } diff --git a/src/app/game-model/fs/ProcessLoadedProject.ts b/src/app/game-model/fs/ProcessLoadedProject.ts new file mode 100644 index 0000000..3aca7ac --- /dev/null +++ b/src/app/game-model/fs/ProcessLoadedProject.ts @@ -0,0 +1,30 @@ +import {GameModel} from "../GameModel"; +import {LoadedProject} from "../../../../app/LoadedProject"; +import {LoadModel} from "../../../../app/LoadModel"; +import {ModelComponentType} from "../ModelComponentType"; +import {ScriptAccount} from "../scriptAccounts/ScriptAccount"; + +export class ProcessLoadedProject { + + static processLoadedProject(loadedProject: LoadedProject): GameModel { + const gameModel = new GameModel(loadedProject.projectName); + loadedProject.loadedModels.forEach(loadedModel => this.processLoadedModel(gameModel, loadedModel)) + return gameModel; + } + + static processLoadedModel(gameModel: GameModel, loadedModel: LoadModel) { + switch (loadedModel.modelType) { + case ModelComponentType.SCRIPTACCOUNT: this.processLoadedScriptAccount(gameModel, loadedModel); break; + case ModelComponentType.GAMESYTEM: this.processLoadedGamesystem(gameModel, loadedModel); break; + } + } + static processLoadedScriptAccount(gameModel: GameModel, loadedModel: LoadModel) { + const scriptAccount = new ScriptAccount("", ""); + Object.assign(scriptAccount, JSON.parse(loadedModel.jsonString)); + gameModel.addScriptAccount(scriptAccount); + } + + static processLoadedGamesystem(gameModel: GameModel, loadedModel: LoadModel) { + + } +} diff --git a/testModel/script-accounts/Temperature.json b/testModel/script-accounts/Temperature.json index 56a6930..c53736b 100644 --- a/testModel/script-accounts/Temperature.json +++ b/testModel/script-accounts/Temperature.json @@ -1,7 +1,7 @@ { "unsaved": false, "componentName": "Temperature", - "componentDescription": "ddada", + "componentDescription": "", "type": 0, "minValue": 0, "maxValue": 100 From e873688cb706c59f4e710ad4fdc481f14b87c705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 17 Feb 2024 10:13:32 +0100 Subject: [PATCH 4/6] Save Gamesystems and Ignore save status and type of saved gamemodelcomponent --- app/SaveProject.js | 4 +- app/SaveProject.ts | 6 +- app/main.ts | 2 +- src/app/app.component.ts | 22 ++++- src/app/game-model/GameModel.ts | 18 +--- src/app/game-model/SaveComponent.ts | 2 - src/app/game-model/StorageModel.ts | 12 --- src/app/game-model/fs/StorageModel.ts | 14 ++++ src/app/game-model/fs/store/StoreProject.ts | 84 +++++++++++++++++++ src/app/game-model/gamesystems/Gamesystem.ts | 5 -- .../gamesystems/SimpleGamesystem.ts | 2 - .../scriptAccounts/ScriptAccount.ts | 5 -- 12 files changed, 128 insertions(+), 48 deletions(-) delete mode 100644 src/app/game-model/StorageModel.ts create mode 100644 src/app/game-model/fs/StorageModel.ts create mode 100644 src/app/game-model/fs/store/StoreProject.ts diff --git a/app/SaveProject.js b/app/SaveProject.js index 41ad558..5b32ad8 100644 --- a/app/SaveProject.js +++ b/app/SaveProject.js @@ -10,8 +10,10 @@ class SaveProject { if (!fs.existsSync(projectDir)) { fs.mkdirSync(projectDir, { recursive: true }); } + console.log(storageModels); storageModels.forEach(storageModel => { - const modelDir = path.join(projectDir, storageModel.storageDir); + let modelDir = path.join(projectDir, storageModel.storageRootDir); + storageModel.storagePath.forEach(pathElement => modelDir = path.join(modelDir, pathElement)); if (!fs.existsSync(modelDir)) { fs.mkdirSync(modelDir, { recursive: true }); } diff --git a/app/SaveProject.ts b/app/SaveProject.ts index 4175a16..cfe06cd 100644 --- a/app/SaveProject.ts +++ b/app/SaveProject.ts @@ -1,4 +1,4 @@ -import {StorageModel} from "../src/app/game-model/StorageModel"; +import {StorageModel} from "../src/app/game-model/fs/StorageModel"; import * as fs from "fs"; import * as path from "node:path"; import {LoadModel} from "./LoadModel"; @@ -13,8 +13,10 @@ export class SaveProject { fs.mkdirSync(projectDir, {recursive: true}); } + console.log(storageModels) storageModels.forEach(storageModel => { - const modelDir = path.join(projectDir, storageModel.storageDir); + let modelDir = path.join(projectDir, storageModel.storageRootDir); + storageModel.storagePath.forEach(pathElement => modelDir = path.join(modelDir, pathElement)); if(!fs.existsSync(modelDir)) { fs.mkdirSync(modelDir, {recursive: true}); } diff --git a/app/main.ts b/app/main.ts index 20acbd8..af69ce5 100644 --- a/app/main.ts +++ b/app/main.ts @@ -2,7 +2,7 @@ import {app, BrowserWindow, screen, Menu, ipcMain, dialog, globalShortcut} from import * as path from 'path'; import * as fs from 'fs'; import {json} from "node:stream/consumers"; -import {StorageModel} from "../src/app/game-model/StorageModel"; +import {StorageModel} from "../src/app/game-model/fs/StorageModel"; import {SaveProject} from "./SaveProject"; let win: BrowserWindow | null = null; diff --git a/src/app/app.component.ts b/src/app/app.component.ts index ec551fe..012ba8f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -20,6 +20,7 @@ import {ProductState} from "./game-model/gamesystems/ProductState"; import {LoadModel} from "../../app/LoadModel"; import {LoadedProject} from "../../app/LoadedProject"; import {ProcessLoadedProject} from "./game-model/fs/ProcessLoadedProject"; +import {StoreProject} from "./game-model/fs/store/StoreProject"; @Component({ selector: 'app-root', @@ -62,6 +63,25 @@ export class AppComponent implements OnInit{ electronService.ipcRenderer.on('open-project', (event: any, loadedProject: LoadedProject) => { this.gameModel = ProcessLoadedProject.processLoadedProject(loadedProject) + const weather = new SimpleGamesystem("Weather"); + const season = new SimpleGamesystem("Season"); + + const springState = season.createState("Spring", "Spring, also known as springtime, is one of the four temperate seasons, succeeding winter and preceding summer."); + const summerState = season.createState("Summer", "Summer is the hottest and brightest of the four temperate seasons, occurring after spring and before autumn. "); + + const sunnyState = weather.createState("Sunny", "The sun is shining. No clouds, no rain, no storm."); + const rainingState = weather.createState("Raining", "It rains") + + season.createTransition(springState!, summerState!); + weather.createTransition(sunnyState!, rainingState!); + + const weather_season = new ProductGamesystem("Weather-Season"); + weather_season.addChildGamesystem(weather); + weather_season.addChildGamesystem(season); + + weather_season.createState([springState!, sunnyState!]); + + this.gameModel.addGamesystem(weather_season); }) } else { console.log('Run in browser'); @@ -69,7 +89,7 @@ export class AppComponent implements OnInit{ } saveGameModel() { - const storageModels = this.gameModel!.save() + const storageModels = StoreProject.storeProject(this.gameModel!); this.electronService.ipcRenderer.send('save-model', storageModels) } diff --git a/src/app/game-model/GameModel.ts b/src/app/game-model/GameModel.ts index bf928e0..0b1a189 100644 --- a/src/app/game-model/GameModel.ts +++ b/src/app/game-model/GameModel.ts @@ -4,7 +4,7 @@ import {Transition} from "./gamesystems/Transition"; import {State} from "./gamesystems/State"; import {ProductGamesystem} from "./gamesystems/ProductGamesystem"; import {SimpleGamesystem} from "./gamesystems/SimpleGamesystem"; -import {StorageModel} from "./StorageModel"; +import {StorageModel} from "./fs/StorageModel"; export class GameModel { private readonly _gameModelName: string @@ -91,22 +91,6 @@ export class GameModel { } } - save() { - const storageModels: StorageModel[] = []; - this.scriptAccounts.forEach(scriptAccount => { - const scriptAccountJson = scriptAccount.save(); - storageModels.push({ - fileName: scriptAccount.componentName, - jsonString: scriptAccountJson, - storageDir: "script-accounts" - }) - - console.log(scriptAccount) - }) - - return storageModels; - } - addScriptAccount(scriptAccount: ScriptAccount) { this.scriptAccounts.push(scriptAccount); } diff --git a/src/app/game-model/SaveComponent.ts b/src/app/game-model/SaveComponent.ts index 631c529..cf2b2a8 100644 --- a/src/app/game-model/SaveComponent.ts +++ b/src/app/game-model/SaveComponent.ts @@ -10,6 +10,4 @@ export abstract class SaveComponent { onSaveContent() { this.unsaved = false; } - - abstract save(): string; } diff --git a/src/app/game-model/StorageModel.ts b/src/app/game-model/StorageModel.ts deleted file mode 100644 index 35b06c5..0000000 --- a/src/app/game-model/StorageModel.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class StorageModel { - jsonString: string - fileName: string - storageDir: string - - - constructor(jsonString: string, fileName: string, storageDir: string) { - this.jsonString = jsonString; - this.fileName = fileName; - this.storageDir = storageDir; - } -} diff --git a/src/app/game-model/fs/StorageModel.ts b/src/app/game-model/fs/StorageModel.ts new file mode 100644 index 0000000..800754e --- /dev/null +++ b/src/app/game-model/fs/StorageModel.ts @@ -0,0 +1,14 @@ +export class StorageModel { + jsonString: string + fileName: string + storagePath: string[] + storageRootDir: string + + + constructor(jsonString: string, fileName: string, storagePath: string[], storageRootDir: string) { + this.jsonString = jsonString; + this.fileName = fileName; + this.storagePath = storagePath; + this.storageRootDir = storageRootDir; + } +} diff --git a/src/app/game-model/fs/store/StoreProject.ts b/src/app/game-model/fs/store/StoreProject.ts new file mode 100644 index 0000000..6503281 --- /dev/null +++ b/src/app/game-model/fs/store/StoreProject.ts @@ -0,0 +1,84 @@ +import {StorageModel} from "../StorageModel"; +import {GameModel} from "../../GameModel"; +import {ScriptAccount} from "../../scriptAccounts/ScriptAccount"; +import {Gamesystem} from "../../gamesystems/Gamesystem"; +import {SimpleGamesystem} from "../../gamesystems/SimpleGamesystem"; +import {ModelComponent} from "../../ModelComponent"; +import {ProductGamesystem} from "../../gamesystems/ProductGamesystem"; + +export class StoreProject { + + static JSON_INDENT = 4 + + static storeProject(gameModel: GameModel): StorageModel[] { + let storageModels: StorageModel[] = []; + storageModels = storageModels.concat(this.storeScriptAccounts(gameModel.scriptAccounts)); + storageModels = storageModels.concat(this.storeGamesystems(gameModel.gamesystems)); + return storageModels; + } + + static storeScriptAccounts(scriptAcccounts: ScriptAccount[]): StorageModel[] { + const storedScriptAccounts: StorageModel[] = []; + scriptAcccounts.forEach(scriptAccount => { + storedScriptAccounts.push({ + fileName: scriptAccount.componentName, + jsonString: JSON.stringify(scriptAccount, (key,value) => { + if(key === 'unsaved' || key === 'type') { + return undefined + } else { + return value; + } + }, StoreProject.JSON_INDENT), + storageRootDir: "script-accounts", + storagePath: [] + }) + scriptAccount.onSaveContent(); + }) + return storedScriptAccounts; + } + + static storeGamesystems(gamesystems: Gamesystem[]): StorageModel[] { + let storedGamesystems: StorageModel[] = []; + gamesystems.forEach(gamesystem => { + const storageModels: StorageModel[] = StoreProject.storeIndividualGamesystem(gamesystem, []); + storedGamesystems = storedGamesystems.concat(storageModels); + }) + return storedGamesystems; + } + + static storeIndividualGamesystem(gamesystem: Gamesystem, storagePath: string[]): StorageModel[] { + if(gamesystem instanceof SimpleGamesystem) { + return [new StorageModel(JSON.stringify(gamesystem, (key, value) => { + if(key === 'startingState' || key === 'endingState') { + return value.stateLabel + } + + if(key === 'incomingTransitions' || key === 'outgoingTransitions' || key === 'unsaved' || key === 'type') { + return undefined; + } else { + return value; + } + }, this.JSON_INDENT), gamesystem.componentName, storagePath, "gamesystems")]; + } else if(gamesystem instanceof ProductGamesystem) { + const storageModels: StorageModel[] = []; + //Root-StorageModel + storagePath.push(gamesystem.componentName); + (gamesystem as ProductGamesystem).innerGamesystems.forEach(innerGamesystem => { + const innerStorageModels: StorageModel[] = StoreProject.storeIndividualGamesystem(innerGamesystem, storagePath) + innerStorageModels.forEach(storageModel => storageModels.push(storageModel)) + }) + + const productData = { + 'componentName': gamesystem.componentName, + 'componentDescription': gamesystem.componentDescription + } + + + storageModels.push(new StorageModel(JSON.stringify(productData, null, this.JSON_INDENT), gamesystem.componentName, storagePath, "gamesystems")) + return storageModels; + } else { + return []; + } + } + +} diff --git a/src/app/game-model/gamesystems/Gamesystem.ts b/src/app/game-model/gamesystems/Gamesystem.ts index 505a830..a1f0d5c 100644 --- a/src/app/game-model/gamesystems/Gamesystem.ts +++ b/src/app/game-model/gamesystems/Gamesystem.ts @@ -25,9 +25,4 @@ export abstract class Gamesystem extends ModelComponent{ return true; } - - save() { - return JSON.stringify(this); - } - } diff --git a/src/app/game-model/gamesystems/SimpleGamesystem.ts b/src/app/game-model/gamesystems/SimpleGamesystem.ts index 4021c93..e9e73b0 100644 --- a/src/app/game-model/gamesystems/SimpleGamesystem.ts +++ b/src/app/game-model/gamesystems/SimpleGamesystem.ts @@ -55,6 +55,4 @@ export class SimpleGamesystem extends Gamesystem return updated; } - - } diff --git a/src/app/game-model/scriptAccounts/ScriptAccount.ts b/src/app/game-model/scriptAccounts/ScriptAccount.ts index 62b0636..65967f4 100644 --- a/src/app/game-model/scriptAccounts/ScriptAccount.ts +++ b/src/app/game-model/scriptAccounts/ScriptAccount.ts @@ -8,9 +8,4 @@ export class ScriptAccount extends ModelComponent{ constructor(componentName: string, componentDescription: string) { super(componentName, componentDescription, ModelComponentType.SCRIPTACCOUNT); } - - save(): string { - this.unsaved = false; - return JSON.stringify(this, null, SaveComponent.JSON_INDENT) - } } From 3b0d4e0194f409be8f87b19862d7c4b695006c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 17 Feb 2024 14:32:19 +0100 Subject: [PATCH 5/6] Load Gamesystems from Filesystem --- app/RecursiveLoadModel.js | 12 +++++ app/RecursiveLoadModel.ts | 12 +++++ app/SaveProject.js | 48 ++++++++++++++++- app/SaveProject.ts | 53 +++++++++++++++++-- .../productGamesystems/ProductStateTrainer.ts | 6 +-- src/app/app.component.ts | 19 ------- src/app/game-model/GameModel.ts | 2 +- src/app/game-model/fs/ProcessLoadedProject.ts | 37 ++++++++++++- .../fs/parser/ProductGamesystemParser.ts | 9 ++++ .../fs/parser/SimpleGamesystemParser.ts | 47 ++++++++++++++++ src/app/game-model/gamesystems/Gamesystem.ts | 4 +- .../gamesystems/ProductGamesystem.ts | 4 +- .../gamesystems/SimpleGamesystem.ts | 2 + 13 files changed, 223 insertions(+), 32 deletions(-) create mode 100644 app/RecursiveLoadModel.js create mode 100644 app/RecursiveLoadModel.ts create mode 100644 src/app/game-model/fs/parser/ProductGamesystemParser.ts create mode 100644 src/app/game-model/fs/parser/SimpleGamesystemParser.ts diff --git a/app/RecursiveLoadModel.js b/app/RecursiveLoadModel.js new file mode 100644 index 0000000..7599083 --- /dev/null +++ b/app/RecursiveLoadModel.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RecursiveLoadModel = void 0; +const LoadModel_1 = require("./LoadModel"); +class RecursiveLoadModel extends LoadModel_1.LoadModel { + constructor(jsonString, modelType, parentLoadModelname) { + super(jsonString, modelType); + this.parentLoadModelname = parentLoadModelname; + } +} +exports.RecursiveLoadModel = RecursiveLoadModel; +//# sourceMappingURL=RecursiveLoadModel.js.map \ No newline at end of file diff --git a/app/RecursiveLoadModel.ts b/app/RecursiveLoadModel.ts new file mode 100644 index 0000000..1b9d251 --- /dev/null +++ b/app/RecursiveLoadModel.ts @@ -0,0 +1,12 @@ +import {LoadModel} from "./LoadModel"; +import {ModelComponentType} from "../src/app/game-model/ModelComponentType"; + +export class RecursiveLoadModel extends LoadModel { + parentLoadModelname: string + + + constructor(jsonString: string, modelType: ModelComponentType, parentLoadModelname: string) { + super(jsonString, modelType); + this.parentLoadModelname = parentLoadModelname; + } +} diff --git a/app/SaveProject.js b/app/SaveProject.js index 5b32ad8..0e77adc 100644 --- a/app/SaveProject.js +++ b/app/SaveProject.js @@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.SaveProject = void 0; const fs = require("fs"); const path = require("node:path"); +const LoadModel_1 = require("./LoadModel"); const ModelComponentType_1 = require("../src/app/game-model/ModelComponentType"); const LoadedProject_1 = require("./LoadedProject"); +const RecursiveLoadModel_1 = require("./RecursiveLoadModel"); class SaveProject { static saveProject(projectDir, storageModels) { if (!fs.existsSync(projectDir)) { @@ -29,7 +31,8 @@ class SaveProject { }); } static loadProject(projectDir) { - const loadedScriptAccounts = SaveProject.loadScriptAccounts(projectDir); + let loadedScriptAccounts = SaveProject.loadScriptAccounts(projectDir); + loadedScriptAccounts = loadedScriptAccounts.concat(SaveProject.loadGamesystems(projectDir)); return new LoadedProject_1.LoadedProject(path.basename(projectDir), loadedScriptAccounts); } static loadScriptAccounts(projectDir) { @@ -49,6 +52,49 @@ class SaveProject { }); return loadedScriptAccounts; } + static loadGamesystems(projectDir) { + const gamesystemDir = path.join(projectDir, "gamesystems"); + const loadedGamesystems = this.loadGamesystemsRecursively(gamesystemDir); + console.log("LoadedGamesystems: ", loadedGamesystems.length); + return loadedGamesystems; + } + static loadGamesystemsRecursively(gamesystemDir) { + let loadedGamesystems = []; + const gamesystemFileNames = fs.readdirSync(gamesystemDir); + gamesystemFileNames.forEach(fileName => { + const gamesystemPath = path.join(gamesystemDir, fileName); + if (fs.lstatSync(gamesystemPath).isDirectory()) { + const childModels = SaveProject.loadGamesystemsRecursively(gamesystemPath); + loadedGamesystems = loadedGamesystems.concat(childModels); + } + else { + const gamesystemData = fs.readFileSync(path.join(gamesystemDir, fileName), "utf-8"); + if (path.parse(fileName).name === path.basename(gamesystemDir)) { + if ((path.basename(gamesystemDir) === path.parse(fileName).name) && path.basename(path.parse(gamesystemDir).dir) === "gamesystems") { + const loadedModel = new LoadModel_1.LoadModel(gamesystemData, ModelComponentType_1.ModelComponentType.GAMESYTEM); + loadedGamesystems.unshift(loadedModel); + } + else { + const loadedModel = new RecursiveLoadModel_1.RecursiveLoadModel(gamesystemData, ModelComponentType_1.ModelComponentType.GAMESYTEM, path.basename(gamesystemDir)); + loadedGamesystems.unshift(loadedModel); + } + } + else { + const secondCon = path.basename(gamesystemDir) === path.parse(fileName).name; + const thirdCon = path.basename(path.parse(gamesystemDir).dir) === "gamesystems"; + if (path.basename(gamesystemDir) === "gamesystems") { + const loadedModel = new LoadModel_1.LoadModel(gamesystemData, ModelComponentType_1.ModelComponentType.GAMESYTEM); + loadedGamesystems.push(loadedModel); + } + else { + const loadedModel = new RecursiveLoadModel_1.RecursiveLoadModel(gamesystemData, ModelComponentType_1.ModelComponentType.GAMESYTEM, path.basename(gamesystemDir)); + loadedGamesystems.push(loadedModel); + } + } + } + }); + return loadedGamesystems; + } } exports.SaveProject = SaveProject; //# sourceMappingURL=SaveProject.js.map \ No newline at end of file diff --git a/app/SaveProject.ts b/app/SaveProject.ts index cfe06cd..7c010d3 100644 --- a/app/SaveProject.ts +++ b/app/SaveProject.ts @@ -3,8 +3,8 @@ import * as fs from "fs"; import * as path from "node:path"; import {LoadModel} from "./LoadModel"; import {ModelComponentType} from "../src/app/game-model/ModelComponentType"; -import {BrowserWindow} from "electron"; import {LoadedProject} from "./LoadedProject"; +import {RecursiveLoadModel} from "./RecursiveLoadModel"; export class SaveProject { @@ -33,8 +33,8 @@ export class SaveProject { } static loadProject(projectDir: string) { - const loadedScriptAccounts: LoadModel[] = SaveProject.loadScriptAccounts(projectDir) - + let loadedScriptAccounts: LoadModel[] = SaveProject.loadScriptAccounts(projectDir) + loadedScriptAccounts = loadedScriptAccounts.concat(SaveProject.loadGamesystems(projectDir)) return new LoadedProject(path.basename(projectDir), loadedScriptAccounts); } @@ -60,4 +60,51 @@ export class SaveProject { return loadedScriptAccounts; } + static loadGamesystems(projectDir: string): LoadModel[] { + const gamesystemDir = path.join(projectDir, "gamesystems"); + const loadedGamesystems = this.loadGamesystemsRecursively(gamesystemDir); + console.log("LoadedGamesystems: ", loadedGamesystems.length); + return loadedGamesystems; + } + + static loadGamesystemsRecursively(gamesystemDir: string): LoadModel[] { + let loadedGamesystems: LoadModel[] = []; + const gamesystemFileNames = fs.readdirSync(gamesystemDir); + + gamesystemFileNames.forEach(fileName => { + const gamesystemPath = path.join(gamesystemDir, fileName); + + if(fs.lstatSync(gamesystemPath).isDirectory()) { + const childModels: LoadModel[] = SaveProject.loadGamesystemsRecursively(gamesystemPath); + loadedGamesystems = loadedGamesystems.concat(childModels); + } else { + const gamesystemData = fs.readFileSync(path.join(gamesystemDir, fileName), "utf-8"); + if(path.parse(fileName).name === path.basename(gamesystemDir) ) { + if((path.basename(gamesystemDir) === path.parse(fileName).name) && path.basename(path.parse(gamesystemDir).dir) === "gamesystems") { + const loadedModel = new LoadModel(gamesystemData, ModelComponentType.GAMESYTEM); + loadedGamesystems.unshift(loadedModel) + } else { + const loadedModel = new RecursiveLoadModel(gamesystemData, ModelComponentType.GAMESYTEM, path.basename(gamesystemDir)) + loadedGamesystems.unshift(loadedModel); + } + + } else { + const secondCon = path.basename(gamesystemDir) === path.parse(fileName).name + const thirdCon = path.basename(path.parse(gamesystemDir).dir) === "gamesystems" + + if(path.basename(gamesystemDir) === "gamesystems"){ + const loadedModel = new LoadModel(gamesystemData, ModelComponentType.GAMESYTEM) + loadedGamesystems.push(loadedModel); + } else { + + const loadedModel = new RecursiveLoadModel(gamesystemData, ModelComponentType.GAMESYTEM, path.basename(gamesystemDir)) + loadedGamesystems.push(loadedModel); + } + + } + } + }) + return loadedGamesystems; + } + } diff --git a/e2e/game-model/gamesystems/productGamesystems/ProductStateTrainer.ts b/e2e/game-model/gamesystems/productGamesystems/ProductStateTrainer.ts index a0d09a4..e473f9f 100644 --- a/e2e/game-model/gamesystems/productGamesystems/ProductStateTrainer.ts +++ b/e2e/game-model/gamesystems/productGamesystems/ProductStateTrainer.ts @@ -16,13 +16,13 @@ export class ProductStateTrainer { static PRODUCT_GAMESYSTEM_NAME = "Product Gamesystem"; static givenFullProductGamesystemWithTwoStates() { - const letter_Gamesystem = new SimpleGamesystem(this.LETTERS_GAMESYSTEM_NAME); + const letter_Gamesystem = new SimpleGamesystem(this.LETTERS_GAMESYSTEM_NAME, ""); const letter_1 = letter_Gamesystem.createState(this.INNERSTATE_LETTER_1, "")!; const letter_2 = letter_Gamesystem.createState(this.INNERSTATE_LETTER_2, "")!; - const number_gamesystem = new SimpleGamesystem(this.NUMBERS_GAMESYSTEM_NAME); + const number_gamesystem = new SimpleGamesystem(this.NUMBERS_GAMESYSTEM_NAME, ""); const number_1 = number_gamesystem.createState(this.INNERSTATE_NUMBER_1, "")!; const number_2 = number_gamesystem.createState(this.INNERSTATE_NUMBER_2, "")!; - const productGamesystem = new ProductGamesystem(this.PRODUCT_GAMESYSTEM_NAME); + const productGamesystem = new ProductGamesystem(this.PRODUCT_GAMESYSTEM_NAME, ""); productGamesystem.states.push(new ProductState( [letter_1, number_1])); productGamesystem.states.push(new ProductState( [letter_1, number_2])); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 012ba8f..2c24f78 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -63,25 +63,6 @@ export class AppComponent implements OnInit{ electronService.ipcRenderer.on('open-project', (event: any, loadedProject: LoadedProject) => { this.gameModel = ProcessLoadedProject.processLoadedProject(loadedProject) - const weather = new SimpleGamesystem("Weather"); - const season = new SimpleGamesystem("Season"); - - const springState = season.createState("Spring", "Spring, also known as springtime, is one of the four temperate seasons, succeeding winter and preceding summer."); - const summerState = season.createState("Summer", "Summer is the hottest and brightest of the four temperate seasons, occurring after spring and before autumn. "); - - const sunnyState = weather.createState("Sunny", "The sun is shining. No clouds, no rain, no storm."); - const rainingState = weather.createState("Raining", "It rains") - - season.createTransition(springState!, summerState!); - weather.createTransition(sunnyState!, rainingState!); - - const weather_season = new ProductGamesystem("Weather-Season"); - weather_season.addChildGamesystem(weather); - weather_season.addChildGamesystem(season); - - weather_season.createState([springState!, sunnyState!]); - - this.gameModel.addGamesystem(weather_season); }) } else { console.log('Run in browser'); diff --git a/src/app/game-model/GameModel.ts b/src/app/game-model/GameModel.ts index 0b1a189..487f53f 100644 --- a/src/app/game-model/GameModel.ts +++ b/src/app/game-model/GameModel.ts @@ -50,7 +50,7 @@ export class GameModel { createGamesystem(gamesystemName: string, parentGamesystemName: string | undefined) { if(gamesystemName != undefined && this.findGamesystem(gamesystemName) == undefined) { - const simpleGamesystem = new SimpleGamesystem(gamesystemName); + const simpleGamesystem = new SimpleGamesystem(gamesystemName, ""); if(parentGamesystemName != undefined) { const parentGamesystem = this.findGamesystem(parentGamesystemName); if(parentGamesystem instanceof SimpleGamesystem) { diff --git a/src/app/game-model/fs/ProcessLoadedProject.ts b/src/app/game-model/fs/ProcessLoadedProject.ts index 3aca7ac..0d379df 100644 --- a/src/app/game-model/fs/ProcessLoadedProject.ts +++ b/src/app/game-model/fs/ProcessLoadedProject.ts @@ -3,6 +3,11 @@ import {LoadedProject} from "../../../../app/LoadedProject"; import {LoadModel} from "../../../../app/LoadModel"; import {ModelComponentType} from "../ModelComponentType"; import {ScriptAccount} from "../scriptAccounts/ScriptAccount"; +import {RecursiveLoadModel} from "../../../../app/RecursiveLoadModel"; +import {SimpleGamesystemParser} from "./parser/SimpleGamesystemParser"; +import {SimpleGamesystem} from "../gamesystems/SimpleGamesystem"; +import {ProductGamesystem} from "../gamesystems/ProductGamesystem"; +import {ProductGamesystemParser} from "./parser/ProductGamesystemParser"; export class ProcessLoadedProject { @@ -25,6 +30,36 @@ export class ProcessLoadedProject { } static processLoadedGamesystem(gameModel: GameModel, loadedModel: LoadModel) { - + const parsedJsonString = JSON.parse(loadedModel.jsonString); + if(loadedModel.hasOwnProperty('parentLoadModelname')) { + const recursiveLoadModel = loadedModel as RecursiveLoadModel + console.log("Loaded Model should be an instance of recursivemodel") + if(parsedJsonString.hasOwnProperty('states') && parsedJsonString.hasOwnProperty('transitions')) { + //SimpleGamesystem + const simpleGamesystem: SimpleGamesystem = SimpleGamesystemParser.parseSimpleGamesystem(parsedJsonString); + const parentModel: ProductGamesystem = gameModel.findGamesystem(recursiveLoadModel.parentLoadModelname) as ProductGamesystem + parentModel.addChildGamesystem(simpleGamesystem); + } else { + console.log("Gamesystems: ", ) + //ProductGamesystem + const productGamesystem: ProductGamesystem = ProductGamesystemParser.parseProductGamesystem(parsedJsonString); + const parentModel: ProductGamesystem = gameModel.findGamesystem(recursiveLoadModel.parentLoadModelname) as ProductGamesystem; + parentModel.addChildGamesystem(productGamesystem); + } + } else { + //Top Gamesystem + if(parsedJsonString.hasOwnProperty('states') && parsedJsonString.hasOwnProperty('transitions')) { + //SimpleGamesystem + const simpleGamesystem: SimpleGamesystem = SimpleGamesystemParser.parseSimpleGamesystem(parsedJsonString); + gameModel.addGamesystem(simpleGamesystem); + } else { + //ProductGamesystem + const productGamesystem = ProductGamesystemParser.parseProductGamesystem(parsedJsonString); + console.log("Generated Productsystem: ", productGamesystem) + gameModel.addGamesystem(productGamesystem); + } + } } + + } diff --git a/src/app/game-model/fs/parser/ProductGamesystemParser.ts b/src/app/game-model/fs/parser/ProductGamesystemParser.ts new file mode 100644 index 0000000..612f7bd --- /dev/null +++ b/src/app/game-model/fs/parser/ProductGamesystemParser.ts @@ -0,0 +1,9 @@ +import {ProductGamesystem} from "../../gamesystems/ProductGamesystem"; + +export class ProductGamesystemParser { + static parseProductGamesystem(jsonObject: any): ProductGamesystem { + const componentName = jsonObject.componentName; + const componentDescript = jsonObject.componentDescription; + return new ProductGamesystem(componentName, componentDescript); + } +} diff --git a/src/app/game-model/fs/parser/SimpleGamesystemParser.ts b/src/app/game-model/fs/parser/SimpleGamesystemParser.ts new file mode 100644 index 0000000..b36c282 --- /dev/null +++ b/src/app/game-model/fs/parser/SimpleGamesystemParser.ts @@ -0,0 +1,47 @@ +import {SimpleGamesystem} from "../../gamesystems/SimpleGamesystem"; +import {SimpleState} from "../../gamesystems/SimpleState"; +import {SimpleTransition} from "../../gamesystems/SimpleTransition"; + +export class SimpleGamesystemParser { + + static parseSimpleGamesystem(jsonObject: any) : SimpleGamesystem { + const gamesystemName = jsonObject.componentName; + const gamesystemDescription = jsonObject.componentDescription; + const simpleStates = SimpleGamesystemParser.parseSimpleStates(jsonObject) + const simpleTransitions = SimpleGamesystemParser.parseSimpleTransitions(jsonObject, simpleStates); + + const gamesystem = new SimpleGamesystem(gamesystemName, gamesystemDescription); + gamesystem.states = simpleStates; + gamesystem.transitions = simpleTransitions; + + return gamesystem; + } + + static parseSimpleStates(jsonObject: any): SimpleState[] { + const states: SimpleState[] = []; + for(let i=0; i state.stateLabel === startingStateLabel); + const endingState = states.find(state => state.stateLabel === endingStateLabel); + + if(startingState != undefined && endingState != undefined) { + transitions.push(new SimpleTransition(startingState, endingState)); + } else { + console.error("Starting or Ending State are not defined!", startingState, endingState) + } + } + return transitions; + } +} diff --git a/src/app/game-model/gamesystems/Gamesystem.ts b/src/app/game-model/gamesystems/Gamesystem.ts index a1f0d5c..e182c25 100644 --- a/src/app/game-model/gamesystems/Gamesystem.ts +++ b/src/app/game-model/gamesystems/Gamesystem.ts @@ -7,8 +7,8 @@ export abstract class Gamesystem extends ModelComponent{ states: S[] = []; transitions: T[] = []; - constructor(gamesystemName: string) { - super(gamesystemName, "", ModelComponentType.GAMESYTEM); + constructor(gamesystemName: string, gamesystemDescription: string) { + super(gamesystemName, gamesystemDescription, ModelComponentType.GAMESYTEM); } abstract createTransition(startingState: S, endingState: S): T|undefined; diff --git a/src/app/game-model/gamesystems/ProductGamesystem.ts b/src/app/game-model/gamesystems/ProductGamesystem.ts index ecef1d3..b81b194 100644 --- a/src/app/game-model/gamesystems/ProductGamesystem.ts +++ b/src/app/game-model/gamesystems/ProductGamesystem.ts @@ -14,7 +14,7 @@ export class ProductGamesystem extends Gamesystem 0) { @@ -77,7 +77,7 @@ export class ProductGamesystem extends Gamesystem, rightSystem: Gamesystem, left_temp: boolean, integratedSystems: Gamesystem[]) { - const productGamesystem = new ProductGamesystem("Temporary Gamesystem"); + const productGamesystem = new ProductGamesystem("Temporary Gamesystem", ""); integratedSystems.forEach(integratedSystem => productGamesystem.addChildGamesystem(integratedSystem)); leftSystem.states.forEach(leftState => { diff --git a/src/app/game-model/gamesystems/SimpleGamesystem.ts b/src/app/game-model/gamesystems/SimpleGamesystem.ts index e9e73b0..d5b4f1f 100644 --- a/src/app/game-model/gamesystems/SimpleGamesystem.ts +++ b/src/app/game-model/gamesystems/SimpleGamesystem.ts @@ -10,6 +10,8 @@ export class SimpleGamesystem extends Gamesystem parentGamesystem: ProductGamesystem | undefined + + createState(label: string, description: string): SimpleState | undefined { if(label == null) { return undefined; From a93a7411a3877b5095235d6d9759737ac9bd5af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Sat, 17 Feb 2024 14:40:07 +0100 Subject: [PATCH 6/6] Generate Productgamesystem States + Transition after loading them --- src/app/game-model/fs/ProcessLoadedProject.ts | 11 +++++++++++ .../game-model/gamesystems/ProductGamesystem.ts | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/app/game-model/fs/ProcessLoadedProject.ts b/src/app/game-model/fs/ProcessLoadedProject.ts index 0d379df..b6fe4d1 100644 --- a/src/app/game-model/fs/ProcessLoadedProject.ts +++ b/src/app/game-model/fs/ProcessLoadedProject.ts @@ -8,15 +8,26 @@ import {SimpleGamesystemParser} from "./parser/SimpleGamesystemParser"; import {SimpleGamesystem} from "../gamesystems/SimpleGamesystem"; import {ProductGamesystem} from "../gamesystems/ProductGamesystem"; import {ProductGamesystemParser} from "./parser/ProductGamesystemParser"; +import {Gamesystem} from "../gamesystems/Gamesystem"; export class ProcessLoadedProject { static processLoadedProject(loadedProject: LoadedProject): GameModel { const gameModel = new GameModel(loadedProject.projectName); loadedProject.loadedModels.forEach(loadedModel => this.processLoadedModel(gameModel, loadedModel)) + //Generate product Gamesystems + this.generateProductGamesystems(gameModel.gamesystems) return gameModel; } + static generateProductGamesystems(gamesystems: Gamesystem[]) { + gamesystems.forEach(gamesystem => { + if(gamesystem instanceof ProductGamesystem) { + gamesystem.generateFromChildsystems(); + } + }) + } + static processLoadedModel(gameModel: GameModel, loadedModel: LoadModel) { switch (loadedModel.modelType) { case ModelComponentType.SCRIPTACCOUNT: this.processLoadedScriptAccount(gameModel, loadedModel); break; diff --git a/src/app/game-model/gamesystems/ProductGamesystem.ts b/src/app/game-model/gamesystems/ProductGamesystem.ts index b81b194..7795942 100644 --- a/src/app/game-model/gamesystems/ProductGamesystem.ts +++ b/src/app/game-model/gamesystems/ProductGamesystem.ts @@ -65,10 +65,25 @@ export class ProductGamesystem extends Gamesystem[] = [this.innerGamesystems[0], this.innerGamesystems[1]]; + if(this.innerGamesystems[0] instanceof ProductGamesystem) { + this.innerGamesystems[0].generateFromChildsystems(); + } + + if(this.innerGamesystems[1] instanceof ProductGamesystem) { + this.innerGamesystems[1].generateFromChildsystems(); + } let gamesystem: ProductGamesystem = ProductGamesystem.generateFromChildsystems(this.innerGamesystems[0], this.innerGamesystems[1], false, integratedSystems); for(let i=2; i