issue-15 #21

Merged
sebastian merged 60 commits from issue-15 into main 2024-03-22 08:46:49 +01:00
133 changed files with 2825 additions and 765 deletions

View File

@ -3,7 +3,8 @@
"ignorePatterns": [
"app/**/*", // ignore nodeJs files
"dist/**/*",
"release/**/*"
"release/**/*",
"src/**/*"
],
"overrides": [
{

View File

@ -1,11 +0,0 @@
"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

View File

@ -1,12 +0,0 @@
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;
}
}

View File

@ -1,11 +0,0 @@
"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

View File

@ -1,12 +0,0 @@
import {LoadModel} from "./LoadModel";
export class LoadedProject {
projectName: string
loadedModels: LoadModel[]
constructor(projectName: string, loadedModels: LoadModel[]) {
this.projectName = projectName;
this.loadedModels = loadedModels;
}
}

View File

@ -1,12 +0,0 @@
"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

View File

@ -1,12 +0,0 @@
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;
}
}

View File

@ -1,100 +0,0 @@
"use strict";
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)) {
fs.mkdirSync(projectDir, { recursive: true });
}
console.log(storageModels);
storageModels.forEach(storageModel => {
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 });
}
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);
}
else {
console.log('JSON file saved successfully:', filePath);
}
});
});
}
static loadProject(projectDir) {
let loadedScriptAccounts = SaveProject.loadScriptAccounts(projectDir);
loadedScriptAccounts = loadedScriptAccounts.concat(SaveProject.loadGamesystems(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;
}
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

View File

@ -1,110 +0,0 @@
import {StorageModel} from "../src/app/game-model/fs/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 {LoadedProject} from "./LoadedProject";
import {RecursiveLoadModel} from "./RecursiveLoadModel";
export class SaveProject {
static saveProject(projectDir: string, storageModels: StorageModel[]) {
if(!fs.existsSync(projectDir)) {
fs.mkdirSync(projectDir, {recursive: true});
}
console.log(storageModels)
storageModels.forEach(storageModel => {
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});
}
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);
} else {
console.log('JSON file saved successfully:', filePath);
}
})
})
}
static loadProject(projectDir: string) {
let loadedScriptAccounts: LoadModel[] = SaveProject.loadScriptAccounts(projectDir)
loadedScriptAccounts = loadedScriptAccounts.concat(SaveProject.loadGamesystems(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;
}
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;
}
}

View File

@ -1,12 +0,0 @@
class StorageModel {
jsonString: string
fileName: string
storageDir: string
constructor(jsonString: string, fileName: string, storageDir: string) {
this.jsonString = jsonString;
this.fileName = fileName;
this.storageDir = storageDir;
}
}

View File

@ -1,9 +1,11 @@
import {app, BrowserWindow, screen, Menu, ipcMain, dialog, globalShortcut} from 'electron';
import {app, BrowserWindow, dialog, globalShortcut, ipcMain, Menu, screen} 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/fs/StorageModel";
import {SaveProject} from "./SaveProject";
import {GameModelLoader} from "./storage/loader/GameModelLoader";
import {StoredGameModel} from "./storage/StoredGameModel";
import {ScriptAccountStorage} from "./storage/storing/ScriptAccountStoring";
import {ModelComponentFileDirectory} from "./storage/ModelComponentFileDirectory";
import {GamesystemStorage} from "./storage/storing/GamesystemStorage";
let win: BrowserWindow | null = null;
const args = process.argv.slice(1),
@ -94,11 +96,15 @@ function createWindow(): BrowserWindow {
contextMenu.popup({ window: win!, x: params.x, y: params.y });
})
ipcMain.on('save-model', (event, storageModels: StorageModel[]) => {
console.log("Save Model")
SaveProject.saveProject(projectDirectory, storageModels);
ipcMain.on('save-model', (event, storedGameModel: StoredGameModel) => {
recieveGameModelToStore(storedGameModel)
})
/*ipcMain.on('delete-component', (event, deletedComponent: DeleteModel) => {
console.log("Delete Model: ", deletedComponent)
deleteComponent(deletedComponent);
})*/
const menuTemplate = [
{
label: 'File',
@ -127,6 +133,10 @@ function createWindow(): BrowserWindow {
const menu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menu)
win.webContents.on('did-finish-load', () => {
loadDevProjectAtStart()
})
return win;
}
@ -160,6 +170,10 @@ try {
})
})
} catch (e) {
// Catch Error
// throw e;
@ -179,13 +193,39 @@ function openProject() {
})
if(selectedPaths != undefined) {
projectDirectory = selectedPaths[0];
console.log("Open Project-Directory: ", projectDirectory)
const loadedProject = SaveProject.loadProject(projectDirectory)
win!.webContents.send("open-project", loadedProject)
openProjectFromFile(selectedPaths[0])
}
}
function loadDevProjectAtStart() {
const projectDir = path.join(process.cwd(), "testModel/")
openProjectFromFile(projectDir)
}
function openProjectFromFile(openProjectDir: string) {
projectDirectory = openProjectDir
const gameModelLoader = new GameModelLoader(openProjectDir);
const loadedProject = gameModelLoader.loadGameModel();
win!.webContents.send("open-project", loadedProject)
}
function saveProject() {
win!.webContents.send('get-project-data')
}
function recieveGameModelToStore(gameModel: StoredGameModel) {
const scriptAccountStorage = new ScriptAccountStorage(path.join(projectDirectory, ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME))
scriptAccountStorage.storeScriptAccounts(gameModel.storedScriptAccounts)
const gamesystemStorage = new GamesystemStorage(path.join(projectDirectory, ModelComponentFileDirectory.GAMESYSTEM_DIR_NAME))
gamesystemStorage.storeGamesystems(gameModel.storedGamesystems)
}
/*function deleteComponent(component: DeleteModel) {
console.log("Delete Component")
if(component.modeltype == ModelComponentType.SCRIPTACCOUNT) {
DeleteTransaction.deleteScriptAccount(projectDirectory, component.componentName);
} else if(component.modeltype === ModelComponentType.GAMESYTEM) {
DeleteTransaction.deleteGamesystem(projectDirectory, component.componentName);
}
}*/

34
app/storage/FileUtils.js Normal file
View File

@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileUtils = void 0;
const fs = require("fs");
const path = require("node:path");
const fs_1 = require("fs");
class FileUtils {
static listFilesInDirectory(directory) {
if (fs.lstatSync(directory).isDirectory()) {
return fs.readdirSync(directory).map(fileName => path.join(directory, fileName));
}
else {
return [];
}
}
static prepareFileForWriting(file) {
const parentDirectory = path.dirname(file);
if (!fs.existsSync(parentDirectory)) {
(0, fs_1.mkdirSync)(parentDirectory, { recursive: true });
}
}
static removeFiles(files) {
files.forEach(file => {
if (fs.lstatSync(file).isDirectory()) {
fs.rmdirSync(file);
}
else {
fs.unlinkSync(file);
}
});
}
}
exports.FileUtils = FileUtils;
//# sourceMappingURL=FileUtils.js.map

33
app/storage/FileUtils.ts Normal file
View File

@ -0,0 +1,33 @@
import * as fs from "fs";
import * as path from "node:path";
import {mkdirSync} from "fs";
import {lstatSync} from "node:fs";
export class FileUtils {
public static listFilesInDirectory(directory: string) {
if(fs.lstatSync(directory).isDirectory()) {
return fs.readdirSync(directory).map(fileName => path.join(directory, fileName))
} else {
return [];
}
}
public static prepareFileForWriting(file: string) {
const parentDirectory = path.dirname(file)
if(!fs.existsSync(parentDirectory)) {
mkdirSync(parentDirectory, {recursive: true})
}
}
public static removeFiles(files: string[]) {
files.forEach(file => {
if(fs.lstatSync(file).isDirectory()) {
fs.rmdirSync(file)
} else {
fs.unlinkSync(file);
}
})
}
}

View File

@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModelComponentFileDirectory = void 0;
class ModelComponentFileDirectory {
}
exports.ModelComponentFileDirectory = ModelComponentFileDirectory;
ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME = "script-accounts";
ModelComponentFileDirectory.GAMESYSTEM_DIR_NAME = "gamesystems";
ModelComponentFileDirectory.GAMESYSTEM_SIMPLE_DIR_NAME = "simple";
ModelComponentFileDirectory.GAMESYSTEM_PRODUCT_DIR_NAME = "product";
//# sourceMappingURL=ModelComponentFileDirectory.js.map

View File

@ -0,0 +1,6 @@
export class ModelComponentFileDirectory {
public static SCRIPTACCOUNT_DIR_NAME = "script-accounts"
public static GAMESYSTEM_DIR_NAME = "gamesystems";
public static GAMESYSTEM_SIMPLE_DIR_NAME = "simple";
public static GAMESYSTEM_PRODUCT_DIR_NAME = "product";
}

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StoreComponent = void 0;
class StoreComponent {
constructor(jsonString, fileName, componentType) {
this.jsonString = jsonString;
this.fileName = fileName;
this.componentType = componentType;
}
}
exports.StoreComponent = StoreComponent;
//# sourceMappingURL=StoreComponent.js.map

View File

@ -0,0 +1,13 @@
import {ModelComponentType} from "../../src/app/project/game-model/ModelComponentType";
export class StoreComponent {
jsonString: string
fileName: string
componentType: ModelComponentType
constructor(jsonString: string, fileName: string, componentType: ModelComponentType) {
this.jsonString = jsonString;
this.fileName = fileName;
this.componentType = componentType
}
}

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StoredGameModel = void 0;
class StoredGameModel {
constructor(gameModelName, storedScriptAccounts, storedGamesystems) {
this.gameModelName = gameModelName;
this.storedGamesystems = storedGamesystems;
this.storedScriptAccounts = storedScriptAccounts;
}
}
exports.StoredGameModel = StoredGameModel;
//# sourceMappingURL=StoredGameModel.js.map

View File

@ -0,0 +1,15 @@
import {StoreComponent} from "./StoreComponent";
export class StoredGameModel {
gameModelName: string
storedGamesystems: StoreComponent[]
storedScriptAccounts: StoreComponent[]
constructor(gameModelName: string, storedScriptAccounts: StoreComponent[], storedGamesystems: StoreComponent[]) {
this.gameModelName = gameModelName;
this.storedGamesystems = storedGamesystems;
this.storedScriptAccounts = storedScriptAccounts;
}
}

View File

@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GameModelLoader = void 0;
const StoredGameModel_1 = require("../StoredGameModel");
const path = require("node:path");
const ModelComponentFileDirectory_1 = require("../ModelComponentFileDirectory");
const ScriptAccountLoader_1 = require("./ScriptAccountLoader");
const GamesystemLoader_1 = require("./GamesystemLoader");
class GameModelLoader {
constructor(gameModelDir) {
this.gameModelDir = gameModelDir;
}
loadGameModel() {
const gameModelName = path.basename(this.gameModelDir);
const storedScriptAccounts = this.loadScriptAccountComponents();
const storedGamesystems = this.loadGamesystems();
return new StoredGameModel_1.StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems);
}
loadScriptAccountComponents() {
const scriptAccountDir = path.join(this.gameModelDir, ModelComponentFileDirectory_1.ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME);
const scriptAccountLoader = new ScriptAccountLoader_1.ScriptAccountLoader(scriptAccountDir);
return scriptAccountLoader.loadScriptAccounts();
}
loadGamesystems() {
const gamesystemDir = path.join(this.gameModelDir, ModelComponentFileDirectory_1.ModelComponentFileDirectory.GAMESYSTEM_DIR_NAME);
const gamesystemLoader = new GamesystemLoader_1.GamesystemLoader(gamesystemDir);
return gamesystemLoader.loadGamesystems();
}
}
exports.GameModelLoader = GameModelLoader;
//# sourceMappingURL=GameModelLoader.js.map

View File

@ -0,0 +1,42 @@
import {StoredGameModel} from "../StoredGameModel";
import {StoreComponent} from "../StoreComponent";
import * as path from "node:path";
import * as fs from "fs";
import {ModelComponentFileDirectory} from "../ModelComponentFileDirectory";
import {ScriptAccountLoader} from "./ScriptAccountLoader";
import {GamesystemLoader} from "./GamesystemLoader";
export class GameModelLoader {
gameModelDir: string
constructor(gameModelDir: string) {
this.gameModelDir = gameModelDir;
}
loadGameModel(): StoredGameModel {
const gameModelName = path.basename(this.gameModelDir)
const storedScriptAccounts = this.loadScriptAccountComponents();
const storedGamesystems = this.loadGamesystems();
return new StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems);
}
private loadScriptAccountComponents() {
const scriptAccountDir = path.join(this.gameModelDir, ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME);
const scriptAccountLoader = new ScriptAccountLoader(scriptAccountDir);
return scriptAccountLoader.loadScriptAccounts()
}
private loadGamesystems(): StoreComponent[] {
const gamesystemDir = path.join(this.gameModelDir, ModelComponentFileDirectory.GAMESYSTEM_DIR_NAME);
const gamesystemLoader = new GamesystemLoader(gamesystemDir);
return gamesystemLoader.loadGamesystems();
}
}

View File

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GamesystemLoader = void 0;
const StoreComponent_1 = require("../StoreComponent");
const FileUtils_1 = require("../FileUtils");
const fs = require("fs");
const path = require("node:path");
const ModelComponentType_1 = require("../../../src/app/project/game-model/ModelComponentType");
class GamesystemLoader {
constructor(gamesystemDir) {
this.gamesystemDir = gamesystemDir;
}
loadGamesystems() {
return this.loadGamesystemsRecursivly(this.gamesystemDir);
}
loadGamesystemsRecursivly(currentGamesystemDir) {
let loadedGamesystems = [];
const gamesystemFiles = FileUtils_1.FileUtils.listFilesInDirectory(currentGamesystemDir);
gamesystemFiles.forEach(gamesystemFile => {
if (fs.lstatSync(gamesystemFile).isDirectory()) {
const childGamesystems = this.loadGamesystemsRecursivly(gamesystemFile);
loadedGamesystems = loadedGamesystems.concat(childGamesystems);
}
else if (path.basename(gamesystemFile).endsWith(".json")) {
const loadedGamesystem = this.loadGamesystem(gamesystemFile);
if (loadedGamesystem != undefined) {
loadedGamesystems.push(loadedGamesystem);
}
}
});
return loadedGamesystems;
}
loadGamesystem(gamesystemFile) {
if (gamesystemFile.endsWith(".json")) {
const gamesystemData = fs.readFileSync(gamesystemFile, 'utf-8');
return new StoreComponent_1.StoreComponent(gamesystemData, gamesystemFile, ModelComponentType_1.ModelComponentType.GAMESYTEM);
}
}
}
exports.GamesystemLoader = GamesystemLoader;
//# sourceMappingURL=GamesystemLoader.js.map

View File

@ -0,0 +1,44 @@
import {StoreComponent} from "../StoreComponent";
import {FileUtils} from "../FileUtils";
import * as fs from "fs";
import * as path from "node:path";
import {ModelComponentType} from "../../../src/app/project/game-model/ModelComponentType";
export class GamesystemLoader {
gamesystemDir: string
constructor(gamesystemDir: string) {
this.gamesystemDir = gamesystemDir;
}
loadGamesystems() {
return this.loadGamesystemsRecursivly(this.gamesystemDir)
}
private loadGamesystemsRecursivly(currentGamesystemDir: string) {
let loadedGamesystems: StoreComponent[] = []
const gamesystemFiles = FileUtils.listFilesInDirectory(currentGamesystemDir);
gamesystemFiles.forEach(gamesystemFile => {
if(fs.lstatSync(gamesystemFile).isDirectory()) {
const childGamesystems = this.loadGamesystemsRecursivly(gamesystemFile);
loadedGamesystems = loadedGamesystems.concat(childGamesystems);
} else if(path.basename(gamesystemFile).endsWith(".json")) {
const loadedGamesystem = this.loadGamesystem(gamesystemFile);
if(loadedGamesystem != undefined) {
loadedGamesystems.push(loadedGamesystem);
}
}
})
return loadedGamesystems;
}
private loadGamesystem(gamesystemFile: string) {
if(gamesystemFile.endsWith(".json")) {
const gamesystemData = fs.readFileSync(gamesystemFile, 'utf-8');
return new StoreComponent(gamesystemData, gamesystemFile, ModelComponentType.GAMESYTEM);
}
}
}

View File

@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScriptAccountLoader = void 0;
const StoreComponent_1 = require("../StoreComponent");
const FileUtils_1 = require("../FileUtils");
const ModelComponentType_1 = require("../../../src/app/project/game-model/ModelComponentType");
const fs = require("fs");
class ScriptAccountLoader {
constructor(scriptAccountDir) {
this.scriptAccountDir = scriptAccountDir;
}
loadScriptAccounts() {
const scriptAccountFiles = FileUtils_1.FileUtils.listFilesInDirectory(this.scriptAccountDir);
const loadedScriptAccounts = [];
scriptAccountFiles.forEach(scriptAccountFile => {
const loadedScriptAccount = this.loadScriptAccount(scriptAccountFile);
if (loadedScriptAccount != undefined) {
loadedScriptAccounts.push(loadedScriptAccount);
}
});
return loadedScriptAccounts;
}
loadScriptAccount(scriptAccountFile) {
if (scriptAccountFile.endsWith(".json")) {
const scriptAccountData = fs.readFileSync(scriptAccountFile, 'utf-8');
return new StoreComponent_1.StoreComponent(scriptAccountData, scriptAccountFile, ModelComponentType_1.ModelComponentType.SCRIPTACCOUNT);
}
}
}
exports.ScriptAccountLoader = ScriptAccountLoader;
//# sourceMappingURL=ScriptAccountLoader.js.map

View File

@ -0,0 +1,34 @@
import {StoreComponent} from "../StoreComponent";
import {FileUtils} from "../FileUtils";
import {ModelComponentType} from "../../../src/app/project/game-model/ModelComponentType";
import * as fs from "fs";
import {ModelComponentFileDirectory} from "../ModelComponentFileDirectory";
import {load} from "@angular-devkit/build-angular/src/utils/server-rendering/esm-in-memory-loader/loader-hooks";
export class ScriptAccountLoader {
scriptAccountDir: string
constructor(scriptAccountDir: string) {
this.scriptAccountDir = scriptAccountDir;
}
loadScriptAccounts(): StoreComponent[] {
const scriptAccountFiles = FileUtils.listFilesInDirectory(this.scriptAccountDir);
const loadedScriptAccounts: StoreComponent[] = []
scriptAccountFiles.forEach(scriptAccountFile => {
const loadedScriptAccount = this.loadScriptAccount(scriptAccountFile);
if(loadedScriptAccount != undefined) {
loadedScriptAccounts.push(loadedScriptAccount)
}
})
return loadedScriptAccounts;
}
private loadScriptAccount(scriptAccountFile: string) {
if(scriptAccountFile.endsWith(".json")) {
const scriptAccountData = fs.readFileSync(scriptAccountFile, 'utf-8');
return new StoreComponent(scriptAccountData, scriptAccountFile, ModelComponentType.SCRIPTACCOUNT);
}
}
}

View File

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GamesystemStorage = void 0;
const FileUtils_1 = require("../FileUtils");
const path = require("node:path");
const fs = require("fs");
class GamesystemStorage {
constructor(gamesystemRootDir) {
this.gamesystemRootDir = gamesystemRootDir;
}
storeGamesystems(gamesystems) {
const unreferencedFiles = this.detectUnusedGamesystemFiles(gamesystems);
FileUtils_1.FileUtils.removeFiles(unreferencedFiles);
gamesystems.forEach(gamesystem => this.storeGamesystem(gamesystem));
}
detectUnusedGamesystemFiles(gamesystems) {
const unreferencedFiles = [];
const gamesystemFiles = FileUtils_1.FileUtils.listFilesInDirectory(this.gamesystemRootDir);
while (gamesystemFiles.length > 0) {
const currentGamesystemFile = gamesystemFiles.shift();
const referencedGamesystemName = path.parse(path.basename(currentGamesystemFile)).name;
const referencedGamesystem = this.findReferencedGamesystem(referencedGamesystemName, gamesystems);
if (referencedGamesystem == undefined) {
unreferencedFiles.push(currentGamesystemFile);
}
else {
const decodedJSONData = JSON.parse(referencedGamesystem.jsonString);
if (decodedJSONData.childsystems != undefined) {
//Check if current file is a directory. When it is a directory, everything is fine
if (fs.lstatSync(currentGamesystemFile).isDirectory()) {
}
else {
const parentDirName = path.basename(path.dirname(currentGamesystemFile));
if (parentDirName !== referencedGamesystemName) {
unreferencedFiles.push(currentGamesystemFile);
}
}
}
}
if (fs.lstatSync(currentGamesystemFile).isDirectory()) {
gamesystemFiles.push(...FileUtils_1.FileUtils.listFilesInDirectory(currentGamesystemFile));
}
}
return unreferencedFiles;
}
findReferencedGamesystem(referencedName, gamesystems) {
return gamesystems.find(gamesystem => path.basename(gamesystem.fileName) === referencedName);
}
storeGamesystem(gamesystem) {
const gamesystemFile = path.join(...gamesystem.fileName.split("/"));
const completeGamesystemFile = path.join(this.gamesystemRootDir, gamesystemFile);
FileUtils_1.FileUtils.prepareFileForWriting(completeGamesystemFile);
fs.writeFileSync(completeGamesystemFile + ".json", gamesystem.jsonString, 'utf-8');
}
}
exports.GamesystemStorage = GamesystemStorage;
//# sourceMappingURL=GamesystemStorage.js.map

View File

@ -0,0 +1,64 @@
import {StoreComponent} from "../StoreComponent";
import {FileUtils} from "../FileUtils";
import * as path from "node:path";
import * as fs from "fs";
export class GamesystemStorage {
private gamesystemRootDir: string
constructor(gamesystemRootDir: string) {
this.gamesystemRootDir = gamesystemRootDir;
}
public storeGamesystems(gamesystems: StoreComponent[]) {
const unreferencedFiles = this.detectUnusedGamesystemFiles(gamesystems)
FileUtils.removeFiles(unreferencedFiles)
gamesystems.forEach(gamesystem => this.storeGamesystem(gamesystem))
}
private detectUnusedGamesystemFiles(gamesystems: StoreComponent[]) {
const unreferencedFiles: string[] = []
const gamesystemFiles = FileUtils.listFilesInDirectory(this.gamesystemRootDir);
while(gamesystemFiles.length > 0) {
const currentGamesystemFile = gamesystemFiles.shift()
const referencedGamesystemName = path.parse(path.basename(currentGamesystemFile!)).name
const referencedGamesystem = this.findReferencedGamesystem(referencedGamesystemName, gamesystems)
if(referencedGamesystem == undefined) {
unreferencedFiles.push(currentGamesystemFile!)
} else {
const decodedJSONData = JSON.parse(referencedGamesystem!.jsonString)
if(decodedJSONData.childsystems != undefined) {
//Check if current file is a directory. When it is a directory, everything is fine
if(fs.lstatSync(currentGamesystemFile!).isDirectory()) {
} else {
const parentDirName = path.basename(path.dirname(currentGamesystemFile!))
if(parentDirName !== referencedGamesystemName) {
unreferencedFiles.push(currentGamesystemFile!)
}
}
}
}
if(fs.lstatSync(currentGamesystemFile!).isDirectory()) {
gamesystemFiles.push(... FileUtils.listFilesInDirectory(currentGamesystemFile!))
}
}
return unreferencedFiles;
}
private findReferencedGamesystem(referencedName: string, gamesystems: StoreComponent[]): StoreComponent | undefined {
return gamesystems.find(gamesystem =>
path.basename(gamesystem.fileName) === referencedName)
}
private storeGamesystem(gamesystem: StoreComponent) {
const gamesystemFile = path.join(... gamesystem.fileName.split("/"))
const completeGamesystemFile = path.join(this.gamesystemRootDir, gamesystemFile)
FileUtils.prepareFileForWriting(completeGamesystemFile)
fs.writeFileSync(completeGamesystemFile + ".json", gamesystem.jsonString, 'utf-8')
}
}

View File

@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScriptAccountStorage = void 0;
const FileUtils_1 = require("../FileUtils");
const path = require("node:path");
const fs = require("fs");
class ScriptAccountStorage {
constructor(scriptAccountDir) {
this.scriptAccountDir = scriptAccountDir;
}
storeScriptAccounts(scriptAccounts) {
this.persistDeletedScriptAccounts(scriptAccounts);
scriptAccounts.forEach(scriptAccount => {
this.storeScriptAccount(scriptAccount);
});
}
persistDeletedScriptAccounts(existingScriptAccount) {
const scriptAccountFiles = FileUtils_1.FileUtils.listFilesInDirectory(this.scriptAccountDir);
scriptAccountFiles.forEach(scriptAccountFile => {
const scriptAccountFileName = path.parse(path.basename(scriptAccountFile)).name;
if (existingScriptAccount.find(scriptAccount => scriptAccount.fileName === scriptAccountFileName) == undefined) {
//No scriptAccountFile was found with that nae of the file. So the scriptAccount was deleted. Remove file
fs.unlinkSync(scriptAccountFile);
}
});
}
storeScriptAccount(scriptAccount) {
const completeScriptAccountFile = path.join(this.scriptAccountDir, scriptAccount.fileName + ".json");
fs.writeFileSync(completeScriptAccountFile, scriptAccount.jsonString, 'utf-8');
}
}
exports.ScriptAccountStorage = ScriptAccountStorage;
//# sourceMappingURL=ScriptAccountStoring.js.map

View File

@ -0,0 +1,36 @@
import {StoreComponent} from "../StoreComponent";
import {FileUtils} from "../FileUtils";
import * as path from "node:path";
import * as fs from "fs";
export class ScriptAccountStorage {
private scriptAccountDir: string
constructor(scriptAccountDir: string) {
this.scriptAccountDir = scriptAccountDir;
}
storeScriptAccounts(scriptAccounts: StoreComponent[]) {
this.persistDeletedScriptAccounts(scriptAccounts)
scriptAccounts.forEach(scriptAccount => {
this.storeScriptAccount(scriptAccount)
})
}
private persistDeletedScriptAccounts(existingScriptAccount: StoreComponent[]) {
const scriptAccountFiles = FileUtils.listFilesInDirectory(this.scriptAccountDir);
scriptAccountFiles.forEach(scriptAccountFile => {
const scriptAccountFileName = path.parse(path.basename(scriptAccountFile)).name
if(existingScriptAccount.find(scriptAccount => scriptAccount.fileName === scriptAccountFileName) == undefined) {
//No scriptAccountFile was found with that nae of the file. So the scriptAccount was deleted. Remove file
fs.unlinkSync(scriptAccountFile)
}
})
}
private storeScriptAccount(scriptAccount: StoreComponent) {
const completeScriptAccountFile = path.join(this.scriptAccountDir, scriptAccount.fileName + ".json")
fs.writeFileSync(completeScriptAccountFile, scriptAccount.jsonString, 'utf-8')
}
}

View File

@ -1,8 +1,8 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {GameModel} from "../../src/app/project/game-model/GameModel";
import {Gamesystem} from "../../src/app/project/game-model/gamesystems/Gamesystem";
test.describe('Adding Gamesystems', () => {

View File

@ -1,8 +1,9 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {Gamesystem} from "../../src/app/project/game-model/gamesystems/Gamesystem";
import {GameModel} from "../../src/app/project/game-model/GameModel";
test.describe('Removing Gamesystems', () => {

View File

@ -1,15 +1,6 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import exp = require("node:constants");
import {end} from "electron-debug";
import {GamesystemTrainer} from "./GamesystemTrainer";
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
import {ProductGamesystem} from "../../../src/app/project/game-model/gamesystems/ProductGamesystem";
test.describe('Test Create Gamesystems', () => {
test('Test creating gamesystem with invalid name', async => {

View File

@ -1,13 +1,6 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import exp = require("node:constants");
import {end} from "electron-debug";
import {GameModel} from "../../../src/app/project/game-model/GameModel";
import {SimpleGamesystem} from "../../../src/app/project/game-model/gamesystems/SimpleGamesystem";
import {GamesystemTrainer} from "./GamesystemTrainer";
test.describe('Test Find Gamesystems', () => {
const GAMEMODELNAME: string = "GameModel";

View File

@ -1,6 +1,6 @@
import {GameModel} from "../../../src/app/game-model/GameModel";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
import {GameModel} from "../../../src/app/project/game-model/GameModel";
import {SimpleGamesystem} from "../../../src/app/project/game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../../src/app/project/game-model/gamesystems/ProductGamesystem";
export class GamesystemTrainer {

View File

@ -1,13 +1,5 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import exp = require("node:constants");
import {end} from "electron-debug";
import {SimpleGamesystem} from "../../../src/app/project/game-model/gamesystems/SimpleGamesystem";
test.describe('Test SimpleGamesystem', () => {

View File

@ -0,0 +1,59 @@
import { test, expect } from '@playwright/test';
import {GamesystemTrainer} from "../GamesystemTrainer";
import {SimpleActionTrainer} from "./SimpleActionTrainer";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import {ScriptAccountAction} from "../../../../src/app/project/game-model/gamesystems/actions/ScriptAccountAction";
test.describe('Test Create SimpleActions', () => {
test('Test creating gamesystem with invalid name', async => {
const gameModel = GamesystemTrainer.givenEmptyGameModel();
let result = gameModel.createGamesystem(undefined, undefined);
expect(result).toBeUndefined();
result = gameModel.createGamesystem(null, undefined);
expect(result).toBeUndefined();
})
test("Adding invalid actions", async () => {
const transition = SimpleActionTrainer.withEmptyActions();
transition.addScriptAccountAction(null);
expect(transition.scriptAccountActions.length).toEqual(0);
transition.addScriptAccountAction(undefined);
expect(transition.scriptAccountActions.length).toEqual(0);
})
test("Adding not existing action", async () => {
const transition = SimpleActionTrainer.withEmptyActions();
const scriptAccount = new ScriptAccount("test", "");
const action = new ScriptAccountAction(scriptAccount, 10);
transition.addScriptAccountAction(action);
expect(transition.scriptAccountActions.length).toEqual(1);
expect(transition.scriptAccountActions[0].scriptAccount).toEqual(action.scriptAccount);
expect(transition.scriptAccountActions[0].changingValue).toEqual(10);
})
test("Adding existing action", async () => {
const transition = SimpleActionTrainer.withSingleAction();
const action = transition.scriptAccountActions[0];
transition.addScriptAccountAction(action);
expect(transition.scriptAccountActions.length).toEqual(1);
expect(transition.scriptAccountActions[0].changingValue).toEqual(20);
expect(transition.scriptAccountActions[0].scriptAccount).toEqual(action.scriptAccount);
})
test("Adding not existing action into non empty actions", async () => {
const transition = SimpleActionTrainer.withSingleAction();
const scriptAccount = new ScriptAccount("Tes", "");
transition.addScriptAccountAction(new ScriptAccountAction(scriptAccount, 10));
expect(transition.scriptAccountActions.length).toEqual(2);
})
});

View File

@ -0,0 +1,33 @@
import { test, expect } from '@playwright/test';
import {GamesystemTrainer} from "../GamesystemTrainer";
import {SimpleActionTrainer} from "./SimpleActionTrainer";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import {ScriptAccountAction} from "../../../../src/app/project/game-model/gamesystems/actions/ScriptAccountAction";
import {SimpleTransition} from "../../../../src/app/project/game-model/gamesystems/transitions/SimpleTransition";
test.describe('Test Remove SimpleActions', () => {
test("Test Removing invalid Actions", async () => {
const transition = SimpleActionTrainer.withSingleAction();
transition.removeScriptAccountAction(null);
expect(transition.scriptAccountActions.length).toEqual(1)
transition.removeScriptAccountAction(undefined);
expect(transition.scriptAccountActions.length).toEqual(1);
})
test("Test removing unknown scriptAccount Action", async () => {
const transition = SimpleActionTrainer.withSingleAction();
const scriptAccount = new ScriptAccount("Test");
transition.removeScriptAccountAction(scriptAccount);
expect(transition.scriptAccountActions.length).toEqual(1);
})
test("Test removing known ScriptAccount", async () => {
const transition = SimpleActionTrainer.withSingleAction();
transition.removeScriptAccountAction(transition.scriptAccountActions[0].scriptAccount)
expect(transition.scriptAccountActions.length).toEqual(0);
})
});

View File

@ -0,0 +1,25 @@
import {SimpleState} from "../../../../src/app/project/game-model/gamesystems/states/SimpleState";
import {SimpleTransition} from "../../../../src/app/project/game-model/gamesystems/transitions/SimpleTransition";
import {Script} from "node:vm";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import {ScriptAccountAction} from "../../../../src/app/project/game-model/gamesystems/actions/ScriptAccountAction";
export class SimpleActionTrainer {
static withEmptyActions() {
const startingState = new SimpleState("Wolkig", "");
const endingState = new SimpleState("Schnee", "");
return new SimpleTransition(startingState, endingState);
}
static withSingleAction() {
const startingState = new SimpleState("Wolkig", "");
const endingState = new SimpleState("Schnee", "");
const scriptAccount = new ScriptAccount("Temperature", "");
const transition = new SimpleTransition(startingState, endingState);
transition.scriptAccountActions.push(new ScriptAccountAction(scriptAccount, 10));
return transition;
}
}

View File

@ -0,0 +1,41 @@
import { test, expect } from '@playwright/test';
import {ScriptAccountCondition} from "../../../../src/app/project/game-model/gamesystems/conditions/ScriptAccountCondition";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import exp = require("node:constants");
import {ConditionTrainer} from "./ConditionTrainer";
import {Conditional} from "@angular/compiler";
import {TransitionConditionTrainer} from "./TransitionConditionTrainer";
import {transition} from "@angular/animations";
test.describe('Test Adding Conditions To Transitions', () => {
test("Test adding not contradicting Conditions", async () => {
const transition = TransitionConditionTrainer.withTransitionWithCondition();
const condition = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("Test", ""), -200, -100);
transition.addScriptAccountCondition(condition);
expect(transition.scriptAccountConditions.length).toEqual(2);
expect(transition.scriptAccountConditions.includes(condition)).toBeTruthy();
})
test("Test adding contradicting Conditions", async () => {
const transition = TransitionConditionTrainer.withTransitionWithCondition();
const condition = ConditionTrainer.withContradictingCondition(transition.scriptAccountConditions[0]);
transition.addScriptAccountCondition(condition)
expect(transition.scriptAccountConditions.length).toEqual(1);
expect(transition.scriptAccountConditions.includes(condition)).toBeFalsy();
})
test("Test expanding Conditions", async () => {
const transition = TransitionConditionTrainer.withTransitionWithCondition();
const condition = ConditionTrainer.withExpendingCondition(transition.scriptAccountConditions[0]);
transition.addScriptAccountCondition(condition);
expect(transition.scriptAccountConditions.length).toEqual(1);
expect(transition.scriptAccountConditions.includes(condition)).toBeFalsy();
expect(transition.scriptAccountConditions[0].minValue).toEqual(-10)
expect(transition.scriptAccountConditions[0].maxValue).toEqual(20)
})
});

View File

@ -0,0 +1,43 @@
import { test, expect } from '@playwright/test';
import {ScriptAccountCondition} from "../../../../src/app/project/game-model/gamesystems/conditions/ScriptAccountCondition";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import exp = require("node:constants");
import {ConditionTrainer} from "./ConditionTrainer";
import {Conditional} from "@angular/compiler";
test.describe('Test Contradicting Conditions', () => {
test("Test contradicting conditions", async () => {
const condition = ConditionTrainer.withSimpleCondition();
let contradictingCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.maxValue + 10, condition.maxValue+200);
expect(condition.isContradicting(contradictingCondition)).toBeTruthy();
contradictingCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-100, condition.minValue-50);
expect(condition.isContradicting(contradictingCondition)).toBeTruthy();
})
test("Test intersecting conditions", async () => {
const condition = ConditionTrainer.withSimpleCondition();
let otherCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-1, condition.minValue+1);
expect(condition.isContradicting(otherCondition)).toBeFalsy();
otherCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.maxValue-1, condition.maxValue+1);
expect(condition.isContradicting(otherCondition)).toBeFalsy();
otherCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-1, condition.maxValue+1);
expect(condition.isContradicting(otherCondition)).toBeFalsy();
expect(condition.isContradicting(condition)).toBeFalsy();
})
test("Test contradicting conditions with different ScriptAccount", async () => {
const condition = ConditionTrainer.withSimpleCondition();
const otherCondition = ScriptAccountCondition.constructScriptAccountCondition(
new ScriptAccount("Another test", ""), condition.minValue-20, condition.minValue-10);
expect(condition.isContradicting(otherCondition)).toBeFalsy();
})
});

View File

@ -0,0 +1,55 @@
import { test, expect } from '@playwright/test';
import {ScriptAccountCondition} from "../../../../src/app/project/game-model/gamesystems/conditions/ScriptAccountCondition";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import exp = require("node:constants");
test.describe('Test Create Gamesystems', () => {
test("Test creation with null/undefined parameters", async () => {
let result = ScriptAccountCondition.constructScriptAccountCondition(null, 1, 2);
expect(result).toBeUndefined()
result = ScriptAccountCondition.constructScriptAccountCondition(undefined, 1, 2);
expect(result).toBeUndefined();
result = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("Test", ""), null, 2);
expect(result).toBeUndefined();
result = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("Test", ""), undefined, 2);
expect(result).toBeUndefined();
result = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("Test", ""), 1, undefined);
expect(result).toBeUndefined();
result = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("Test", ""),1, null);
expect(result).toBeUndefined();
})
test("Test Creation with swapped Min Max Parameter", async () => {
let result = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("Test", ""), 2, 1);
expect(result).toBeUndefined();
})
test("Test Correct Condition Creation", async () => {
const scriptAccount = new ScriptAccount("Test", "");
let result = ScriptAccountCondition.constructScriptAccountCondition(scriptAccount, 1, 2);
expect(result).toBeDefined();
expect(result!.scriptAccount).toEqual(scriptAccount)
expect(result!.minValue).toEqual(1);
expect(result!.maxValue).toEqual(2)
result = ScriptAccountCondition.constructScriptAccountCondition(scriptAccount, -10, 2);
expect(result).toBeDefined();
expect(result!.scriptAccount).toEqual(scriptAccount)
expect(result!.minValue).toEqual(-10);
expect(result!.maxValue).toEqual(2)
result = ScriptAccountCondition.constructScriptAccountCondition(scriptAccount, -20, -10);
expect(result).toBeDefined();
expect(result!.scriptAccount).toEqual(scriptAccount)
expect(result!.minValue).toEqual(-20);
expect(result!.maxValue).toEqual(-10)
})
});

View File

@ -0,0 +1,44 @@
import { test, expect } from '@playwright/test';
import {ScriptAccountCondition} from "../../../../src/app/project/game-model/gamesystems/conditions/ScriptAccountCondition";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import exp = require("node:constants");
import {ConditionTrainer} from "./ConditionTrainer";
test.describe('Test Expand Conditions', () => {
test("Test expansion with contradiccting Conditions", async () => {
const condition = ConditionTrainer.withSimpleCondition();
const otherCondition = ConditionTrainer.withContradictingCondition(condition);
condition.extendCondition(otherCondition)
expect(condition.minValue).toEqual(ConditionTrainer.withSimpleCondition().minValue);
expect(condition.maxValue).toEqual(ConditionTrainer.withSimpleCondition().maxValue);
})
test("Test lower expansion of Conditions", async () => {
const condition = ConditionTrainer.withSimpleCondition();
const otherCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-10, condition.minValue+10)
condition.extendCondition(otherCondition);
expect(condition.minValue).toEqual(ConditionTrainer.withSimpleCondition().minValue-10)
expect(condition.maxValue).toEqual(ConditionTrainer.withSimpleCondition().maxValue);
})
test("Test higher expansion of conditions", async () => {
const condition = ConditionTrainer.withSimpleCondition();
const otherCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.maxValue-10, condition.maxValue+10)
condition.extendCondition(otherCondition)
expect(condition.minValue).toEqual(ConditionTrainer.withSimpleCondition().minValue)
expect(condition.maxValue).toEqual(ConditionTrainer.withSimpleCondition().maxValue+10)
})
test("Test higher and lower Expansion of Conditions", async () => {
const condition = ConditionTrainer.withSimpleCondition();
const otherCondition = ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-10, condition.maxValue+10);
condition.extendCondition(otherCondition);
expect(condition.minValue).toEqual(ConditionTrainer.withSimpleCondition().minValue-10)
expect(condition.maxValue).toEqual(ConditionTrainer.withSimpleCondition().maxValue+10)
})
});

View File

@ -0,0 +1,17 @@
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import {ScriptAccountCondition} from "../../../../src/app/project/game-model/gamesystems/conditions/ScriptAccountCondition";
export class ConditionTrainer {
static withSimpleCondition(): ScriptAccountCondition {
const scriptAccount = new ScriptAccount("Test", "");
return ScriptAccountCondition.constructScriptAccountCondition(scriptAccount, 0, 10);
}
static withContradictingCondition(condition: ScriptAccountCondition): ScriptAccountCondition {
return ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-20, condition.minValue-10);
}
static withExpendingCondition(condition: ScriptAccountCondition): ScriptAccount {
return ScriptAccountCondition.constructScriptAccountCondition(condition.scriptAccount, condition.minValue-10, condition.maxValue+10);
}
}

View File

@ -0,0 +1,24 @@
import {SimpleState} from "../../../../src/app/project/game-model/gamesystems/states/SimpleState";
import {SimpleTransition} from "../../../../src/app/project/game-model/gamesystems/transitions/SimpleTransition";
import {ScriptAccount} from "../../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import {ScriptAccountCondition} from "../../../../src/app/project/game-model/gamesystems/conditions/ScriptAccountCondition";
export class TransitionConditionTrainer {
static withTransitionWithoutConditions() {
const startingState = new SimpleState("StartingState", "");
const endingState = new SimpleState("EndingState", "");
return new SimpleTransition(startingState, endingState);
}
static withTransitionWithCondition() {
const startingState = new SimpleState("StartingState", "");
const endingState = new SimpleState("EndingState", "");
const transition = new SimpleTransition(startingState, endingState);
const scriptAccount = new ScriptAccount("ScriptAccount", "");
transition.scriptAccountConditions.push(ScriptAccountCondition.constructScriptAccountCondition(scriptAccount, 0, 10)!)
return transition;
}
}

View File

@ -1,17 +1,6 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import exp = require("node:constants");
import {end} from "electron-debug";
import {GamesystemTrainer} from "./GamesystemTrainer";
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
import {ProductStateTrainer} from "./ProductStateTrainer";
import {SimpleState} from "../../../../src/app/game-model/gamesystems/SimpleState";
import {SimpleState} from "../../../../src/app/project/game-model/gamesystems/states/SimpleState";
test.describe('Test Create ProductStates', () => {
test("Adding already existent ProductState", async () => {

View File

@ -1,7 +1,7 @@
import { test, expect } from '@playwright/test';
import {ProductStateTrainer} from "./ProductStateTrainer";
import {ProductState} from "../../../../src/app/game-model/gamesystems/ProductState";
import {SimpleGamesystem} from "../../../../src/app/game-model/gamesystems/SimpleGamesystem";
import {ProductState} from "../../../../src/app/project/game-model/gamesystems/states/ProductState";
import {SimpleGamesystem} from "../../../../src/app/project/game-model/gamesystems/SimpleGamesystem";
test.describe('Test Create ProductTransitions', () => {
test("Test ProductTransition Creation with invalid inputs", async ()=> {
const gamesystem = ProductStateTrainer.givenFullProductGamesystemWithTwoStates();

View File

@ -1,17 +1,5 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import exp = require("node:constants");
import {end} from "electron-debug";
import {GamesystemTrainer} from "./GamesystemTrainer";
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
import {ProductStateTrainer} from "./ProductStateTrainer";
import {SimpleState} from "../../../../src/app/game-model/gamesystems/SimpleState";
test.describe('Test Check Equal of Innerstates', () => {
test("Test invalid input for equal checking", async()=> {

View File

@ -1,17 +1,4 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
import exp = require("node:constants");
import {end} from "electron-debug";
import {GamesystemTrainer} from "./GamesystemTrainer";
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
import {ProductStateTrainer} from "./ProductStateTrainer";
import {SimpleState} from "../../../../src/app/game-model/gamesystems/SimpleState";
import {ProductSystemGenerationTrainer} from "./ProductSystemGenerationTrainer";
test.describe('Test Create ProductStates', () => {

View File

@ -1,7 +1,7 @@
import {ProductGamesystem} from "../../../../src/app/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../src/app/game-model/gamesystems/SimpleGamesystem";
import {ProductState} from "../../../../src/app/game-model/gamesystems/ProductState";
import {ProductTransition} from "../../../../src/app/game-model/gamesystems/ProductTransition";
import {ProductGamesystem} from "../../../../src/app/project/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../src/app/project/game-model/gamesystems/SimpleGamesystem";
import {ProductState} from "../../../../src/app/project/game-model/gamesystems/states/ProductState";
import {ProductTransition} from "../../../../src/app/project/game-model/gamesystems/transitions/ProductTransition";
export class ProductStateTrainer {
static INNERSTATE_LETTER_1 = "A";

View File

@ -1,5 +1,5 @@
import {ProductGamesystem} from "../../../../src/app/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../src/app/game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../../../src/app/project/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../src/app/project/game-model/gamesystems/SimpleGamesystem";
export class ProductSystemGenerationTrainer {

View File

@ -1,10 +1,10 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
import * as PATH from 'path';
import {GameModel} from "../../../src/app/game-model/GameModel";
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
import {GameModel} from "../../../src/app/project/game-model/GameModel";
import {Gamesystem} from "../../src/app/project/game-model/gamesystems/Gamesystem";
import {ScriptAccount} from "../../../src/app/project/game-model/scriptAccounts/ScriptAccount";
import {ModelComponentType} from "../../../src/app/project/game-model/ModelComponentType";
test.describe('Test ScriptAccounts', () => {

View File

@ -1,5 +1,5 @@
<div class="container">
<div class="full-height-container">
<div class="full-height-container" >
<button mat-icon-button class="small-icon-button" [ngClass]="openContent === ModelComponentType.SCRIPTACCOUNT ? 'selected':''"
(click)="openScriptAccountsOverview()"><mat-icon>inventory_2</mat-icon></button>
<button mat-icon-button class="small-icon-button" [ngClass]="openContent === ModelComponentType.GAMESYTEM ? 'selected':''"
@ -9,7 +9,7 @@
<mat-drawer-container class="example-container" autosize>
<mat-drawer #drawer class="example-sidenav" mode="side">
<div class="sidenav-header">
<div class="sidenav-header" (click)="resetSelection()">
<button mat-button [matMenuTriggerFor]="contentMenu">
<span class="mat-button-wrapper">{{ModelComponentTypeUtillities.toString(openContent)}}
<mat-icon class="mat-icon">expand_more</mat-icon>
@ -27,7 +27,7 @@
</mat-drawer>
<div class="example-sidenav-content">
<app-editor #editor (onModelNameUpdate)="onModelNameUpdate()"></app-editor>
<app-editor #editor (onModelNameUpdate)="onModelNameUpdate()" [gameModel]="gameModel"></app-editor>
</div>
</mat-drawer-container>

View File

@ -1,26 +1,25 @@
import {Component, NgZone, OnInit, ViewChild} from '@angular/core';
import {ElectronService} from './core/services';
import {APP_CONFIG} from '../environments/environment';
import {ModelComponentType} from "./game-model/ModelComponentType";
import {MatDrawerContainer} from "@angular/material/sidenav";
import {ModelComponentTypeUtillities} from "./game-model/ModelComponentTypeUtillities";
import {GameModel} from "./game-model/GameModel";
import {EditorComponent} from "./editor/editor.component";
import {ModelComponent} from "./game-model/ModelComponent";
import {
ScriptAccountOverviewComponent
} from "./side-overviews/script-account-overview/script-account-overview.component";
import {MatDialog} from "@angular/material/dialog";
import {DeleteConfirmationDialogComponent} from "./delete-confirmation-dialog/delete-confirmation-dialog.component";
import {ScriptAccount} from "./game-model/scriptAccounts/ScriptAccount";
import {GamescriptOverviewComponent} from "./side-overviews/gamescript-overview/gamescript-overview.component";
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";
import {StoreProject} from "./game-model/fs/store/StoreProject";
import {ModelComponentType} from "./project/game-model/ModelComponentType";
import {ModelComponentTypeUtillities} from "./project/game-model/ModelComponentTypeUtillities";
import {ScriptAccount} from "./project/game-model/scriptAccounts/ScriptAccount";
import {Gamesystem} from "./project/game-model/gamesystems/Gamesystem";
import {ModelComponent} from "./project/game-model/ModelComponent";
import {GameModel} from "./project/game-model/GameModel";
import {StoredGameModel} from "../../app/storage/StoredGameModel";
import {GamesystemParser} from "./project/parser/gamesystemParser/GamesystemParser";
import {ScriptAccountParser} from "./project/parser/ScriptAccountParser";
import {ElectronService} from "./core/services";
import {ScriptAccountSerializer} from "./project/serializer/ScriptAccountSerializer";
import {StoreComponent} from "../../app/storage/StoreComponent";
import {GamesystemSerializer} from "./project/serializer/GamesystemSerializer";
@Component({
selector: 'app-root',
@ -38,17 +37,10 @@ export class AppComponent implements OnInit{
gameModel: GameModel | undefined
constructor(private electronService: ElectronService,
private zone: NgZone,
private dialog: MatDialog
private dialog: MatDialog,
private zone: NgZone
) {
console.log('APP_CONFIG', APP_CONFIG);
if (electronService.isElectron) {
console.log(process.env);
console.log('Run in electron');
console.log('Electron ipcRenderer', this.electronService.ipcRenderer);
console.log('NodeJS childProcess', this.electronService.childProcess);
if(electronService.isElectron) {
electronService.ipcRenderer.on('context-menu', (event: any, message: string) => {
this.zone.run(() => {
this.onContextMenuMessageRecieved(message);
@ -57,21 +49,18 @@ export class AppComponent implements OnInit{
electronService.ipcRenderer.on('get-project-data', (event: any, message: string) => {
this.zone.run(() => {
this.saveGameModel();
this.onSaveProject();
})
})
electronService.ipcRenderer.on('open-project', (event: any, loadedProject: LoadedProject) => {
this.gameModel = ProcessLoadedProject.processLoadedProject(loadedProject)
electronService.ipcRenderer.on('open-project', (event: any, loadedProject: StoredGameModel) => {
this.zone.run(() => {
this.onLoadProject(loadedProject)
})
})
} else {
console.log('Run in browser');
}
}
saveGameModel() {
const storageModels = StoreProject.storeProject(this.gameModel!);
this.electronService.ipcRenderer.send('save-model', storageModels)
}
}
onContextMenuMessageRecieved(message: string) {
@ -108,12 +97,18 @@ export class AppComponent implements OnInit{
private onDeleteModelComponent() {
const affectedModelComponent = this.getSelectedModelComponent();
console.log("Affected ModelComponent: ", affectedModelComponent)
const dialogRef = this.dialog.open(DeleteConfirmationDialogComponent, {data: affectedModelComponent, minWidth: "400px"});
dialogRef.afterClosed().subscribe(res => {
if(res != undefined && res) {
if(affectedModelComponent instanceof ScriptAccount) {
this.gameModel!.removeScriptAccount(affectedModelComponent);
//this.electronService.ipcRenderer.send('delete-component', new DeleteModel(affectedModelComponent.componentName, ModelComponentType.SCRIPTACCOUNT))
} else if(affectedModelComponent instanceof Gamesystem) {
this.gameModel!.removeGamesystem(affectedModelComponent);
//this.electronService.ipcRenderer.send('delete-component', new DeleteModel(affectedModelComponent.componentName, ModelComponentType.GAMESYTEM))
this.gamesystemOverview!.refresh()
}
}
})
@ -142,48 +137,63 @@ export class AppComponent implements OnInit{
} else {
parentGamesystemName = this.gamesystemOverview!.selectedGamesystemName;
}
const createdGamesystem = this.gameModel!.createGamesystem("New Gamesystem", parentGamesystemName);
if(createdGamesystem != undefined) {
this.gamesystemOverview!.refresh();
this.editor?.openGameModelComponent(createdGamesystem!);
this.editor?.openGameModelComponent(createdGamesystem);
}
}
private getSelectedModelComponent(): ModelComponent | undefined {
if(this.openContent == ModelComponentType.SCRIPTACCOUNT) {
if(this.scriptAccountOverview != undefined) {
return this.scriptAccountOverview!.selectedScriptAccount;
return this.scriptAccountOverview.selectedScriptAccount;
} else {
console.log("[WARN] [App.component] ScriptAccountOverview is undefined")
}
} else if(this.openContent == ModelComponentType.GAMESYTEM){
if(this.gamesystemOverview != undefined) {
return this.gamesystemOverview.getSelectedGamesystem()
} else {
console.log("[WARN] [App.component] GamesystemOverview is undefined")
}
}
return undefined;
}
ngOnInit() {
/*this.gameModel = new GameModel("No More");
this.gameModel.createScriptAccount("Temperature");
this.gameModel.createScriptAccount("Luftfeuchtigkeit");
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. ");
onLoadProject(storedGameModel: StoredGameModel) {
const gameModel = new GameModel(storedGameModel.gameModelName)
const sunnyState = weather.createState("Sunny", "The sun is shining. No clouds, no rain, no storm.");
const rainingState = weather.createState("Raining", "It rains")
const scriptAccounts = ScriptAccountParser.parseScriptAccounts(storedGameModel.storedScriptAccounts);
season.createTransition(springState!, summerState!);
weather.createTransition(sunnyState!, rainingState!);
const gamesystemParser = new GamesystemParser(scriptAccounts);
const gamesystems = gamesystemParser.parseStoredGamesystems(storedGameModel.storedGamesystems);
const weather_season = new ProductGamesystem("Weather-Season");
weather_season.addChildGamesystem(weather);
weather_season.addChildGamesystem(season);
gameModel.scriptAccounts = scriptAccounts
gameModel.gamesystems = gamesystems
gameModel.generateProductSystemContents()
weather_season.createState([springState!, sunnyState!]);
console.log(gameModel.scriptAccounts)
this.gameModel.addGamesystem(weather_season);*/
this.gameModel = gameModel;
}
onSaveProject() {
if(this.gameModel != undefined) {
const storedScriptAccounts = ScriptAccountSerializer.serializeScriptAccounts(this.gameModel.scriptAccounts)
const storedGamesystems: StoreComponent[] = GamesystemSerializer.serializeGamesystems(this.gameModel.gamesystems)
const storeModel = new StoredGameModel(this.gameModel.gameModelName, storedScriptAccounts, storedGamesystems)
if(this.electronService.isElectron) {
this.electronService.ipcRenderer.send('save-model', storeModel)
}
}
}
openScriptAccountsOverview() {
@ -218,4 +228,10 @@ export class AppComponent implements OnInit{
this.gamesystemOverview!.refresh();
}
}
resetSelection() {
if(this.gamesystemOverview != undefined) {
this.gamesystemOverview.resetSelectedGamesystem()
}
}
}

View File

@ -62,6 +62,12 @@ import {
} from "./editor/gamesystem-editor/state-editor/product-state-editor/product-state-editor.component";
import {MatTooltip} from "@angular/material/tooltip";
import {MatCard, MatCardContent} from "@angular/material/card";
import {
ScriptaccountActionEditorComponent
} from "./editor/gamesystem-editor/transition-editor/scriptaccount-action-editor/scriptaccount-action-editor.component";
import {
ScriptaccountConditionEditorComponent
} from "./editor/gamesystem-editor/scriptaccount-condition-editor/scriptaccount-condition-editor.component";
// AoT requires an exported function for factories
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
@ -81,7 +87,9 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
SimpleTransitionEditorComponent,
ProductTransitionEditorComponent,
ProductStateEditorComponent,
ProductGamesystemEditorComponent
ProductGamesystemEditorComponent,
ScriptaccountActionEditorComponent,
ScriptaccountConditionEditorComponent
],
imports: [
BrowserModule,

View File

@ -1,19 +1,24 @@
import {Component, Inject} from '@angular/core';
import {Component, Inject, OnInit} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {ModelComponentTypeUtillities} from "../game-model/ModelComponentTypeUtillities";
import {ModelComponent} from "../game-model/ModelComponent";
import {ModelComponent} from "../project/game-model/ModelComponent";
import {ModelComponentTypeUtillities} from "../project/game-model/ModelComponentTypeUtillities";
@Component({
selector: 'app-delete-confirmation-dialog',
templateUrl: './delete-confirmation-dialog.component.html',
styleUrl: './delete-confirmation-dialog.component.scss'
})
export class DeleteConfirmationDialogComponent {
export class DeleteConfirmationDialogComponent implements OnInit{
constructor(private dialogRef: MatDialogRef<DeleteConfirmationDialogComponent>,
@Inject(MAT_DIALOG_DATA) public deleteModelComponent: ModelComponent) {
}
protected readonly ModelComponentTypeUtillities = ModelComponentTypeUtillities;
ngOnInit(): void {
console.log("delete Confirmation dialog here")
}
cancel() {
this.dialogRef.close(false);
@ -22,4 +27,6 @@ export class DeleteConfirmationDialogComponent {
confirmDelete() {
this.dialogRef.close(true);
}
protected readonly ModelComponentTypeUtillities = ModelComponentTypeUtillities;
}

View File

@ -12,7 +12,8 @@
[scriptAccount]="convertModelComponentToScriptAccount(modelComponent)"></app-script-account-editor>
<app-gamesystem-editor *ngIf="modelComponent.type === ModelComponentType.GAMESYTEM"
[gamesystem]="convertModelComponentToGamesystem(modelComponent)"
(onOpenGamesystemEditor)="openGameModelComponent($event)"></app-gamesystem-editor>
(onOpenGamesystemEditor)="openGameModelComponent($event)"
[scriptAccounts]="gameModel!.scriptAccounts"></app-gamesystem-editor>
</mat-tab>
</mat-tab-group>

View File

@ -1,11 +1,12 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {GameModel} from "../game-model/GameModel";
import {ModelComponent} from "../game-model/ModelComponent";
import {ModelComponentType} from "../game-model/ModelComponentType";
import {ScriptAccount} from "../game-model/scriptAccounts/ScriptAccount";
import {Gamesystem} from "../game-model/gamesystems/Gamesystem";
import {State} from "../game-model/gamesystems/State";
import {Transition} from "../game-model/gamesystems/Transition";
import {ModelComponent} from "../project/game-model/ModelComponent";
import {GameModel} from "../project/game-model/GameModel";
import {ScriptAccount} from "../project/game-model/scriptAccounts/ScriptAccount";
import {Gamesystem} from "../project/game-model/gamesystems/Gamesystem";
import {State} from "../project/game-model/gamesystems/states/State";
import {Transition} from "../project/game-model/gamesystems/transitions/Transition";
import {ModelComponentType} from "../project/game-model/ModelComponentType";
@Component({
selector: 'app-editor',
@ -16,6 +17,7 @@ export class EditorComponent {
gameModelComponents: ModelComponent[] = [];
@Output("onModelNameUpdate") onModelNameUpdateEmitter = new EventEmitter<boolean>();
activeTab: number = this.gameModelComponents.length;
@Input() gameModel: GameModel | undefined
openGameModelComponent(gameModelComponent: ModelComponent) {
if(!this.gameModelComponents.includes(gameModelComponent)) {
@ -42,9 +44,10 @@ export class EditorComponent {
}
}
protected readonly ModelComponentType = ModelComponentType;
onModelNameUpdate() {
this.onModelNameUpdateEmitter.emit(true);
}
protected readonly ModelComponentType = ModelComponentType;
}

View File

@ -1,3 +1,3 @@
<app-simple-gamesystem-editor *ngIf="isSimpleGamesystem()" [simpleGamesystem]="convertGamesystemToSimpleGamesystem()"></app-simple-gamesystem-editor>
<app-simple-gamesystem-editor *ngIf="isSimpleGamesystem()" [simpleGamesystem]="convertGamesystemToSimpleGamesystem()" [scriptAccunts]="scriptAccounts"></app-simple-gamesystem-editor>
<app-product-gamesystem-editor *ngIf="!isSimpleGamesystem()" [gamesystem]="convertGamesystemToProductGamesystem()"
(onOpenGamesystemEditor)="onOpenGamesystemEditor($event)"></app-product-gamesystem-editor>

View File

@ -1,21 +1,26 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {GameModel} from "../../game-model/GameModel";
import {Gamesystem} from "../../game-model/gamesystems/Gamesystem";
import {State} from "../../game-model/gamesystems/State";
import {Transition} from "../../game-model/gamesystems/Transition";
import {SimpleGamesystem} from "../../game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../game-model/gamesystems/ProductGamesystem";
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {State} from "../../project/game-model/gamesystems/states/State";
import {Gamesystem} from "../../project/game-model/gamesystems/Gamesystem";
import { Transition } from '../../project/game-model/gamesystems/transitions/Transition';
import {ScriptAccount} from "../../project/game-model/scriptAccounts/ScriptAccount";
import {SimpleGamesystem} from "../../project/game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../project/game-model/gamesystems/ProductGamesystem";
@Component({
selector: 'app-gamesystem-editor',
templateUrl: './gamesystem-editor.component.html',
styleUrl: './gamesystem-editor.component.scss'
})
export class GamesystemEditorComponent {
export class GamesystemEditorComponent implements OnInit{
@Input() gamesystem: Gamesystem<State<any>, Transition<any>> | undefined
@Input() scriptAccounts: ScriptAccount[] = [];
@Output('onOpenGamesystemEditor') openGamesystemEmitter = new EventEmitter<SimpleGamesystem>();
ngOnInit() {
console.log("GamesystemEditor: ", this.scriptAccounts.length)
}
isSimpleGamesystem() {
return this.gamesystem instanceof SimpleGamesystem;
}

View File

@ -1,9 +1,9 @@
import {Gamesystem} from "../../../game-model/gamesystems/Gamesystem";
import {SimpleGamesystem} from "../../../game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../../game-model/gamesystems/ProductGamesystem";
import {State} from "../../../game-model/gamesystems/State";
import {ProductState} from "../../../game-model/gamesystems/ProductState";
import {SimpleState} from "../../../game-model/gamesystems/SimpleState";
import {Gamesystem} from "../../../project/game-model/gamesystems/Gamesystem";
import {SimpleGamesystem} from "../../../project/game-model/gamesystems/SimpleGamesystem";
import {ProductGamesystem} from "../../../project/game-model/gamesystems/ProductGamesystem";
import {State} from "../../../project/game-model/gamesystems/states/State";
import {SimpleState} from "../../../project/game-model/gamesystems/states/SimpleState";
import {ProductState} from "../../../project/game-model/gamesystems/states/ProductState";
export class LeafGamesystemCalculator {

View File

@ -1,10 +1,9 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {ProductGamesystem} from "../../../game-model/gamesystems/ProductGamesystem";
import {ProductStateEditorComponent} from "../state-editor/product-state-editor/product-state-editor.component";
import {SimpleGamesystem} from "../../../game-model/gamesystems/SimpleGamesystem";
import {
ProductTransitionEditorComponent
} from "../transition-editor/product-transition-editor/product-transition-editor.component";
import {ProductGamesystem} from "../../../project/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../project/game-model/gamesystems/SimpleGamesystem";

View File

@ -0,0 +1,56 @@
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="scriptAccount">
<th mat-header-cell *matHeaderCellDef>ScriptAccount</th>
<td mat-cell *matCellDef="let condition; let i = index">
<span *ngIf="condition !== addedCondition">{{condition.scriptAccount.componentName}}</span>
<mat-form-field appearance="fill" class="long-form" *ngIf="condition === addedCondition">
<mat-label>ScriptAccount</mat-label>
<mat-select [(ngModel)]="addedCondition!.scriptAccount">
<mat-option *ngFor="let scriptAccount of scriptAccounts" [value]="scriptAccount">{{scriptAccount.componentName}}</mat-option>
</mat-select>
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="minValue">
<th mat-header-cell *matHeaderCellDef>Minimal Value</th>
<td mat-cell *matCellDef="let condition">
<span *ngIf="condition !== editedCondition && condition !== addedCondition">{{condition.minValue}}</span>
<mat-form-field appearance="fill" class="long-form" *ngIf=" condition === editedCondition">
<mat-label>Minimal Value</mat-label>
<input matInput [(ngModel)]="editedCondition!.minValue">
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="maxValue">
<th mat-header-cell *matHeaderCellDef>Maximal Value</th>
<td mat-cell *matCellDef="let condition">
<span *ngIf="condition !== editedCondition && condition !== addedCondition">{{condition.maxValue}}</span>
<mat-form-field appearance="fill" class="long-form" *ngIf=" condition === editedCondition">
<mat-label>Maximal Value</mat-label>
<input matInput [(ngModel)]="editedCondition!.maxValue">
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="edit">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let condition;">
<button mat-icon-button class="icon-btn-primary" *ngIf="editedCondition === undefined" (click)="edit(condition)"><mat-icon>edit</mat-icon></button>
<button mat-icon-button class="icon-btn-primary" *ngIf="editedCondition === condition" (click)="finishEditing()"><mat-icon>done</mat-icon></button>
</td>
</ng-container>
<ng-container matColumnDef="delete">
<th mat-header-cell *matHeaderCellDef>
<button mat-icon-button (click)="createCondition()"><mat-icon>add</mat-icon></button>
</th>
<td mat-cell *matCellDef="let condition">
<button mat-icon-button color="warn" (click)="deleteCondition(condition)"><mat-icon>delete</mat-icon></button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

View File

@ -0,0 +1,7 @@
.mat-column-edit, .mat-column-delete {
width: 32px;
}
table {
width: 100%;
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ScriptaccountConditionEditorComponent } from './scriptaccount-condition-editor.component';
describe('ScriptaccountConditionEditorComponent', () => {
let component: ScriptaccountConditionEditorComponent;
let fixture: ComponentFixture<ScriptaccountConditionEditorComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ScriptaccountConditionEditorComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ScriptaccountConditionEditorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,67 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {MatTableDataSource} from "@angular/material/table";
import {ScriptAccountCondition} from "../../../project/game-model/gamesystems/conditions/ScriptAccountCondition";
import {ScriptAccount} from "../../../project/game-model/scriptAccounts/ScriptAccount";
@Component({
selector: 'app-scriptaccount-condition-editor',
templateUrl: './scriptaccount-condition-editor.component.html',
styleUrl: './scriptaccount-condition-editor.component.scss'
})
export class ScriptaccountConditionEditorComponent implements OnInit{
@Input() conditions: ScriptAccountCondition[] = []
@Input() scriptAccounts: ScriptAccount[] = []
@Input() enableEditiong: boolean = false
@Output() onCreateCondition: EventEmitter<ScriptAccountCondition> = new EventEmitter<ScriptAccountCondition>();
@Output() onDeleteCondition: EventEmitter<ScriptAccountCondition> = new EventEmitter<ScriptAccountCondition>();
dataSource: MatTableDataSource<ScriptAccountCondition> = new MatTableDataSource();
displayedColumns = ['scriptAccount', 'minValue', 'maxValue']
editedCondition: ScriptAccountCondition | undefined
addedCondition: ScriptAccountCondition | undefined
ngOnInit() {
this.dataSource.data = this.conditions.concat();
if(this.enableEditiong) {
this.displayedColumns.push( 'edit', 'delete')
}
}
createCondition() {
this.addedCondition = ScriptAccountCondition.constructScriptAccountCondition(new ScriptAccount("", ""), 0,0);
this.editedCondition = this.addedCondition;
this.dataSource.data = this.dataSource.data.concat(this.addedCondition!);
}
finishEditing() {
if(this.addedCondition != undefined) {
const createdCondition = ScriptAccountCondition.constructScriptAccountCondition(this.addedCondition.scriptAccount, this.addedCondition.minValue, this.addedCondition.maxValue);
if(createdCondition != undefined) {
console.log(createdCondition)
this.onCreateCondition.emit(createdCondition);
console.log(this.conditions)
this.dataSource.data = this.conditions;
}
this.addedCondition = undefined;
}
this.editedCondition = undefined;
}
edit(condition: ScriptAccountCondition) {
this.editedCondition = condition;
}
deleteCondition(condition: ScriptAccountCondition) {
if(this.addedCondition === condition) {
this.addedCondition = undefined;
this.dataSource.data = this.conditions.concat();
} else {
this.onDeleteCondition.emit(condition);
this.dataSource.data = this.conditions.concat();
}
}
}

View File

@ -1,4 +1,4 @@
<app-simple-state-editor [states]="simpleGamesystem!.states" [gamesystem]="simpleGamesystem"></app-simple-state-editor>
<app-simple-state-editor [states]="simpleGamesystem!.states" [gamesystem]="simpleGamesystem" [scriptAccounts]="scriptAccunts"></app-simple-state-editor>
<div id="transition-editor">
<app-simple-transition-editor [gamesystem]="simpleGamesystem"></app-simple-transition-editor>
<app-simple-transition-editor [gamesystem]="simpleGamesystem" [scriptAccounts]="scriptAccunts"></app-simple-transition-editor>
</div>

View File

@ -1,6 +1,7 @@
import {Component, Input} from '@angular/core';
import {SimpleGamesystem} from "../../../game-model/gamesystems/SimpleGamesystem";
import {MatTableDataSource} from "@angular/material/table";
import {SimpleGamesystem} from "../../../project/game-model/gamesystems/SimpleGamesystem";
import {ScriptAccount} from "../../../project/game-model/scriptAccounts/ScriptAccount";
@Component({
selector: 'app-simple-gamesystem-editor',
@ -10,7 +11,7 @@ import {MatTableDataSource} from "@angular/material/table";
export class SimpleGamesystemEditorComponent {
@Input() simpleGamesystem: SimpleGamesystem | undefined
@Input() scriptAccunts: ScriptAccount[] = []
}

View File

@ -4,7 +4,7 @@
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Filter" #input>
</mat-form-field>
<table mat-table [dataSource]="datasource" class="mat-elevation-z8">
<table mat-table [dataSource]="datasource" class="mat-elevation-z8" multiTemplateDataRows>
<ng-container *ngFor="let col of displayedColumns; let i = index" [matColumnDef]="col">
<th mat-header-cell *matHeaderCellDef>{{col}}</th>
<td mat-cell *matCellDef="let state">
@ -15,8 +15,36 @@
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<ng-container matColumnDef="expand">
<th mat-header-cell *matHeaderCellDef aria-label="row actions">&nbsp;</th>
<td mat-cell *matCellDef="let element">
<button mat-icon-button aria-label="expand row" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()">
@if (expandedElement === element) {
<mat-icon>keyboard_arrow_up</mat-icon>
} @else {
<mat-icon>keyboard_arrow_down</mat-icon>
}
</button>
</td>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="expandedColumns.length">
<div class="example-element-detail"
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<app-scriptaccount-condition-editor [conditions]="element.conditions" [enableEditiong]="false"></app-scriptaccount-condition-editor>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="expandedColumns"></tr>
<tr mat-row *matRowDef="let element; columns: expandedColumns;"
class="example-element-row"
[class.example-expanded-row]="expandedElement === element"
(click)="expandedElement = expandedElement === element ? null : element">
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>
</mat-card-content>
</mat-card>

View File

@ -2,10 +2,59 @@ table {
width: 100%;
}
.mat-column-Initial {
.mat-column-Initial, .mat-column-expand {
width: 32px;
}
.long-form {
width: 100%;
}
table {
width: 100%;
}
tr.example-detail-row {
height: 0;
}
tr.example-element-row:not(.example-expanded-row):hover {
background: #545456;
}
tr.example-element-row:not(.example-expanded-row):active {
background: #545456;
}
.example-element-row td {
border-bottom-width: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
}
.example-element-diagram {
min-width: 80px;
border: 2px solid black;
padding: 8px;
font-weight: lighter;
margin: 8px 0;
height: 104px;
}
.example-element-symbol {
font-weight: bold;
font-size: 40px;
line-height: normal;
}
.example-element-description {
padding: 16px;
}
.example-element-description-attribution {
opacity: 0.5;
}

View File

@ -1,18 +1,24 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ProductGamesystem} from "../../../../game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {
MatTableDataSource
} from "@angular/material/table";
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
import {State} from "../../../../game-model/gamesystems/State";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
import {animate, state, style, transition, trigger} from "@angular/animations";
import {ProductGamesystem} from "../../../../project/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../project/game-model/gamesystems/SimpleGamesystem";
import {ProductState} from "../../../../project/game-model/gamesystems/states/ProductState";
import {State} from "../../../../project/game-model/gamesystems/states/State";
@Component({
selector: 'app-product-state-editor',
templateUrl: './product-state-editor.component.html',
animations: [
trigger('detailExpand', [
state('collapsed,void', style({height: '0px', minHeight: '0'})),
state('expanded', style({height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
styleUrl: './product-state-editor.component.scss'
})
export class ProductStateEditorComponent implements OnInit{
@ -20,13 +26,16 @@ export class ProductStateEditorComponent implements OnInit{
@Input() gamesystem: ProductGamesystem | undefined
@Output('onOpenGamesystemEditor') openGamesystemEditorEmitter = new EventEmitter<SimpleGamesystem>();
displayedColumns: string[] = [];
expandedColumns: string[] = []
datasource = new MatTableDataSource<ProductState>();
expandedElement: ProductState | null = null;
ngOnInit() {
this.gamesystem!.generateFromChildsystems();
this.generateColumnNamesRecursively(this.gamesystem!, "");
this.displayedColumns.push('Initial');
this.expandedColumns = [...this.displayedColumns, 'expand'];
this.datasource.data = this.gamesystem!.states;
this.datasource.filterPredicate = (data: ProductState, filter: string) => {
const leaf_states = LeafGamesystemCalculator.calcLeafStates(data);
@ -44,7 +53,6 @@ export class ProductStateEditorComponent implements OnInit{
})
}
protected readonly SimpleState = SimpleState;
getLeafState(state: State<any>, i: number) {
return LeafGamesystemCalculator.calcLeafStates(state)[i];

View File

@ -25,6 +25,11 @@
<mat-label>Description</mat-label>
<textarea matInput [(ngModel)]="element.stateDescription" rows="3" (ngModelChange)="onStateChange()"></textarea>
</mat-form-field>
<div class="long-form">
<app-scriptaccount-condition-editor [conditions]="element.conditions" [scriptAccounts]="scriptAccounts" [enableEditiong]="true"
(onCreateCondition)="onCreateCondition(element, $event)" (onDeleteCondition)="deleteCondition(element, $event)"></app-scriptaccount-condition-editor>
</div>
</div>
</td>
</ng-container>
@ -46,8 +51,8 @@
<ng-container matColumnDef="edit">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let state">
<button mat-icon-button color="primary" *ngIf="editedElement !== state" (click)="editState(state)" [disabled]="editedElement !== null"><mat-icon>edit</mat-icon></button>
<button mat-icon-button color="primary" (click)="finishEditing()" *ngIf="editedElement === state"><mat-icon>done</mat-icon></button>
<button mat-icon-button class="icon-btn-primary" *ngIf="editedElement !== state" (click)="editState(state)" [disabled]="editedElement !== null"><mat-icon>edit</mat-icon></button>
<button mat-icon-button class="icon-btn-primary" (click)="finishEditing()" *ngIf="editedElement === state"><mat-icon>done</mat-icon></button>
</td>
</ng-container>

View File

@ -17,12 +17,6 @@ tr.example-element-row:not(.example-expanded-row):active {
.example-element-row td {
border-bottom-width: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
}
.example-element-diagram {
min-width: 80px;
border: 2px solid black;

View File

@ -1,11 +1,11 @@
import {Component, Input, OnInit} from '@angular/core';
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
import {MatTableDataSource} from "@angular/material/table";
import {animate, state, style, transition, trigger} from "@angular/animations";
import {MatSnackBar} from "@angular/material/snack-bar";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
import {SimpleState} from "../../../../project/game-model/gamesystems/states/SimpleState";
import {SimpleGamesystem} from "../../../../project/game-model/gamesystems/SimpleGamesystem";
import {ScriptAccount} from "../../../../project/game-model/scriptAccounts/ScriptAccount";
import {ScriptAccountCondition} from "../../../../project/game-model/gamesystems/conditions/ScriptAccountCondition";
@Component({
selector: 'app-simple-state-editor',
@ -23,6 +23,7 @@ export class SimpleStateEditorComponent implements OnInit{
@Input() states: SimpleState[] = [];
@Input() gamesystem: SimpleGamesystem | undefined
@Input() scriptAccounts: ScriptAccount[] = []
dataSource = new MatTableDataSource<SimpleState>();
displayedColumns = ["name", "initial", "edit", "delete"];
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
@ -93,4 +94,13 @@ export class SimpleStateEditorComponent implements OnInit{
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
onCreateCondition(state: SimpleState, condition: ScriptAccountCondition) {
state.addScriptAccountCondition(condition);
}
deleteCondition(state: SimpleState, condition: ScriptAccountCondition) {
state.removeScriptAccountCondition(condition.scriptAccount);
}
}

View File

@ -4,14 +4,31 @@
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Filter" #input>
</mat-form-field>
<table mat-table [dataSource]="dataSource">
<table mat-table [dataSource]="dataSource" multiTemplateDataRows>
<ng-container *ngFor="let col of displayedColumns; let i = index" [matColumnDef]="col.internalName">
<th mat-header-cell *matHeaderCellDef (dblclick)="openGamesystemEditor(i)">{{col.displayedName}}</th>
<td mat-cell *matCellDef="let transition" [matTooltip]="getLeafStateByIndex(transition, i).stateDescription" (dblclick)="openGamesystemEditor(i)">
{{getLeafStateByIndex(transition, i).stateLabel}}
</td>
</ng-container>
<ng-container [matColumnDef]="'expand'">
<th mat-header-cell *matHeaderCellDef ></th>
<td mat-cell *matCellDef="let transition">
<button mat-icon-button aria-label="expand row" (click)="(expandedElement = expandedElement === transition ? null : transition); $event.stopPropagation()">
@if (expandedElement === transition) {
<mat-icon>keyboard_arrow_up</mat-icon>
} @else {
<mat-icon>keyboard_arrow_down</mat-icon>
}
</button>
</td>
</ng-container>
<ng-container matColumnDef="header-row-sec-group">
<th
mat-header-cell
@ -28,7 +45,7 @@
mat-header-cell
*matHeaderCellDef
[style.text-align]="'center'"
[attr.colspan]="numberLeafSystems"
[attr.colspan]="numberLeafSystems+1"
>
Ending State
</th>
@ -41,9 +58,22 @@
></tr>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
<div class="example-element-detail"
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<app-scriptaccount-condition-editor [enableEditiong]="false" [conditions]="element.scriptAccountConditions" ></app-scriptaccount-condition-editor>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columns;sticky:true"></tr>
<tr mat-row *matRowDef="let row; columns: columns;"></tr>
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
class="example-element-row"
[class.example-expanded-row]="expandedElement === element"
(click)="expandedElement = expandedElement === element ? null : element">
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>

View File

@ -2,3 +2,56 @@
width: 100%;
}
.mat-column-expand {
width: 32px;
text-align: center;
}
table {
width: 100%;
}
tr.example-detail-row {
height: 0;
}
tr.example-element-row:not(.example-expanded-row):hover {
background: whitesmoke;
}
tr.example-element-row:not(.example-expanded-row):active {
background: #efefef;
}
.example-element-row td {
border-bottom-width: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
}
.example-element-diagram {
min-width: 80px;
border: 2px solid black;
padding: 8px;
font-weight: lighter;
margin: 8px 0;
height: 104px;
}
.example-element-symbol {
font-weight: bold;
font-size: 40px;
line-height: normal;
}
.example-element-description {
padding: 16px;
}
.example-element-description-attribution {
opacity: 0.5;
}

View File

@ -1,12 +1,13 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ProductGamesystem} from "../../../../game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {
MatTableDataSource
} from "@angular/material/table";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
import {animate, state, style, transition, trigger} from "@angular/animations";
import {ProductGamesystem} from "../../../../project/game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../project/game-model/gamesystems/SimpleGamesystem";
import {ProductTransition} from "../../../../project/game-model/gamesystems/transitions/ProductTransition";
import {ProductState} from "../../../../project/game-model/gamesystems/states/ProductState";
class DisplayedColumnName {
displayedName: string
internalName: string
@ -20,7 +21,14 @@ class DisplayedColumnName {
@Component({
selector: 'app-product-transition-editor',
templateUrl: './product-transition-editor.component.html',
styleUrl: './product-transition-editor.component.scss'
styleUrl: './product-transition-editor.component.scss',
animations: [
trigger('detailExpand', [
state('collapsed,void', style({height: '0px', minHeight: '0'})),
state('expanded', style({height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class ProductTransitionEditorComponent implements OnInit{
@ -30,6 +38,8 @@ export class ProductTransitionEditorComponent implements OnInit{
dataSource = new MatTableDataSource<ProductTransition>();
displayedColumns: DisplayedColumnName[] = [];
columns: string[] = [];
columnsToDisplayWithExpand = [...this.columns, 'expand'];
expandedElement: ProductTransition | null = null
numberLeafSystems: number = -1;
ngOnInit() {
@ -40,6 +50,7 @@ export class ProductTransitionEditorComponent implements OnInit{
this.numberLeafSystems = leafGamesystems.length;
this.columns = this.displayedColumns.map(column => column.internalName)
this.columnsToDisplayWithExpand = [...this.columns, 'expand']
this.dataSource.data = this.gamesystem.transitions;
this.dataSource.filterPredicate = (data: ProductTransition, filter: string) => {
@ -64,7 +75,6 @@ export class ProductTransitionEditorComponent implements OnInit{
}
const leafStates = LeafGamesystemCalculator.calcLeafStates(state);
console.log(leafStates)
return leafStates[index];
}

View File

@ -0,0 +1,45 @@
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="scriptAccount">
<th mat-header-cell *matHeaderCellDef>ScriptAccount</th>
<td mat-cell *matCellDef="let action">
<span *ngIf="action !== addedAction">{{action.scriptAccount.componentName}}</span>
<mat-form-field appearance="fill" class="long-form" *ngIf="action === addedAction">
<mat-label>ScriptAccount</mat-label>
<mat-select [(ngModel)]="addedAction!.scriptAccount">
<mat-option *ngFor="let scriptAccount of scriptAccounts" [value]="scriptAccount">{{scriptAccount.componentName}}</mat-option>
</mat-select>
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="valueChange">
<th mat-header-cell *matHeaderCellDef>Value</th>
<td mat-cell *matCellDef="let action">
<span *ngIf="addedAction !== action && editedAction != action">{{action.changingValue}}</span>
<mat-form-field appearance="fill" class="long-form" *ngIf="addedAction === action || editedAction === action">
<mat-label>Value</mat-label>
<input matInput [(ngModel)]="editedAction!.changingValue" type="number">
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="edit">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let action">
<button mat-icon-button class="icon-btn-primary" (click)="editAction(action)" [disabled]="addedAction != undefined || editedAction != undefined" *ngIf="action !== editedAction && action !== addedAction"><mat-icon>edit</mat-icon></button>
<button mat-icon-button class="icon-btn-primary" *ngIf="action === editedAction || action === addedAction" (click)="finishEditing()"><mat-icon>done</mat-icon></button>
</td>
</ng-container>
<ng-container matColumnDef="delete">
<th mat-header-cell *matHeaderCellDef>
<button mat-icon-button (click)="createNewAction()"><mat-icon>add</mat-icon></button>
</th>
<td mat-cell *matCellDef="let action">
<button mat-icon-button color="warn" (click)="deleteAction(action)"><mat-icon>delete</mat-icon></button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

View File

@ -0,0 +1,11 @@
table {
width: 100%;
}
.long-form {
width: 100%;
}
.mat-column-edit, .mat-column-delete, .mat-column-expand {
width: 32px;
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ScriptaccountActionEditorComponent } from './scriptaccount-action-editor.component';
describe('ScriptaccountActionEditorComponent', () => {
let component: ScriptaccountActionEditorComponent;
let fixture: ComponentFixture<ScriptaccountActionEditorComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ScriptaccountActionEditorComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ScriptaccountActionEditorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,57 @@
import {Component, Input, OnInit} from '@angular/core';
import {MatTableDataSource} from "@angular/material/table";
import {ScriptAccount} from "../../../../project/game-model/scriptAccounts/ScriptAccount";
import {Transition} from "../../../../project/game-model/gamesystems/transitions/Transition";
import {ScriptAccountAction} from "../../../../project/game-model/gamesystems/actions/ScriptAccountAction";
@Component({
selector: 'app-scriptaccount-action-editor',
templateUrl: './scriptaccount-action-editor.component.html',
styleUrl: './scriptaccount-action-editor.component.scss'
})
export class ScriptaccountActionEditorComponent implements OnInit{
@Input() transition: Transition<any> | undefined
@Input() scriptAccounts: ScriptAccount[] = []
@Input() enableEditing: boolean = false;
dataSource: MatTableDataSource<ScriptAccountAction> = new MatTableDataSource();
displayedColumns: string[] = ['scriptAccount', "valueChange", 'edit', 'delete'];
editedAction: ScriptAccountAction | undefined
addedAction: ScriptAccountAction | undefined
ngOnInit() {
this.dataSource.data = this.transition!.scriptAccountActions.map(action => action);
if(!this.enableEditing) {
this.displayedColumns = this.displayedColumns.slice(0, -2);
}
}
editAction(scriptAccountAction: ScriptAccountAction) {
this.editedAction = scriptAccountAction;
}
createNewAction() {
this.addedAction = new ScriptAccountAction(new ScriptAccount("", ""), 0);
this.editedAction = this.addedAction;
this.dataSource.data = this.dataSource.data.concat(this.addedAction);
}
finishEditing() {
if(this.addedAction != undefined && this.addedAction.scriptAccount.componentName !== '') {
this.transition?.addScriptAccountAction(this.addedAction)
console.log(this.addedAction.scriptAccount)
this.dataSource.data = this.transition!.scriptAccountActions;
console.log(this.dataSource.data.length, this.transition!.scriptAccountActions.length)
this.addedAction = undefined;
}
this.editedAction = undefined;
}
deleteAction(action: ScriptAccountAction) {
this.transition!.removeScriptAccountAction(action.scriptAccount)
this.dataSource.data = this.transition!.scriptAccountActions
}
}

View File

@ -40,7 +40,17 @@
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
<div class="example-element-detail"
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<p>Expanded Detail</p>
<div class="condition-action-container">
<div class="action-container">
<app-scriptaccount-action-editor [transition]="element" [scriptAccounts]="scriptAccounts" [enableEditing]="true"></app-scriptaccount-action-editor>
</div>
<div class="condition-container">
<app-scriptaccount-condition-editor [conditions]="element.scriptAccountConditions" [scriptAccounts]="scriptAccounts" [enableEditiong]="true"
(onCreateCondition)="onCreateCondition(element, $event)" (onDeleteCondition)="deleteCondition(element, $event)"></app-scriptaccount-condition-editor>
</div>
</div>
</div>
</td>
</ng-container>
@ -48,8 +58,8 @@
<ng-container matColumnDef="edit">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let transition">
<button mat-icon-button color="primary" *ngIf="editedTransition !== transition" [disabled]="editedTransition != undefined"><mat-icon>edit</mat-icon></button>
<button mat-icon-button color="primary" *ngIf="editedTransition === transition"
<button mat-icon-button class="icon-btn-primary" *ngIf="editedTransition !== transition" [disabled]="editedTransition != undefined"><mat-icon>edit</mat-icon></button>
<button mat-icon-button class="icon-btn-primary" *ngIf="editedTransition === transition"
[disabled]="transitionError || transitionStartingStateError || transitionEndingStateError" (click)="finishEditing()"
><mat-icon>done</mat-icon></button>
</td>

View File

@ -61,3 +61,16 @@ tr.example-element-row:not(.example-expanded-row):active {
.mat-error {
color: red;
}
.condition-action-container {
display: flex;
width: 100%
}
.condition-container {
width: 45%;
}
.action-container {
width: 45%;
}

View File

@ -1,21 +1,13 @@
import {Component, Input, OnInit} from '@angular/core';
import {GameModel} from "../../../../game-model/GameModel";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {
MatCell,
MatCellDef,
MatColumnDef,
MatHeaderCell,
MatHeaderCellDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
MatTable,
MatTableDataSource
} from "@angular/material/table";
import {SimpleTransition} from "../../../../game-model/gamesystems/SimpleTransition";
import {animate, state, style, transition, trigger} from "@angular/animations";
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
import {SimpleGamesystem} from "../../../../project/game-model/gamesystems/SimpleGamesystem";
import {ScriptAccount} from "../../../../project/game-model/scriptAccounts/ScriptAccount";
import {SimpleTransition} from "../../../../project/game-model/gamesystems/transitions/SimpleTransition";
import {SimpleState} from "../../../../project/game-model/gamesystems/states/SimpleState";
import {ScriptAccountCondition} from "../../../../project/game-model/gamesystems/conditions/ScriptAccountCondition";
@Component({
selector: 'app-simple-transition-editor',
templateUrl: './simple-transition-editor.component.html',
@ -31,6 +23,7 @@ import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGame
export class SimpleTransitionEditorComponent implements OnInit {
@Input() gamesystem: SimpleGamesystem | undefined
@Input() scriptAccounts: ScriptAccount[] = []
displayedColumns: string[] = ["starting-state", "ending-state", "edit", "delete"];
dataSource = new MatTableDataSource<SimpleTransition>();
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
@ -49,6 +42,7 @@ export class SimpleTransitionEditorComponent implements OnInit {
this.dataSource.filterPredicate = (data: SimpleTransition, filter: string) => {
return [data.startingState, data.endingState].some((state) => state.stateLabel.toLowerCase().includes(filter))
}
console.log("TransitionEditor: ", this.scriptAccounts.length)
}
addTransition() {
@ -93,4 +87,14 @@ export class SimpleTransitionEditorComponent implements OnInit {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
protected readonly transition = transition;
onCreateCondition(transition: SimpleTransition, condition: ScriptAccountCondition) {
transition.addScriptAccountCondition(condition);
}
deleteCondition(trasition: SimpleTransition, condition: ScriptAccountCondition) {
trasition.removeScriptAccountCondition(condition.scriptAccount);
}
}

View File

@ -1,6 +1,6 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ModelComponent} from "../../game-model/ModelComponent";
import {FormControl, Validators} from "@angular/forms";
import {ModelComponent} from "../../project/game-model/ModelComponent";
@Component({
selector: 'app-model-component-editor',

View File

@ -1,13 +1,13 @@
<div *ngIf="scriptAccount != undefined">
<mat-form-field class="example-full-width">
<mat-label>MinValue</mat-label>
<input matInput [formControl]="minCtrl" type="number" (keypress)="onKeyPress($event)" (change)="onUpdateMinValue()">
<input matInput [formControl]="minCtrl" type="number" (change)="onUpdateMinValue($event)">
<mat-error *ngIf="minCtrl.hasError('required')">Please enter a valid number!</mat-error>
</mat-form-field>
<mat-form-field class="example-full-width">
<mat-label>MaxValue</mat-label>
<input matInput type="number" [formControl]="maxCtrl" (keypress)="onKeyPress($event)" (change)="onUpdateMaxValue()">
<input matInput type="number" [formControl]="maxCtrl" (change)="onUpdateMaxValue()">
<mat-error *ngIf="maxCtrl.hasError('required')">Please enter a valid number!</mat-error>
</mat-form-field>

View File

@ -1,12 +1,12 @@
import {Component, Input, OnInit} from '@angular/core';
import {ScriptAccount} from "../../game-model/scriptAccounts/ScriptAccount";
import {ModelComponent} from "../../game-model/ModelComponent";
import {MatFormField} from "@angular/material/form-field";
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";
import {ScriptAccount} from "../../project/game-model/scriptAccounts/ScriptAccount";
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
@ -22,8 +22,8 @@ export class MyErrorStateMatcher implements ErrorStateMatcher {
export class ScriptAccountEditorComponent implements OnInit{
@Input("scriptAccount") scriptAccount : ScriptAccount | undefined
minCtrl: FormControl = new FormControl(0, [Validators.required, Validators.pattern('^[0-9]*$')]);
maxCtrl: FormControl = new FormControl(100, [Validators.required, Validators.pattern('^[0-9]*$')]);
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) {
@ -33,15 +33,8 @@ export class ScriptAccountEditorComponent implements OnInit{
this.maxCtrl.setValue(this.scriptAccount!.maxValue);
}
onKeyPress(event: KeyboardEvent) {
const input = event.key;
const isDigit = /^\d+$/.test(input);
if (!isDigit) {
event.preventDefault();
}
}
onUpdateMinValue() {
onUpdateMinValue(event: Event) {
this.scriptAccount!.minValue = Number(this.minCtrl.value);
this.scriptAccount!.onModifyContent();
}

View File

@ -1,47 +0,0 @@
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<jsonObject.states.length; i++) {
const state = new SimpleState("", "");
Object.assign(state, jsonObject.states[i]);
states.push(state);
}
return states;
}
static parseSimpleTransitions(jsonObject: any, states: SimpleState[]): SimpleTransition[] {
const transitions: SimpleTransition[] = [];
for(let i=0; i<jsonObject.transitions.length; i++) {
const startingStateLabel = jsonObject.transitions[i].startingState;
const endingStateLabel = jsonObject.transitions[i].endingState;
const startingState = states.find(state => 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;
}
}

View File

@ -1,27 +0,0 @@
import {Transition} from "./Transition";
export abstract class State<T extends Transition<any>> {
incomingTransitions: T[] =[];
outgoingTransitions: T[] =[];
initial: boolean = false;
addIncomingTransition(transition: T) {
this.incomingTransitions.push(transition);
}
addOutgoingTransition(transition: T) {
this.outgoingTransitions.push(transition);
}
removeIncomingTransition(transition: T) {
}
removeOutgoingTransition(transition: T) {
}
abstract equals(state: State<Transition<any>>): boolean;
}

View File

@ -1,15 +0,0 @@
import {State} from "./State";
export abstract class Transition<S extends State<any>> {
startingState: S
endingState: S
constructor(startingState: S, endingState: S) {
this.startingState = startingState;
this.endingState = endingState;
this.startingState.addOutgoingTransition(this);
this.endingState.addIncomingTransition(this);
}
}

View File

@ -1,39 +1,34 @@
import {Gamesystem} from "./gamesystems/Gamesystem";
import {ScriptAccount} from "./scriptAccounts/ScriptAccount";
import {Transition} from "./gamesystems/Transition";
import {State} from "./gamesystems/State";
import {Transition} from "./gamesystems/transitions/Transition";
import {State} from "./gamesystems/states/State";
import {ProductGamesystem} from "./gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "./gamesystems/SimpleGamesystem";
import {StorageModel} from "./fs/StorageModel";
export class GameModel {
private readonly _gameModelName: string
gameModelName: string
private _gamesystems: Gamesystem<any, any>[] = [];
private _scriptAccounts: ScriptAccount[] = [];
gamesystems: Gamesystem<any, any>[] = [];
scriptAccounts: ScriptAccount[] = [];
constructor(gameModelName: string) {
this._gameModelName = gameModelName;
}
get gameModelName(): string {
return this._gameModelName;
}
get gamesystems(): Gamesystem<any, any>[] {
return this._gamesystems;
}
get scriptAccounts(): ScriptAccount[] {
return this._scriptAccounts;
this.gameModelName = gameModelName;
}
addGamesystem(gamesystem: Gamesystem<any, any>) {
if(this.findGamesystem(gamesystem.componentName) == undefined) {
this._gamesystems.push(gamesystem);
this.gamesystems.push(gamesystem);
}
}
removeGamesystem(gamesystem : Gamesystem<any, any>) {
this._gamesystems = this._gamesystems.filter(g => g !== gamesystem);
if(gamesystem.parentGamesystem == undefined) {
this.gamesystems = this.gamesystems.filter(g => g !== gamesystem);
} else {
(gamesystem.parentGamesystem as ProductGamesystem).removeChildGamesystem(gamesystem);
}
}
createScriptAccount(scriptAccountName: string) {
@ -72,7 +67,7 @@ export class GameModel {
removeScriptAccount(scriptAccount: ScriptAccount) {
if(scriptAccount != undefined) {
this._scriptAccounts = this.scriptAccounts.filter(s => s != scriptAccount);
this.scriptAccounts = this.scriptAccounts.filter(s => s != scriptAccount);
}
}
@ -94,4 +89,12 @@ export class GameModel {
addScriptAccount(scriptAccount: ScriptAccount) {
this.scriptAccounts.push(scriptAccount);
}
generateProductSystemContents() {
this.gamesystems.forEach(gamesystem => {
if(gamesystem instanceof ProductGamesystem) {
gamesystem.generateFromChildsystems();
}
})
}
}

View File

@ -0,0 +1,12 @@
import {ModelComponentType} from "../ModelComponentType";
export class DeleteModel {
componentName: string
modeltype: ModelComponentType
constructor(componentName: string, modeltype: ModelComponentType) {
this.componentName = componentName;
this.modeltype = modeltype;
}
}

View File

@ -47,21 +47,23 @@ export class ProcessLoadedProject {
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 simpleGamesystem: SimpleGamesystem = SimpleGamesystemParser.parseSimpleGamesystem(parsedJsonString, gameModel.scriptAccounts);
const parentModel: ProductGamesystem = gameModel.findGamesystem(recursiveLoadModel.parentLoadModelname) as ProductGamesystem
parentModel.addChildGamesystem(simpleGamesystem);
simpleGamesystem.parentGamesystem = parentModel
} else {
console.log("Gamesystems: ", )
//ProductGamesystem
const productGamesystem: ProductGamesystem = ProductGamesystemParser.parseProductGamesystem(parsedJsonString);
const parentModel: ProductGamesystem = gameModel.findGamesystem(recursiveLoadModel.parentLoadModelname) as ProductGamesystem;
parentModel.addChildGamesystem(productGamesystem);
productGamesystem.parentGamesystem = parentModel
}
} else {
//Top Gamesystem
if(parsedJsonString.hasOwnProperty('states') && parsedJsonString.hasOwnProperty('transitions')) {
//SimpleGamesystem
const simpleGamesystem: SimpleGamesystem = SimpleGamesystemParser.parseSimpleGamesystem(parsedJsonString);
const simpleGamesystem: SimpleGamesystem = SimpleGamesystemParser.parseSimpleGamesystem(parsedJsonString, gameModel.scriptAccounts);
gameModel.addGamesystem(simpleGamesystem);
} else {
//ProductGamesystem

View File

@ -0,0 +1,95 @@
import {SimpleGamesystem} from "../../gamesystems/SimpleGamesystem";
import {SimpleState} from "../../gamesystems/states/SimpleState";
import {SimpleTransition} from "../../gamesystems/transitions/SimpleTransition";
import {ScriptAccount} from "../../scriptAccounts/ScriptAccount";
import {ScriptAccountCondition} from "../../gamesystems/conditions/ScriptAccountCondition";
import {ScriptAccountAction} from "../../gamesystems/actions/ScriptAccountAction";
export class SimpleGamesystemParser {
static parseSimpleGamesystem(jsonObject: any, scriptAccounts: ScriptAccount[] = []) : SimpleGamesystem {
const gamesystemName = jsonObject.componentName;
const gamesystemDescription = jsonObject.componentDescription;
const simpleStates = SimpleGamesystemParser.parseSimpleStates(jsonObject, scriptAccounts)
const simpleTransitions = SimpleGamesystemParser.parseSimpleTransitions(jsonObject, simpleStates, scriptAccounts);
const gamesystem = new SimpleGamesystem(gamesystemName, gamesystemDescription);
gamesystem.states = simpleStates;
gamesystem.transitions = simpleTransitions;
return gamesystem;
}
static parseSimpleStates(jsonObject: any, scriptAccounts: ScriptAccount[] = []): SimpleState[] {
const states: SimpleState[] = [];
for(let i=0; i<jsonObject.states.length; i++) {
const state = new SimpleState(jsonObject.states[i].stateLabel, jsonObject.states[i].stateDescription);
const conditions = jsonObject.states[i].conditions
state.initial = jsonObject.states[i].initial
for(let j=0; j<conditions.length; j++) {
const searchedScriptAccount = scriptAccounts.find(scriptAccount => scriptAccount.componentName === conditions[j].scriptAccount)
if(searchedScriptAccount != undefined) {
const scriptAccountCondition =
ScriptAccountCondition.constructScriptAccountCondition(searchedScriptAccount, conditions[j].minValue, conditions[j].maxValue)
state.conditions.push(scriptAccountCondition!)
}
}
states.push(state);
}
return states;
}
static parseSimpleTransitions(jsonObject: any, states: SimpleState[], scriptAccounts: ScriptAccount[]): SimpleTransition[] {
const transitions: SimpleTransition[] = [];
for(let i=0; i<jsonObject.transitions.length; i++) {
const startingStateLabel = jsonObject.transitions[i].startingState;
const endingStateLabel = jsonObject.transitions[i].endingState;
const startingState = states.find(state => state.stateLabel === startingStateLabel);
const endingState = states.find(state => state.stateLabel === endingStateLabel);
const actions: ScriptAccountAction[] = []
for(let j=0; j<jsonObject.transitions[i].scriptAccountActions.length; j++) {
const scriptAccountName = jsonObject.transitions[i].scriptAccountActions[j].scriptAccount
const referencedScriptAccount = scriptAccounts.find(scriptAccount => scriptAccount.componentName === scriptAccountName)
if(referencedScriptAccount != undefined) {
const scriptAccountAction = new ScriptAccountAction(referencedScriptAccount!, jsonObject.transitions[i].scriptAccountActions[j].changingValue)
actions.push(scriptAccountAction)
}
}
const conditions: ScriptAccountCondition[] = [];
for(let j=0; j<jsonObject.transitions[i].scriptAccountConditions.length; j++) {
const scriptAccountName = jsonObject.transitions[i].scriptAccountConditions[j].scriptAccount
const referencedScriptAccount = scriptAccounts.find(scriptAccount => scriptAccount.componentName === scriptAccountName)
if(referencedScriptAccount != undefined) {
const minValue = jsonObject.transitions[i].scriptAccountConditions[j].minValue
const maxValue = jsonObject.transitions[i].scriptAccountConditions[j].maxValue
const scriptAccountCondition =
ScriptAccountCondition.constructScriptAccountCondition(referencedScriptAccount, minValue, maxValue)
conditions.push(scriptAccountCondition!)
}
}
if(startingState != undefined && endingState != undefined) {
const simpleTransition = new SimpleTransition(startingState, endingState);
simpleTransition.scriptAccountActions = actions;
simpleTransition.scriptAccountConditions = conditions;
transitions.push(simpleTransition);
} else {
console.error("Starting or Ending State are not defined!", startingState, endingState)
}
}
return transitions;
}
}

View File

@ -53,7 +53,11 @@ export class StoreProject {
return value.stateLabel
}
if(key === 'incomingTransitions' || key === 'outgoingTransitions' || key === 'unsaved' || key === 'type') {
if(key === "scriptAccount") {
return value.componentName
}
if(key === 'parentGamesystem' || key === 'incomingTransitions' || key === 'outgoingTransitions' || key === 'unsaved' || key === 'type') {
return undefined;
} else {
return value;

Some files were not shown because too many files have changed in this diff Show More