diff --git a/app/main.ts b/app/main.ts index ba1a8b6..30431c1 100644 --- a/app/main.ts +++ b/app/main.ts @@ -8,6 +8,7 @@ import {ModelComponentFileDirectory} from "./storage/ModelComponentFileDirectory import {GamesystemStorage} from "./storage/storing/GamesystemStorage"; import {Character} from "../src/app/project/game-model/characters/Character"; import {CharacterStorage} from "./storage/storing/CharacterStorage"; +import {ItemgroupStorage} from "./storage/storing/ItemgroupStorage"; let win: BrowserWindow | null = null; const args = process.argv.slice(1), @@ -96,6 +97,29 @@ function createWindow(): BrowserWindow { click: () => { win!.webContents.send('context-menu', "new-character"); } + }, + { + label: "Itemgroup", + submenu: [ + { + label: "Abstract Itemgroup", + click: () => { + win!.webContents.send('context-menu', "new-itemgroup_abstract") + } + }, + { + label: "Concrete Itemgroup", + click: () => { + win!.webContents.send('context-menu', "new-itemgroup_concrete") + } + }, + { + label: "Item", + click: () => { + win!.webContents.send("context-menu", "new-item") + } + } + ] } ] @@ -247,6 +271,10 @@ function recieveGameModelToStore(gameModel: StoredGameModel) { const characterStorage = new CharacterStorage(path.join(projectDirectory, ModelComponentFileDirectory.CHARACTER_DIR_NAME)) characterStorage.storeCharacters(gameModel.storedCharacters) + + const itemgroupStorage = new ItemgroupStorage(path.join(projectDirectory, ModelComponentFileDirectory.ITEMGROUP_DIR_NAME)) + itemgroupStorage.storeItemgroups(gameModel.storedItemgroups); + itemgroupStorage.storeItems(gameModel.storedItems) } /*function deleteComponent(component: DeleteModel) { diff --git a/app/storage/ModelComponentFileDirectory.js b/app/storage/ModelComponentFileDirectory.js index 8d28902..eda48c4 100644 --- a/app/storage/ModelComponentFileDirectory.js +++ b/app/storage/ModelComponentFileDirectory.js @@ -7,4 +7,5 @@ exports.ModelComponentFileDirectory = ModelComponentFileDirectory; ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME = "script-accounts"; ModelComponentFileDirectory.GAMESYSTEM_DIR_NAME = "gamesystems"; ModelComponentFileDirectory.CHARACTER_DIR_NAME = "characters"; +ModelComponentFileDirectory.ITEMGROUP_DIR_NAME = "items"; //# sourceMappingURL=ModelComponentFileDirectory.js.map \ No newline at end of file diff --git a/app/storage/ModelComponentFileDirectory.ts b/app/storage/ModelComponentFileDirectory.ts index a0b9c8c..c68a714 100644 --- a/app/storage/ModelComponentFileDirectory.ts +++ b/app/storage/ModelComponentFileDirectory.ts @@ -2,4 +2,5 @@ export class ModelComponentFileDirectory { public static SCRIPTACCOUNT_DIR_NAME = "script-accounts" public static GAMESYSTEM_DIR_NAME = "gamesystems"; public static CHARACTER_DIR_NAME = "characters"; + static ITEMGROUP_DIR_NAME = "items"; } diff --git a/app/storage/StoredGameModel.js b/app/storage/StoredGameModel.js index 57bfbe7..860b91d 100644 --- a/app/storage/StoredGameModel.js +++ b/app/storage/StoredGameModel.js @@ -2,11 +2,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.StoredGameModel = void 0; class StoredGameModel { - constructor(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters) { + constructor(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, storedItemgroups, storedItems) { this.gameModelName = gameModelName; this.storedGamesystems = storedGamesystems; this.storedScriptAccounts = storedScriptAccounts; this.storedCharacters = storedCharacters; + this.storedItemgroups = storedItemgroups; + this.storedItems = storedItems; } } exports.StoredGameModel = StoredGameModel; diff --git a/app/storage/StoredGameModel.ts b/app/storage/StoredGameModel.ts index d9d762b..829b038 100644 --- a/app/storage/StoredGameModel.ts +++ b/app/storage/StoredGameModel.ts @@ -6,13 +6,17 @@ export class StoredGameModel { storedGamesystems: StoreComponent[] storedScriptAccounts: StoreComponent[] storedCharacters: StoreComponent[] + storedItemgroups: StoreComponent[] + storedItems: StoreComponent[] constructor(gameModelName: string, storedScriptAccounts: StoreComponent[], storedGamesystems: StoreComponent[], - storedCharacters: StoreComponent[]) { + storedCharacters: StoreComponent[], storedItemgroups: StoreComponent[], storedItems: StoreComponent[]) { this.gameModelName = gameModelName; this.storedGamesystems = storedGamesystems; this.storedScriptAccounts = storedScriptAccounts; this.storedCharacters = storedCharacters; + this.storedItemgroups = storedItemgroups; + this.storedItems = storedItems; } } diff --git a/app/storage/loader/GameModelLoader.js b/app/storage/loader/GameModelLoader.js index 480dc36..0b8447e 100644 --- a/app/storage/loader/GameModelLoader.js +++ b/app/storage/loader/GameModelLoader.js @@ -7,8 +7,11 @@ const ModelComponentFileDirectory_1 = require("../ModelComponentFileDirectory"); const ScriptAccountLoader_1 = require("./ScriptAccountLoader"); const GamesystemLoader_1 = require("./GamesystemLoader"); const CharacterLoader_1 = require("./CharacterLoader"); +const ItemLoader_1 = require("./ItemLoader"); class GameModelLoader { constructor(gameModelDir) { + this.loadedItemgroups = []; + this.loadedItems = []; this.gameModelDir = gameModelDir; } loadGameModel() { @@ -16,7 +19,8 @@ class GameModelLoader { const storedScriptAccounts = this.loadScriptAccountComponents(); const storedGamesystems = this.loadGamesystems(); const storedCharacters = this.loadCharacters(); - return new StoredGameModel_1.StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters); + this.loadItemsAndItemgroups(); + return new StoredGameModel_1.StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, this.loadedItemgroups, this.loadedItems); } loadScriptAccountComponents() { const scriptAccountDir = path.join(this.gameModelDir, ModelComponentFileDirectory_1.ModelComponentFileDirectory.SCRIPTACCOUNT_DIR_NAME); @@ -33,6 +37,13 @@ class GameModelLoader { const characterLoader = new CharacterLoader_1.CharacterLoader(characterDir); return characterLoader.loadCharacters(); } + loadItemsAndItemgroups() { + const itemgroupDir = path.join(this.gameModelDir, ModelComponentFileDirectory_1.ModelComponentFileDirectory.ITEMGROUP_DIR_NAME); + const itemgroupLoader = new ItemLoader_1.ItemLoader(itemgroupDir); + itemgroupLoader.loadItemgroups(); + this.loadedItems = itemgroupLoader.loadedItems; + this.loadedItemgroups = itemgroupLoader.loadedItemgroups; + } } exports.GameModelLoader = GameModelLoader; //# sourceMappingURL=GameModelLoader.js.map \ No newline at end of file diff --git a/app/storage/loader/GameModelLoader.ts b/app/storage/loader/GameModelLoader.ts index 615c354..9423d73 100644 --- a/app/storage/loader/GameModelLoader.ts +++ b/app/storage/loader/GameModelLoader.ts @@ -6,10 +6,14 @@ import {ModelComponentFileDirectory} from "../ModelComponentFileDirectory"; import {ScriptAccountLoader} from "./ScriptAccountLoader"; import {GamesystemLoader} from "./GamesystemLoader"; import {CharacterLoader} from "./CharacterLoader"; +import {ItemLoader} from "./ItemLoader"; export class GameModelLoader { gameModelDir: string + loadedItemgroups: StoreComponent[] = [] + loadedItems: StoreComponent[] = [] + constructor(gameModelDir: string) { this.gameModelDir = gameModelDir; @@ -21,8 +25,9 @@ export class GameModelLoader { const storedScriptAccounts = this.loadScriptAccountComponents(); const storedGamesystems = this.loadGamesystems(); const storedCharacters = this.loadCharacters() + this.loadItemsAndItemgroups(); - return new StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters); + return new StoredGameModel(gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, this.loadedItemgroups, this.loadedItems); } private loadScriptAccountComponents() { @@ -44,7 +49,12 @@ export class GameModelLoader { } + private loadItemsAndItemgroups() { + const itemgroupDir = path.join(this.gameModelDir, ModelComponentFileDirectory.ITEMGROUP_DIR_NAME); + const itemgroupLoader = new ItemLoader(itemgroupDir); + itemgroupLoader.loadItemgroups(); - - + this.loadedItems = itemgroupLoader.loadedItems; + this.loadedItemgroups = itemgroupLoader.loadedItemgroups; + } } diff --git a/app/storage/loader/ItemLoader.js b/app/storage/loader/ItemLoader.js new file mode 100644 index 0000000..acb1bff --- /dev/null +++ b/app/storage/loader/ItemLoader.js @@ -0,0 +1,59 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ItemLoader = void 0; +const StoreComponent_1 = require("../StoreComponent"); +const FileUtils_1 = require("../FileUtils"); +const path = require("node:path"); +const ModelComponentType_1 = require("../../../src/app/project/game-model/ModelComponentType"); +const fs = require("node:fs"); +class ItemLoader { + constructor(itemDir) { + this._loadedItemgroups = []; + this._loadedItems = []; + this.itemDir = itemDir; + } + loadItemgroups() { + this.loadItemgroupsRecursively(this.itemDir); + } + get loadedItemgroups() { + return this._loadedItemgroups; + } + get loadedItems() { + return this._loadedItems; + } + loadItemgroupsRecursively(currentDir) { + const itemgroupFiles = FileUtils_1.FileUtils.listFilesInDirectory(currentDir); + itemgroupFiles.forEach(itemgroupFile => { + if (fs.lstatSync(itemgroupFile).isDirectory()) { + this.loadItemgroupsRecursively(itemgroupFile); + } + else if (path.basename(itemgroupFile).endsWith(".json") && this.fileRepresentsItemgroup(itemgroupFile)) { + const loadedItemgroup = this.loadSingleItemgroup(itemgroupFile); + this._loadedItemgroups.push(loadedItemgroup); + } + else if (path.basename(itemgroupFile).endsWith(".json")) { + const loadedItem = this.loadSingleItem(itemgroupFile); + this._loadedItems.push(loadedItem); + } + }); + } + loadSingleItemgroup(itemgroupFile) { + if (itemgroupFile.endsWith(".json")) { + const data = fs.readFileSync(itemgroupFile, "utf-8"); + return new StoreComponent_1.StoreComponent(data, itemgroupFile, ModelComponentType_1.ModelComponentType.ITEMGROUP); + } + return undefined; + } + loadSingleItem(itemFile) { + if (itemFile.endsWith(".json")) { + const data = fs.readFileSync(itemFile, "utf-8"); + return new StoreComponent_1.StoreComponent(data, itemFile, ModelComponentType_1.ModelComponentType.ITEM); + } + return undefined; + } + fileRepresentsItemgroup(file) { + return path.basename(path.dirname(file)) === path.parse(path.basename(file)).name; + } +} +exports.ItemLoader = ItemLoader; +//# sourceMappingURL=ItemLoader.js.map \ No newline at end of file diff --git a/app/storage/loader/ItemLoader.ts b/app/storage/loader/ItemLoader.ts new file mode 100644 index 0000000..91b6a83 --- /dev/null +++ b/app/storage/loader/ItemLoader.ts @@ -0,0 +1,65 @@ +import {StoreComponent} from "../StoreComponent"; +import {FileUtils} from "../FileUtils"; +import * as path from "node:path"; +import {ModelComponentType} from "../../../src/app/project/game-model/ModelComponentType"; +import * as fs from "node:fs"; + +export class ItemLoader { + + itemDir: string + private _loadedItemgroups: StoreComponent[] = [] + private _loadedItems: StoreComponent[] = [] + + constructor(itemDir: string) { + this.itemDir = itemDir; + } + + loadItemgroups(){ + this.loadItemgroupsRecursively(this.itemDir); + } + + + get loadedItemgroups(): StoreComponent[] { + return this._loadedItemgroups; + } + + get loadedItems(): StoreComponent[] { + return this._loadedItems; + } + + private loadItemgroupsRecursively(currentDir: string) { + const itemgroupFiles = FileUtils.listFilesInDirectory(currentDir); + + itemgroupFiles.forEach(itemgroupFile => { + if(fs.lstatSync(itemgroupFile).isDirectory()) { + this.loadItemgroupsRecursively(itemgroupFile); + } else if(path.basename(itemgroupFile).endsWith(".json") && this.fileRepresentsItemgroup(itemgroupFile)){ + const loadedItemgroup = this.loadSingleItemgroup(itemgroupFile)!; + this._loadedItemgroups.push(loadedItemgroup) + } else if(path.basename(itemgroupFile).endsWith(".json")) { + const loadedItem = this.loadSingleItem(itemgroupFile)!; + this._loadedItems.push(loadedItem); + } + }) + } + + private loadSingleItemgroup(itemgroupFile: string): StoreComponent | undefined { + if(itemgroupFile.endsWith(".json")) { + const data = fs.readFileSync(itemgroupFile, "utf-8"); + return new StoreComponent(data, itemgroupFile, ModelComponentType.ITEMGROUP); + } + return undefined + } + + private loadSingleItem(itemFile: string) { + if(itemFile.endsWith(".json")) { + const data = fs.readFileSync(itemFile, "utf-8"); + return new StoreComponent(data, itemFile, ModelComponentType.ITEM); + } + return undefined + } + + private fileRepresentsItemgroup(file: string): boolean { + return path.basename(path.dirname(file)) === path.parse(path.basename(file)).name; + } +} diff --git a/app/storage/storing/ItemgroupStorage.js b/app/storage/storing/ItemgroupStorage.js new file mode 100644 index 0000000..2851c97 --- /dev/null +++ b/app/storage/storing/ItemgroupStorage.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ItemgroupStorage = void 0; +const FileUtils_1 = require("../FileUtils"); +const path = require("node:path"); +const fs = require("node:fs"); +class ItemgroupStorage { + constructor(itemgroupDir) { + this.itemgroupDir = itemgroupDir; + FileUtils_1.FileUtils.prepareDirectoryFroWriting(this.itemgroupDir); + } + storeItemgroups(itemgroups) { + itemgroups.forEach(itemgroup => { + this.storeItemgroup(itemgroup); + }); + } + storeItemgroup(itemgroup) { + const file = path.join(...itemgroup.fileName.split("/")); + const completeFileName = path.join(this.itemgroupDir, file); + const itemgroupDirectory = path.join(...itemgroup.fileName.split("/").slice(0, -1)); + const completeItemgroupDirectory = path.join(this.itemgroupDir, itemgroupDirectory); + FileUtils_1.FileUtils.prepareDirectoryFroWriting(completeItemgroupDirectory); + fs.writeFileSync(completeFileName + ".json", itemgroup.jsonString, "utf-8"); + } + storeItems(storedItems) { + storedItems.forEach(item => this.storeItemgroup(item)); + } +} +exports.ItemgroupStorage = ItemgroupStorage; +//# sourceMappingURL=ItemgroupStorage.js.map \ No newline at end of file diff --git a/app/storage/storing/ItemgroupStorage.ts b/app/storage/storing/ItemgroupStorage.ts new file mode 100644 index 0000000..84f7fdd --- /dev/null +++ b/app/storage/storing/ItemgroupStorage.ts @@ -0,0 +1,35 @@ +import {FileUtils} from "../FileUtils"; +import {StoreComponent} from "../StoreComponent"; +import * as path from "node:path"; +import * as fs from "node:fs"; + +export class ItemgroupStorage { + private itemgroupDir: string + + + constructor(itemgroupDir: string) { + this.itemgroupDir = itemgroupDir; + FileUtils.prepareDirectoryFroWriting(this.itemgroupDir); + } + + public storeItemgroups(itemgroups: StoreComponent[]) { + itemgroups.forEach(itemgroup => { + this.storeItemgroup(itemgroup) + }) + } + + private storeItemgroup(itemgroup: StoreComponent) { + const file = path.join(... itemgroup.fileName.split("/")); + const completeFileName = path.join(this.itemgroupDir, file); + + const itemgroupDirectory = path.join(... itemgroup.fileName.split("/").slice(0, -1)) + const completeItemgroupDirectory = path.join(this.itemgroupDir, itemgroupDirectory) + FileUtils.prepareDirectoryFroWriting(completeItemgroupDirectory); + fs.writeFileSync(completeFileName + ".json", itemgroup.jsonString, "utf-8") + } + + + storeItems(storedItems: StoreComponent[]) { + storedItems.forEach(item => this.storeItemgroup(item)) + } +} diff --git a/src/app/app.component.html b/src/app/app.component.html index 0626929..c8c374d 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -6,6 +6,9 @@ (click)="openGamesystemsOverview()">code + + @@ -23,11 +26,15 @@ + +
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3ad2831..6a0240f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -27,6 +27,9 @@ import {CharacterParser} from "./project/parser/characterParser/CharacterParser" import {TemplateType} from "./project/game-model/templates/TemplateType"; import {TemplateTypeUtilities} from "./project/game-model/templates/TemplateTypeUtilities"; import {SimpleTemplateGamesystem} from "./project/game-model/templates/simpleGamesystem/SimpleTemplateGamesystem"; +import {ItemSerializer} from "./project/serializer/ItemSerializer"; +import {ItemgroupParser} from "./project/parser/itemParser/ItemgroupParser"; +import {ItemParser} from "./project/parser/itemParser/ItemParser"; @Component({ selector: 'app-root', @@ -223,6 +226,13 @@ export class AppComponent implements OnInit{ const characterParser = new CharacterParser(characterTemplateSystems, characterRelationTemplateSystems, gameModel.scriptAccounts); gameModel.characters = characterParser.parseCharacters(storedGameModel.storedCharacters) + const itemgroupParser = new ItemgroupParser(); + itemgroupParser.parseItemgroups(storedGameModel.storedItemgroups); + gameModel.itemgroups = itemgroupParser.getParsedTopItemgroups(); + + const itemParser = new ItemParser(itemgroupParser.getParsedItemgroups()) + itemParser.parseItems(storedGameModel.storedItems); + this.gameModel = gameModel; } @@ -231,7 +241,12 @@ export class AppComponent implements OnInit{ const storedScriptAccounts = ScriptAccountSerializer.serializeScriptAccounts(this.gameModel.scriptAccounts) const storedGamesystems: StoreComponent[] = GamesystemSerializer.serializeGamesystems(this.gameModel.gamesystems) const storedCharacters: StoreComponent[] = CharacterSerializer.serializeCharacters(this.gameModel.characters) - const storeModel = new StoredGameModel(this.gameModel.gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters) + + const itemSerializer = new ItemSerializer(); + const storedItemgroups: StoreComponent[] = itemSerializer.serializeItemgroups(this.gameModel!.itemgroups); + const storedItems: StoreComponent[] = itemSerializer.getSerializedItems() + + const storeModel = new StoredGameModel(this.gameModel.gameModelName, storedScriptAccounts, storedGamesystems, storedCharacters, storedItemgroups, storedItems) if(this.electronService.isElectron) { this.electronService.ipcRenderer.send('save-model', storeModel) @@ -254,6 +269,11 @@ export class AppComponent implements OnInit{ this.drawer!.open() } + openOverview(overviewType: ModelComponentType) { + this.openContent = overviewType; + this.drawer!.open(); + } + protected readonly ModelComponentType = ModelComponentType; closeContentOverview() { @@ -284,4 +304,5 @@ export class AppComponent implements OnInit{ } + protected readonly open = open; } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 34970f6..152535a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -72,7 +72,7 @@ import {CharacterOverviewComponent} from "./side-overviews/character-overview/ch import {CharacterEditorComponent} from "./editor/character-editor/character-editor.component"; import { MatAccordion, - MatExpansionPanel, + MatExpansionPanel, MatExpansionPanelDescription, MatExpansionPanelHeader, MatExpansionPanelTitle } from "@angular/material/expansion"; @@ -82,7 +82,15 @@ import { import { StateInitialCellComponent } from "./editor/gamesystem-editor/state-editor/simple-state-editor/state-initial-cell/state-initial-cell.component"; - +import {ItemOverviewComponent} from "./side-overviews/item-overview/item-overview.component"; +import {ItemGroupEditorComponent} from "./editor/items/item-group-editor/item-group-editor.component"; +import {ItemEditorComponent} from "./editor/items/item-editor/item-editor.component"; +import { + ItemgroupInheritorComponent +} from "./editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component"; +import { + InheritedItemCharacteristicEditorComponent +} from "./editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component"; // AoT requires an exported function for factories const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json'); @@ -107,71 +115,77 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl CharacterOverviewComponent, CharacterEditorComponent, TemplateSpecificatorComponent, - StateInitialCellComponent + StateInitialCellComponent, + ItemOverviewComponent, + ItemGroupEditorComponent, + ItemEditorComponent, + ItemgroupInheritorComponent, + InheritedItemCharacteristicEditorComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpClientModule, + CoreModule, + SharedModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: httpLoaderFactory, + deps: [HttpClient] + } + }), + BrowserAnimationsModule, + MatIcon, + MatToolbar, + MatButton, + MatFormField, + MatInput, + MatDrawerContainer, + MatDrawer, + MatIconButton, + MatMenuTrigger, + MatMenu, + MatMenuItem, + MatListItem, + MatActionList, + MatTabGroup, + MatTab, + MatTabLabel, + MatLabel, + MatFormField, + ReactiveFormsModule, + MatError, + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatMiniFabButton, + MatTreeModule, + MatTable, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatCellDef, + MatCell, + MatHeaderRow, + MatRow, + MatHeaderRowDef, + MatRowDef, + MatCheckbox, + MatSelect, + MatOption, + MatHint, + MatTooltip, + MatCard, + MatCardContent, + MatCardHeader, + MatAccordion, + MatExpansionPanel, + MatExpansionPanelTitle, + MatCardTitle, + MatExpansionPanelHeader, + MatExpansionPanelDescription ], - imports: [ - BrowserModule, - FormsModule, - HttpClientModule, - CoreModule, - SharedModule, - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useFactory: httpLoaderFactory, - deps: [HttpClient] - } - }), - BrowserAnimationsModule, - MatIcon, - MatToolbar, - MatButton, - MatFormField, - MatInput, - MatDrawerContainer, - MatDrawer, - MatIconButton, - MatMenuTrigger, - MatMenu, - MatMenuItem, - MatListItem, - MatActionList, - MatTabGroup, - MatTab, - MatTabLabel, - MatLabel, - MatFormField, - ReactiveFormsModule, - MatError, - MatDialogTitle, - MatDialogContent, - MatDialogActions, - MatMiniFabButton, - MatTreeModule, - MatTable, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatCellDef, - MatCell, - MatHeaderRow, - MatRow, - MatHeaderRowDef, - MatRowDef, - MatCheckbox, - MatSelect, - MatOption, - MatHint, - MatTooltip, - MatCard, - MatCardContent, - MatCardHeader, - MatAccordion, - MatExpansionPanel, - MatExpansionPanelTitle, - MatCardTitle, - MatExpansionPanelHeader - ], providers: [], bootstrap: [AppComponent] }) diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index 23be637..ae86488 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -20,5 +20,7 @@ > + + diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts index 50f44b9..2b31b33 100644 --- a/src/app/editor/editor.component.ts +++ b/src/app/editor/editor.component.ts @@ -7,6 +7,8 @@ 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"; import {Character} from "../project/game-model/characters/Character"; +import {ItemGroup} from "../project/game-model/inventory/ItemGroup"; +import {Item} from "../project/game-model/inventory/Item"; @Component({ @@ -57,4 +59,18 @@ export class EditorComponent { return modelComponent as Character return undefined; } + + convertModelComponentToItemGroup(modelComponent: ModelComponent) { + if(modelComponent instanceof ItemGroup) { + return modelComponent as ItemGroup + } + return undefined; + } + + convertModelComponentToItem(modelComponent: ModelComponent) { + if(modelComponent instanceof Item) { + return modelComponent as Item; + } + return undefined; + } } diff --git a/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.html b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.html new file mode 100644 index 0000000..42bbb40 --- /dev/null +++ b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + +
Characteristic{{characteristicValue.key.characteristicName}}Value + {{characteristicValue.value}} + + Value + + + + + +
diff --git a/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.scss b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.scss new file mode 100644 index 0000000..80c8212 --- /dev/null +++ b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.scss @@ -0,0 +1,3 @@ +.mat-column-edit { + width: 32px; +} diff --git a/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.spec.ts b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.spec.ts new file mode 100644 index 0000000..437d097 --- /dev/null +++ b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { InheritedItemCharacteristicEditorComponent } from './inherited-item-characteristic-editor.component'; + +describe('InheritedItemCharacteristicEditorComponent', () => { + let component: InheritedItemCharacteristicEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [InheritedItemCharacteristicEditorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(InheritedItemCharacteristicEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.ts b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.ts new file mode 100644 index 0000000..167bd38 --- /dev/null +++ b/src/app/editor/items/item-editor/inherited-item-characteristic-editor/inherited-item-characteristic-editor.component.ts @@ -0,0 +1,42 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {ItemGroup} from "../../../../project/game-model/inventory/ItemGroup"; +import {Item} from "../../../../project/game-model/inventory/Item"; +import {MatTableDataSource} from "@angular/material/table"; +import {ItemgroupCharacteristicValue} from "../../../../project/game-model/inventory/ItemgroupCharacteristicValue"; + +@Component({ + selector: 'app-inherited-item-characteristic-editor', + templateUrl: './inherited-item-characteristic-editor.component.html', + styleUrl: './inherited-item-characteristic-editor.component.scss' +}) +export class InheritedItemCharacteristicEditorComponent implements OnInit{ + + @Input() inheritedItemgroup: ItemGroup | undefined + @Input() item: Item | undefined + + datasource: MatTableDataSource = new MatTableDataSource(); + displayedColumns: string[] = ['characteristic', 'value', 'edit'] + editedItemgroupCharacteristicValue: ItemgroupCharacteristicValue | undefined + + ngOnInit() { + this.item!.initializeItemCharacteristics(); + this.datasource.data = this.findCharacteristicValuesByItemgroup(this.inheritedItemgroup!); + } + + + findCharacteristicValuesByItemgroup(itemGroup: ItemGroup): ItemgroupCharacteristicValue[] { + const result = this.item?.itemCharacteristicValues.filter(value => value.key.itemgroup.componentName === itemGroup.componentName); + if(result != undefined) { + return result; + } + return [] + } + + editCharacteristicValue(itemCharacteristicValue: ItemgroupCharacteristicValue): void { + this.editedItemgroupCharacteristicValue = itemCharacteristicValue; + } + + finishEditing() { + this.editedItemgroupCharacteristicValue = undefined; + } +} diff --git a/src/app/editor/items/item-editor/item-editor.component.html b/src/app/editor/items/item-editor/item-editor.component.html new file mode 100644 index 0000000..8ff7a5d --- /dev/null +++ b/src/app/editor/items/item-editor/item-editor.component.html @@ -0,0 +1,20 @@ + + + Inherited Itemgroups + + + + + + {{itemgroup.componentName}} + {{itemgroup.componentDescription}} + + +
+ +
+
+
+ +
+
diff --git a/src/app/editor/items/item-editor/item-editor.component.scss b/src/app/editor/items/item-editor/item-editor.component.scss new file mode 100644 index 0000000..6fd81c6 --- /dev/null +++ b/src/app/editor/items/item-editor/item-editor.component.scss @@ -0,0 +1,3 @@ +.panel-actions { + float: right; +} diff --git a/src/app/editor/items/item-editor/item-editor.component.spec.ts b/src/app/editor/items/item-editor/item-editor.component.spec.ts new file mode 100644 index 0000000..a1e4546 --- /dev/null +++ b/src/app/editor/items/item-editor/item-editor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemEditorComponent } from './item-editor.component'; + +describe('ItemEditorComponent', () => { + let component: ItemEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ItemEditorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ItemEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/editor/items/item-editor/item-editor.component.ts b/src/app/editor/items/item-editor/item-editor.component.ts new file mode 100644 index 0000000..05a673d --- /dev/null +++ b/src/app/editor/items/item-editor/item-editor.component.ts @@ -0,0 +1,49 @@ +import {Component, Input} from '@angular/core'; +import {Item} from "../../../project/game-model/inventory/Item"; +import {ItemGroup} from "../../../project/game-model/inventory/ItemGroup"; +import {GameModel} from "../../../project/game-model/GameModel"; +import {MatDialog} from "@angular/material/dialog"; +import {ItemgroupInheritorComponent} from "./itemgroup-inheritor/itemgroup-inheritor.component"; +import {ItemgroupUtilities} from "../../../project/game-model/utils/ItemgroupUtilities"; + +@Component({ + selector: 'app-item-editor', + templateUrl: './item-editor.component.html', + styleUrl: './item-editor.component.scss' +}) +export class ItemEditorComponent { + + @Input() item: Item | undefined + @Input() gameModel: GameModel | undefined; + + + constructor(private dialog: MatDialog) { + + } + + onAddNewInheritedItemgroup() { + const itemgroups = this.item!.manuallyInheritedGroups.concat(this.item!.hierarchyInheritedGroups); + const dialogRef = this.dialog.open(ItemgroupInheritorComponent, { + data: this.gameModel!.itemgroupsAsList.filter(group => !itemgroups.includes(group)), + width: "400px" + }) + + dialogRef.afterClosed().subscribe(res => { + if(res != undefined) { + this.item!.addInheritedGroup(res); + } + }) + } + + deleteInheritedItemgroup(itemgroup: ItemGroup) { + this.item!.deleteInheritedGroup(itemgroup); + } + + get automaticallyInheritedItemgroups() { + return ItemgroupUtilities.findItemgroupPathToItem(this.item!.componentName, this.gameModel!.itemgroups); + } + + get manuallyAndHierarchyItemgroups() { + return this.item!.hierarchyInheritedGroups.concat(this.item!.manuallyInheritedGroups); + } +} diff --git a/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.html b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.html new file mode 100644 index 0000000..dc0ed23 --- /dev/null +++ b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.html @@ -0,0 +1,13 @@ +

Inherit Itemgroup

+ + + Select Itemgroup + + {{itemgroup.componentName}} + + + + + + + diff --git a/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.scss b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.spec.ts b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.spec.ts new file mode 100644 index 0000000..3bdf452 --- /dev/null +++ b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemgroupInheritorComponent } from './itemgroup-inheritor.component'; + +describe('ItemgroupInheritorComponent', () => { + let component: ItemgroupInheritorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ItemgroupInheritorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ItemgroupInheritorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.ts b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.ts new file mode 100644 index 0000000..c71a02e --- /dev/null +++ b/src/app/editor/items/item-editor/itemgroup-inheritor/itemgroup-inheritor.component.ts @@ -0,0 +1,25 @@ +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef, MatDialogTitle} from "@angular/material/dialog"; +import {ItemGroup} from "../../../../project/game-model/inventory/ItemGroup"; + +@Component({ + selector: 'app-itemgroup-inheritor', + templateUrl: './itemgroup-inheritor.component.html', + styleUrl: './itemgroup-inheritor.component.scss' +}) +export class ItemgroupInheritorComponent { + + selectedItemgroup: ItemGroup | undefined + + constructor(private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public availableItemgroups: ItemGroup[]) { + } + + cancel() { + this.dialogRef.close() + } + + submit() { + this.dialogRef.close(this.selectedItemgroup); + } +} diff --git a/src/app/editor/items/item-group-editor/item-group-editor.component.html b/src/app/editor/items/item-group-editor/item-group-editor.component.html new file mode 100644 index 0000000..caa4082 --- /dev/null +++ b/src/app/editor/items/item-group-editor/item-group-editor.component.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + +
Characteristic + {{element.characteristicName}} + + Name + + + Description + {{element.characteristicDescription}} + + Name + + + + + +
diff --git a/src/app/editor/items/item-group-editor/item-group-editor.component.scss b/src/app/editor/items/item-group-editor/item-group-editor.component.scss new file mode 100644 index 0000000..9aa19ce --- /dev/null +++ b/src/app/editor/items/item-group-editor/item-group-editor.component.scss @@ -0,0 +1,7 @@ +.mat-column-edit, .mat-column-delete { + width: 32px; +} + +.mat-column-Characteristic, { + width: 25%; +} diff --git a/src/app/editor/items/item-group-editor/item-group-editor.component.spec.ts b/src/app/editor/items/item-group-editor/item-group-editor.component.spec.ts new file mode 100644 index 0000000..a6bbd54 --- /dev/null +++ b/src/app/editor/items/item-group-editor/item-group-editor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemGroupEditorComponent } from './item-group-editor.component'; + +describe('ItemGroupEditorComponent', () => { + let component: ItemGroupEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ItemGroupEditorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ItemGroupEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/editor/items/item-group-editor/item-group-editor.component.ts b/src/app/editor/items/item-group-editor/item-group-editor.component.ts new file mode 100644 index 0000000..2436e71 --- /dev/null +++ b/src/app/editor/items/item-group-editor/item-group-editor.component.ts @@ -0,0 +1,46 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {ItemGroup} from "../../../project/game-model/inventory/ItemGroup"; +import {MatColumnDef, MatTable, MatTableDataSource} from "@angular/material/table"; +import {ItemGroupCharacteristic} from "../../../project/game-model/inventory/ItemgroupCharacteristic"; +import {Item} from "../../../project/game-model/inventory/Item"; + +@Component({ + selector: 'app-item-group-editor', + templateUrl: './item-group-editor.component.html', + styleUrl: './item-group-editor.component.scss' +}) +export class ItemGroupEditorComponent implements OnInit{ + + @Input() itemgroup: ItemGroup | undefined + + itemQualityDatasource: MatTableDataSource = new MatTableDataSource(); + displayedColumns: string[] = ["Characteristic", "Description", 'edit', 'delete'] + + editedCharacteristic: ItemGroupCharacteristic | undefined; + + + ngOnInit(): void { + this.itemQualityDatasource.data = this.itemgroup!.itemGroupCharacteristics; + } + + deleteItemgroupCharacteristic(characteristic: ItemGroupCharacteristic) { + this.itemgroup!.itemGroupCharacteristics = this.itemgroup!.itemGroupCharacteristics.filter(igc => igc.characteristicName !== characteristic.characteristicName); + this.itemQualityDatasource.data = this.itemgroup!.itemGroupCharacteristics; + } + + editItemgroupCharacteristic(characteristic: ItemGroupCharacteristic) { + this.editedCharacteristic = characteristic; + } + + finishEditing() { + this.editedCharacteristic = undefined; + } + + addItemgroupCharacteristic() { + const itemgroupCharacteristic = new ItemGroupCharacteristic("", "", this.itemgroup!); + this.itemgroup!.addItemgroupCharacteristic(itemgroupCharacteristic); + + this.itemQualityDatasource.data = this.itemgroup!.itemGroupCharacteristics; + this.editedCharacteristic = itemgroupCharacteristic; + } +} diff --git a/src/app/project/game-model/GameModel.ts b/src/app/project/game-model/GameModel.ts index 295b6bb..dde1cc3 100644 --- a/src/app/project/game-model/GameModel.ts +++ b/src/app/project/game-model/GameModel.ts @@ -11,6 +11,12 @@ import {SimpleTemplateGamesystem} from "./templates/simpleGamesystem/SimpleTempl import {ProductTemplateSystem} from "./templates/productGamesystem/ProductTemplateSystem"; import {ProductTemplateCreator} from "./templates/productGamesystem/ProductTemplateCreator"; import {CharacterRelation} from "./characters/CharacterRelation"; +import {ItemGroup} from "./inventory/ItemGroup"; +import {AbstractItemGroup} from "./inventory/AbstractItemGroup"; +import {ConcreteItemGroup} from "./inventory/ConcreteItemGroup"; +import {Item} from "./inventory/Item"; +import {ItemgroupUtilities} from "./utils/ItemgroupUtilities"; +import {ItemGroupCharacteristic} from "./inventory/ItemgroupCharacteristic"; export class GameModel { gameModelName: string @@ -18,11 +24,69 @@ export class GameModel { gamesystems: Gamesystem[] = []; scriptAccounts: ScriptAccount[] = []; characters: Character[] = [] + itemgroups: ItemGroup[] = [] constructor(gameModelName: string) { this.gameModelName = gameModelName; } + addAbstractItemgroup(groupName: string, parentgroup: AbstractItemGroup | undefined) { + //Ensure that Itemgroup does not exist + if(parentgroup == undefined) { + if(GameModel.findItemgroupByName(groupName, this.itemgroups) == undefined) { + const itemgroup = new AbstractItemGroup(groupName, "", ModelComponentType.ITEMGROUP) + this.itemgroups.push(itemgroup); + itemgroup.addItemgroupCharacteristic(new ItemGroupCharacteristic("Test0", "", itemgroup)); + } + } else { + if(GameModel.findItemgroupByName(groupName, parentgroup.children) == undefined) { + parentgroup.addChildItemgroup(new AbstractItemGroup(groupName, "", ModelComponentType.ITEMGROUP)); + } + } + } + + addConcreteItemgroup(groupName: string, parentgroup: AbstractItemGroup | undefined) { + //Ensure that Itemgroup does not exist + if(parentgroup == undefined) { + if(GameModel.findItemgroupByName(groupName, this.itemgroups) == undefined) { + this.itemgroups.push(new ConcreteItemGroup(groupName, "", ModelComponentType.ITEMGROUP)); + } + } else { + if(GameModel.findItemgroupByName(groupName, parentgroup.children) == undefined) { + parentgroup.addChildItemgroup(new ConcreteItemGroup(groupName, "", ModelComponentType.ITEMGROUP)); + } + } + } + + addItem(itemName: string, conceteItemgroupName: string) { + const itemgroup = GameModel.findItemgroupByName(conceteItemgroupName, this.itemgroups); + if(itemgroup instanceof ConcreteItemGroup) { + const itemgroups: ItemGroup[] = ItemgroupUtilities.findItemgroupPathToItemgroup(conceteItemgroupName, this.itemgroups); + + if(itemgroups.length > 0) { + const item = new Item(itemName, "", ModelComponentType.ITEM ) + itemgroup.addItem(item, itemgroups) + return item; + } + } + } + + + public static findItemgroupByName(name: string, itemgroups: ItemGroup[]) { + const itemgroupQueue: ItemGroup[] = itemgroups.concat(); + while(itemgroupQueue.length > 0 ) { + const currentItemgroup = itemgroupQueue.shift()!; + + if(currentItemgroup.componentName === name) { + return currentItemgroup; + } + + if(currentItemgroup instanceof AbstractItemGroup) { + currentItemgroup.children.forEach(itemgroup => itemgroupQueue.push(itemgroup)); + } + } + } + addGamesystem(gamesystem: Gamesystem) { if(this.findGamesystem(gamesystem.componentName) == undefined) { this.gamesystems.push(gamesystem); @@ -202,4 +266,19 @@ export class GameModel { return requestedTemplates; } + + get itemgroupsAsList() { + let itemgroupQueue: ItemGroup[] = this.itemgroups.concat(); + const result: ItemGroup[] = [] + while(itemgroupQueue.length > 0) { + const currentGroup = itemgroupQueue.shift()!; + + if(currentGroup instanceof AbstractItemGroup) { + itemgroupQueue = itemgroupQueue.concat(currentGroup.children); + } + result.push(currentGroup); + } + + return result; + } } diff --git a/src/app/project/game-model/ModelComponentType.ts b/src/app/project/game-model/ModelComponentType.ts index 14eaf8b..ffef110 100644 --- a/src/app/project/game-model/ModelComponentType.ts +++ b/src/app/project/game-model/ModelComponentType.ts @@ -1,6 +1,8 @@ export enum ModelComponentType { SCRIPTACCOUNT, GAMESYTEM, - CHARACTER + CHARACTER, + ITEMGROUP, + ITEM } diff --git a/src/app/project/game-model/ModelComponentTypeUtillities.ts b/src/app/project/game-model/ModelComponentTypeUtillities.ts index aa736fd..984a7a2 100644 --- a/src/app/project/game-model/ModelComponentTypeUtillities.ts +++ b/src/app/project/game-model/ModelComponentTypeUtillities.ts @@ -6,6 +6,8 @@ export class ModelComponentTypeUtillities { case ModelComponentType.SCRIPTACCOUNT: return "ScriptAccounts"; case ModelComponentType.GAMESYTEM: return "Gamesystems"; case ModelComponentType.CHARACTER: return "Characters" + case ModelComponentType.ITEM: return "Items"; + case ModelComponentType.ITEMGROUP: return "Itemgroups"; default: return "Undefined"; } } @@ -15,6 +17,8 @@ export class ModelComponentTypeUtillities { case ModelComponentType.SCRIPTACCOUNT: return "ScriptAccount"; case ModelComponentType.GAMESYTEM: return "Gamesystem"; case ModelComponentType.CHARACTER: return "Character" + case ModelComponentType.ITEM: return "Item"; + case ModelComponentType.ITEMGROUP: return "Itemgroup"; default: return "Undefined"; } } @@ -24,6 +28,8 @@ export class ModelComponentTypeUtillities { case "gamesystem": return ModelComponentType.GAMESYTEM; case "scriptaccount": return ModelComponentType.SCRIPTACCOUNT; case "character": return ModelComponentType.CHARACTER + case "item": return ModelComponentType.ITEM; + case "itemgroup": return ModelComponentType.ITEMGROUP; } } } diff --git a/src/app/project/game-model/inventory/AbstractItemGroup.ts b/src/app/project/game-model/inventory/AbstractItemGroup.ts new file mode 100644 index 0000000..cc95cb0 --- /dev/null +++ b/src/app/project/game-model/inventory/AbstractItemGroup.ts @@ -0,0 +1,20 @@ +import {ItemGroup} from "./ItemGroup"; +import {ItemGroupCharacteristic} from "./ItemgroupCharacteristic"; +import {ItemgroupType} from "./ItemgroupType"; + +export class AbstractItemGroup extends ItemGroup { + + children: ItemGroup[] = []; + itemgroupType = ItemgroupType.ABSTRACT + + addChildItemgroup(itemGroup: ItemGroup) { + this.children.push(itemGroup) + itemGroup.parentGroup = this; + } + + protected addCharacteristicValue(characteristic: ItemGroupCharacteristic): void { + //Do Nothing + } + + +} diff --git a/src/app/project/game-model/inventory/ConcreteItemGroup.ts b/src/app/project/game-model/inventory/ConcreteItemGroup.ts new file mode 100644 index 0000000..5ad4710 --- /dev/null +++ b/src/app/project/game-model/inventory/ConcreteItemGroup.ts @@ -0,0 +1,31 @@ +import {ItemGroup} from "./ItemGroup"; +import {Item} from "./Item"; +import {ItemGroupCharacteristic} from "./ItemgroupCharacteristic"; +import {ItemgroupType} from "./ItemgroupType"; + +export class ConcreteItemGroup extends ItemGroup { + + items: Item[] = []; + itemgroupType = ItemgroupType.CONCRETE + + addItem(item: Item, parentItemgroups: ItemGroup[]) { + if(this.findItemByName(item.componentName) == undefined) { + parentItemgroups.forEach(itemgroup => { + item.addInheritedHierarchyGroup(itemgroup); + }) + this.items.push(item); + } + } + + findItemByName(itemName: string) { + return this.items.find(item => item.componentName === itemName); + } + + protected addCharacteristicValue(characteristic: ItemGroupCharacteristic): void { + this.items.forEach(item => { + item.addCharacteristic(characteristic); + }) + } + + +} diff --git a/src/app/project/game-model/inventory/Item.ts b/src/app/project/game-model/inventory/Item.ts new file mode 100644 index 0000000..6d0978c --- /dev/null +++ b/src/app/project/game-model/inventory/Item.ts @@ -0,0 +1,59 @@ +import {ModelComponent} from "../ModelComponent"; +import {ItemGroup} from "./ItemGroup"; +import {ItemgroupCharacteristicValue} from "./ItemgroupCharacteristicValue"; +import {ItemGroupCharacteristic} from "./ItemgroupCharacteristic"; + +export class Item extends ModelComponent { + + + manuallyInheritedGroups: ItemGroup[] = [] + hierarchyInheritedGroups: ItemGroup[] = [] + itemCharacteristicValues: ItemgroupCharacteristicValue[] = [] + + initializeItemCharacteristics() { + const inheritedGroups = this.manuallyInheritedGroups.concat(this.hierarchyInheritedGroups); + inheritedGroups.forEach(itemGroup => { + this.initializeItemCharacteristicsOfItemgroup(itemGroup); + }) + } + + initializeItemCharacteristicsOfItemgroup(itemGroup: ItemGroup) { + itemGroup.itemGroupCharacteristics.forEach(characteristic => { + this.addCharacteristic(characteristic); + }) + } + + private isValueInitialized(characteristic: ItemGroupCharacteristic) { + return this.itemCharacteristicValues.find(value => value.key.characteristicName === characteristic.characteristicName) !== undefined + } + + addInheritedGroup(itemgroup: ItemGroup) { + if(this.findItemgroupByName(itemgroup.componentName) == undefined) { + this.manuallyInheritedGroups.push(itemgroup); + itemgroup.manuallyInheritedItems.push(this); + this.initializeItemCharacteristicsOfItemgroup(itemgroup); + } + } + + findItemgroupByName(groupName: string) { + const itemgroups = this.hierarchyInheritedGroups.concat(this.manuallyInheritedGroups); + return itemgroups.find(group => group.componentName === groupName); + } + + addCharacteristic(characteristic: ItemGroupCharacteristic) { + const characteristicValue = new ItemgroupCharacteristicValue(characteristic, 0); + if(!this.isValueInitialized(characteristic)) { + this.itemCharacteristicValues.push(characteristicValue); + } + } + + deleteInheritedGroup(itemgroup: ItemGroup) { + this.manuallyInheritedGroups = this.manuallyInheritedGroups.filter(manually => manually.componentName !== itemgroup.componentName); + } + + addInheritedHierarchyGroup(itemgroup: ItemGroup) { + this.hierarchyInheritedGroups.push(itemgroup); + this.initializeItemCharacteristicsOfItemgroup(itemgroup); + + } +} diff --git a/src/app/project/game-model/inventory/ItemGroup.ts b/src/app/project/game-model/inventory/ItemGroup.ts new file mode 100644 index 0000000..3096e7b --- /dev/null +++ b/src/app/project/game-model/inventory/ItemGroup.ts @@ -0,0 +1,35 @@ +import {ModelComponent} from "../ModelComponent"; +import {ItemGroupCharacteristic} from "./ItemgroupCharacteristic"; +import {AbstractItemGroup} from "./AbstractItemGroup"; +import {Item} from "./Item"; + +export abstract class ItemGroup extends ModelComponent { + + itemGroupCharacteristics: ItemGroupCharacteristic[] = [] + parentGroup: AbstractItemGroup | undefined + manuallyInheritedItems: Item[] = [] + + addItemgroupCharacteristic(itemgroupCharacteristic: ItemGroupCharacteristic) { + this.itemGroupCharacteristics.push(itemgroupCharacteristic); + this.addCharacteristicValueForManuallyItems(itemgroupCharacteristic); + this.addCharacteristicValue(itemgroupCharacteristic); + } + + protected abstract addCharacteristicValue(characteristic: ItemGroupCharacteristic): void; + + private addCharacteristicValueForManuallyItems(characteristic: ItemGroupCharacteristic) { + this.manuallyInheritedItems.forEach(item => { + item.addCharacteristic(characteristic); + }) + } + + inheritManualItem(item: Item) { + if(this.manuallyInheritedItems.find(inheritedItems => inheritedItems.componentName === item.componentName) == undefined) { + this.manuallyInheritedItems.push(item); + item.addInheritedGroup(this); + } + } + + + +} diff --git a/src/app/project/game-model/inventory/ItemgroupCharacteristic.ts b/src/app/project/game-model/inventory/ItemgroupCharacteristic.ts new file mode 100644 index 0000000..d28b9a1 --- /dev/null +++ b/src/app/project/game-model/inventory/ItemgroupCharacteristic.ts @@ -0,0 +1,14 @@ +import {ItemGroup} from "./ItemGroup"; + +export class ItemGroupCharacteristic { + characteristicName: string; + characteristicDescription: string + itemgroup: ItemGroup + + + constructor(characteristicName: string, characteristicDescription: string, itemgroup: ItemGroup) { + this.characteristicName = characteristicName; + this.characteristicDescription = characteristicDescription; + this.itemgroup = itemgroup; + } +} diff --git a/src/app/project/game-model/inventory/ItemgroupCharacteristicValue.ts b/src/app/project/game-model/inventory/ItemgroupCharacteristicValue.ts new file mode 100644 index 0000000..436d3b7 --- /dev/null +++ b/src/app/project/game-model/inventory/ItemgroupCharacteristicValue.ts @@ -0,0 +1,14 @@ +import {ItemGroupCharacteristic} from "./ItemgroupCharacteristic"; + +export class ItemgroupCharacteristicValue { + key: ItemGroupCharacteristic + value: number + + + constructor(key: ItemGroupCharacteristic, value: number) { + this.key = key; + this.value = value; + } + + +} diff --git a/src/app/project/game-model/inventory/ItemgroupType.ts b/src/app/project/game-model/inventory/ItemgroupType.ts new file mode 100644 index 0000000..f1ca933 --- /dev/null +++ b/src/app/project/game-model/inventory/ItemgroupType.ts @@ -0,0 +1,4 @@ +export enum ItemgroupType { + CONCRETE, + ABSTRACT +} diff --git a/src/app/project/game-model/utils/ItemgroupUtilities.ts b/src/app/project/game-model/utils/ItemgroupUtilities.ts new file mode 100644 index 0000000..25c9533 --- /dev/null +++ b/src/app/project/game-model/utils/ItemgroupUtilities.ts @@ -0,0 +1,67 @@ +import {GameModel} from "../GameModel"; +import {ItemGroup} from "../inventory/ItemGroup"; +import {AbstractItemGroup} from "../inventory/AbstractItemGroup"; +import {ConcreteItemGroup} from "../inventory/ConcreteItemGroup"; + +export class ItemgroupUtilities { + + public static findItemgroupPathToItem(searchedItemName: string, itemgroups: ItemGroup[]): ItemGroup[] { + for(let i=0; i 0) { + return found_path; + } + } + return []; + } + + public static findItemgroupPathToItemgroup(searchedItemgroupName: string, itemgroups: ItemGroup[]): ItemGroup[] { + for(let i=0; i 0) { + return found_path; + } + } + return []; + } + + private static findItemgroupPathToItemgroupRecursive(root: ItemGroup, searchedItemgroupName: string, path: ItemGroup[]): ItemGroup[] { + path.push(root); + + if(root.componentName === searchedItemgroupName) { + return path; + } + + if(root instanceof AbstractItemGroup) { + for(let i=0; i 0) { + return found_path; + } + } + return []; + } else { + return []; + } + } + + private static findItemgroupPathToItemRecursive(root: ItemGroup, searchedItemName: string, path: ItemGroup[]): ItemGroup[] { + path.push(root); + + if(root instanceof ConcreteItemGroup) { + const searchedItem = root.items.find(item => item.componentName === searchedItemName) + if(searchedItem != undefined) { + return path; + } + } else if(root instanceof AbstractItemGroup) { + for(let i=0; i 0) { + return found_path; + } + } + } + return []; + } + +} diff --git a/src/app/project/parser/itemParser/ItemParser.ts b/src/app/project/parser/itemParser/ItemParser.ts new file mode 100644 index 0000000..40da22f --- /dev/null +++ b/src/app/project/parser/itemParser/ItemParser.ts @@ -0,0 +1,87 @@ +import {ItemGroup} from "../../game-model/inventory/ItemGroup"; +import {StoreComponent} from "../../../../../app/storage/StoreComponent"; +import {Item} from "../../game-model/inventory/Item"; +import {ModelComponentType} from "../../game-model/ModelComponentType"; +import {ConcreteItemGroup} from "../../game-model/inventory/ConcreteItemGroup"; +import {ItemgroupCharacteristicValue} from "../../game-model/inventory/ItemgroupCharacteristicValue"; + +export class ItemParser { + parsedItemgroups: ItemGroup[] = [] + + constructor(itemgroups: ItemGroup[] = []) { + this.parsedItemgroups = itemgroups; + } + + parseItems(storeComponents: StoreComponent[]): Item[] { + const parsedItems: Item[] = [] + storeComponents.forEach(storeComponent => parsedItems.push(this.parseSingleItem(storeComponent))); + return parsedItems; + } + + private parseSingleItem(storeComponent: StoreComponent) { + const parsedData = JSON.parse(storeComponent.jsonString); + + const componentName = parsedData.componentName; + const componentDescription = parsedData.componentDescription; + + const manuallyInheritedGroups = this.parseInheritedGroups(parsedData.manuallyInheritedGroups); + const hierarchyInheritedGroups = this.parseInheritedGroups(parsedData.hierarchyInheritedGroups); + + const item = new Item(componentName, componentDescription, ModelComponentType.ITEM); + item.manuallyInheritedGroups = manuallyInheritedGroups; + item.hierarchyInheritedGroups = hierarchyInheritedGroups; + + const owningGroup = hierarchyInheritedGroups.find(itemgroup => itemgroup instanceof ConcreteItemGroup); + if (owningGroup) { + (owningGroup as ConcreteItemGroup).items.push(item); + } else { + console.log("[ERROR] No group found for item: ", item.componentName) + } + + + item.itemCharacteristicValues = this.parseItemCharacteristicValues(parsedData.itemCharacteristicValues); + return item; + } + + private parseInheritedGroups(inheritedGroupsData: any) { + const inheritedGroups: ItemGroup[] = [] + for(let i=0; i group.componentName === inheritedGroupName); + if (matchedGroup) { + inheritedGroups.push(matchedGroup); + } + } + + return inheritedGroups; + } + + private parseItemCharacteristicValues(data: any): ItemgroupCharacteristicValue[] { + const values: ItemgroupCharacteristicValue[] = [] + for(let i=0; i characteristic.characteristicName === itemCharacteristicName); + + if(characteristic != undefined) { + return characteristic; + } + } + return undefined; + } + + +} diff --git a/src/app/project/parser/itemParser/ItemgroupParser.ts b/src/app/project/parser/itemParser/ItemgroupParser.ts new file mode 100644 index 0000000..fb18e77 --- /dev/null +++ b/src/app/project/parser/itemParser/ItemgroupParser.ts @@ -0,0 +1,94 @@ +import {ItemGroup} from "../../game-model/inventory/ItemGroup"; +import {StoreComponent} from "../../../../../app/storage/StoreComponent"; +import {ItemGroupCharacteristic} from "../../game-model/inventory/ItemgroupCharacteristic"; +import {AbstractItemGroup} from "../../game-model/inventory/AbstractItemGroup"; +import {ModelComponentType} from "../../game-model/ModelComponentType"; +import {ConcreteItemGroup} from "../../game-model/inventory/ConcreteItemGroup"; + +export class ItemgroupParser { + + private parsedItemgroups: ItemGroup[] = [] + private topParsedItemgroups: ItemGroup[] = [] + + parseItemgroups(storeComponents: StoreComponent[]) { + const topologicalSort = this.topologicalSort(storeComponents); + topologicalSort.forEach(storeComponent => this.parseSingleItemgroup(storeComponent)); + return this.parsedItemgroups; + } + + private topologicalSort(storeComponents: StoreComponent[]) { + const sortedObjects: StoreComponent[] = [] + const visited: {[key: string]: boolean} = {}; + + const visit = (object: StoreComponent) => { + const jsonData = JSON.parse(object.jsonString) + if(visited[jsonData.componentName]) return; + visited[jsonData.componentName] = true; + + if(jsonData.parent) { + const parentObject = storeComponents.find(obj => JSON.parse(obj.jsonString).componentName === jsonData.parent); + if(parentObject) { + visit(parentObject); + } + } + sortedObjects.push(object); + } + + storeComponents.forEach(object => visit(object)); + + return sortedObjects; + } + + parseSingleItemgroup(storeComponent: StoreComponent) { + const data = JSON.parse(storeComponent.jsonString); + + const componentName = data.componentName; + const componentDescription = data.componentDescription; + const parentgroupName = data.parentgroup; + + let itemgroup; + if(data.itemgroupType == 0) { + itemgroup = new ConcreteItemGroup(componentName, componentDescription, ModelComponentType.ITEMGROUP); + } else { + itemgroup = new AbstractItemGroup(componentName, componentDescription, ModelComponentType.ITEMGROUP); + } + + const parentgroup = this.parsedItemgroups.find(parent => parent.componentName === parentgroupName); + + if(parentgroup != undefined) { + const abstractParentgroup = parentgroup as AbstractItemGroup; + abstractParentgroup.addChildItemgroup(itemgroup) + this.parsedItemgroups.push(itemgroup) + } else { + this.parsedItemgroups.push(itemgroup); + this.topParsedItemgroups.push(itemgroup); + } + + this.parseItemgroupCharacteristics(data.itemGroupCharacteristics, itemgroup); + } + + parseItemgroupCharacteristics(itemgroupCharacteristicsData: any, itemgroup: ItemGroup): ItemGroupCharacteristic[] { + const itemgroupCharacteristics: ItemGroupCharacteristic[] = [] + for(let i=0; i { if(this.IGNORED_SIMPLE_ATTRIBUTES.includes(key)) { diff --git a/src/app/project/serializer/ItemSerializer.ts b/src/app/project/serializer/ItemSerializer.ts new file mode 100644 index 0000000..80d51bf --- /dev/null +++ b/src/app/project/serializer/ItemSerializer.ts @@ -0,0 +1,135 @@ +import {ItemGroup} from "../game-model/inventory/ItemGroup"; +import {StoreComponent} from "../../../../app/storage/StoreComponent"; +import {AbstractItemGroup} from "../game-model/inventory/AbstractItemGroup"; +import {ConcreteItemGroup} from "../game-model/inventory/ConcreteItemGroup"; +import {ModelComponentType} from "../game-model/ModelComponentType"; +import {SerializeConstants} from "./SerializeConstants"; +import {Item} from "../game-model/inventory/Item"; +import {ItemgroupType} from "../game-model/inventory/ItemgroupType"; + +export class ItemSerializer { + + private serializedItemgroups: StoreComponent[] = [] + private serializedItems: StoreComponent[] = [] + private static ignoredGroupKeys: string[] = ['type', 'unsaved', "itemgroup", "manuallyInheritedGroups", "hierarchyInheritedGroups", "items"] + private static ignoredItemKeys: string[] = ['type', 'unsaved'] + + public serializeItemgroups(itemgroups: ItemGroup[]): StoreComponent[] { + itemgroups.forEach(itemgroup => { + this.serializeSingleItemgroupHierarchy(itemgroup) + }) + return this.serializedItemgroups; + } + + private serializeSingleItemgroupHierarchy(itemgroup: ItemGroup) { + if(itemgroup instanceof AbstractItemGroup) { + const storeComponent = this.serializeAbstractItemgroup(itemgroup) + this.serializedItemgroups.push(storeComponent) + itemgroup.children.forEach(child => this.serializeSingleItemgroupHierarchy(child)); + } else { + const storeComponent = this.serializeConcreteItemgroup(itemgroup as ConcreteItemGroup); + this.serializedItemgroups.push(storeComponent) + + this.serializeItemsOfItemgroup(itemgroup as ConcreteItemGroup); + } + } + + private serializeAbstractItemgroup(itemgroup: AbstractItemGroup): StoreComponent { + const componentType = ModelComponentType.ITEMGROUP; + const fileName = ItemSerializer.computeItemgroupPath(itemgroup); + + const jsonObject = { + componentName: itemgroup.componentName, + componentDescription: itemgroup.componentDescription, + itemGroupCharacteristics: itemgroup.itemGroupCharacteristics.map(characteristic => { + return { + characteristicName: characteristic.characteristicName, + characteristicDescription: characteristic.characteristicDescription + } + }), + parentgroup: itemgroup.parentGroup, + itemgroupType: ItemgroupType.ABSTRACT + }; + + const jsonString = JSON.stringify(jsonObject, (key, value) => { + return value; + }, SerializeConstants.JSON_INDENT); + return new StoreComponent(jsonString, fileName, componentType) + } + + private serializeConcreteItemgroup(itemgroup: ConcreteItemGroup) { + const componentType = ModelComponentType.ITEMGROUP; + const fileName = ItemSerializer.computeItemgroupPath(itemgroup); + + const jsonObject = { + componentName: itemgroup.componentName, + componentDescription: itemgroup.componentDescription, + itemGroupCharacteristics: itemgroup.itemGroupCharacteristics.map(characteristic => { + return { + characteristicName: characteristic.characteristicName, + characteristicDescription: characteristic.characteristicDescription + } + }), + itemgroupType: ItemgroupType.CONCRETE, + parentgroup: itemgroup.parentGroup?.componentName + }; + + const jsonString = JSON.stringify(jsonObject, (key, value) => { + return value; + }, SerializeConstants.JSON_INDENT); + return new StoreComponent(jsonString, fileName, componentType) + } + + private static computeItemgroupPath(itemgroup: ItemGroup, itemPath: boolean = false): string { + const itemgroupPath: string[] = []; + itemgroupPath.push(itemgroup.componentName); + + if(!itemPath) { + itemgroupPath.push(itemgroup.componentName); + } + + + while(itemgroup.parentGroup !== undefined) { + itemgroupPath.unshift(itemgroup.parentGroup.componentName); + itemgroup = itemgroup.parentGroup; + } + + return itemgroupPath.join("/"); + } + + private serializeItemsOfItemgroup(itemgroup: ConcreteItemGroup) { + const fileName = ItemSerializer.computeItemgroupPath(itemgroup, true); + itemgroup.items.forEach(item => { + const storeComponent = this.serializeSingleItem(fileName, item); + this.serializedItems.push(storeComponent) + }) + + + } + + private serializeSingleItem(itemgroupPath: string, item: Item) { + const itemFile = itemgroupPath + "/" + item.componentName; + + const jsonString = JSON.stringify(item, (key, value) => { + if(ItemSerializer.ignoredItemKeys.includes(key)) { + return undefined + } + + if(value instanceof ItemGroup) { + return value.componentName + } + + if(key == "key") { + return value.characteristicName + } + + return value; + }, SerializeConstants.JSON_INDENT) + + return new StoreComponent(jsonString, itemFile, ModelComponentType.ITEM) + } + + getSerializedItems() { + return this.serializedItems; + } +} diff --git a/src/app/shared/Tupel.ts b/src/app/shared/Tupel.ts new file mode 100644 index 0000000..e05b237 --- /dev/null +++ b/src/app/shared/Tupel.ts @@ -0,0 +1,10 @@ +export class Tupel { + value00: A + value01: B + + + constructor(value00: A, value01: B) { + this.value00 = value00; + this.value01 = value01; + } +} diff --git a/src/app/side-overviews/item-overview/item-overview.component.html b/src/app/side-overviews/item-overview/item-overview.component.html new file mode 100644 index 0000000..2622561 --- /dev/null +++ b/src/app/side-overviews/item-overview/item-overview.component.html @@ -0,0 +1,22 @@ + + + + + + folder + data_object + {{node.name}} + + + + + folder + data_object + {{node.name}} + + diff --git a/src/app/side-overviews/item-overview/item-overview.component.scss b/src/app/side-overviews/item-overview/item-overview.component.scss new file mode 100644 index 0000000..d799155 --- /dev/null +++ b/src/app/side-overviews/item-overview/item-overview.component.scss @@ -0,0 +1,41 @@ +.mat-tree-node { + min-height: 1.8em !important; + height: 1.8em; +} + + +.small-icon-button { + width: 26px !important; + height: 26px !important; + padding: 0px !important; + display: inline-flex !important; + align-items: center; + justify-content: center; + margin-left: 5px; + margin-right: 5px; + margin-bottom: 2px; + + & > *[role=img] { + width: 18px; + height: 18px; + font-size: 18px; + + svg { + width: 18px; + height: 18px; + } + } + + .mat-mdc-button-touch-target { + width: 22px !important; + height: 22px !important; + } +} + +.small-icon-button mat-icon { + color: whitesmoke; +} + +.selected-node { + background-color: #545456 +} diff --git a/src/app/side-overviews/item-overview/item-overview.component.spec.ts b/src/app/side-overviews/item-overview/item-overview.component.spec.ts new file mode 100644 index 0000000..58c2547 --- /dev/null +++ b/src/app/side-overviews/item-overview/item-overview.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemOverviewComponent } from './item-overview.component'; + +describe('ItemOverviewComponent', () => { + let component: ItemOverviewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ItemOverviewComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ItemOverviewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/side-overviews/item-overview/item-overview.component.ts b/src/app/side-overviews/item-overview/item-overview.component.ts new file mode 100644 index 0000000..3ae9aa0 --- /dev/null +++ b/src/app/side-overviews/item-overview/item-overview.component.ts @@ -0,0 +1,123 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {GameModel} from "../../project/game-model/GameModel"; +import {FlatTreeControl} from "@angular/cdk/tree"; +import {MatTreeFlatDataSource, MatTreeFlattener} from "@angular/material/tree"; +import {AbstractItemGroup} from "../../project/game-model/inventory/AbstractItemGroup"; +import {ConcreteItemGroup} from "../../project/game-model/inventory/ConcreteItemGroup"; +import {ModelComponent} from "../../project/game-model/ModelComponent"; +import {ModelComponentType} from "../../project/game-model/ModelComponentType"; +import {ItemGroup} from "../../project/game-model/inventory/ItemGroup"; +import {Item} from "../../project/game-model/inventory/Item"; + +interface FlatNode { + expandable: boolean, + name: string, + level: number, + type: ModelComponentType +} + +@Component({ + selector: 'app-item-overview', + templateUrl: './item-overview.component.html', + styleUrl: './item-overview.component.scss' +}) +export class ItemOverviewComponent implements OnInit{ + + @Input() gameModel: GameModel | undefined + @Output() openItemgroupEmitter: EventEmitter = new EventEmitter(); + @Output() onOpenItemEditor: EventEmitter = new EventEmitter(); + + private _transformer = (node: ModelComponent, level: number) => { + if(node instanceof AbstractItemGroup) { + return { + expandable: !!node.children && node.children.length > 0, + name: node.componentName, + level: level, + type: ModelComponentType.ITEMGROUP, + }; + } else if(node instanceof ConcreteItemGroup) { + return { + expandable: !!node.items && node.items.length > 0, + name: node.componentName, + level: level, + type: ModelComponentType.ITEMGROUP, + } + } else { + return { + expandable: false, + name: node.componentName, + level: level, + type: ModelComponentType.ITEM + } + } + }; + + + treeControl = new FlatTreeControl( + node => node.level, + node => node.expandable, + ); + + treeFlattener = new MatTreeFlattener( + this._transformer, + node => node.level, + node => node.expandable, + node => this.getNodeChildren(node) + ); + + dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); + selectedItem: FlatNode | undefined + + hasChild = (_: number, node: FlatNode) => node.expandable; + + getNodeChildren(node: ModelComponent): ModelComponent[] { + if(node instanceof ConcreteItemGroup) { + return node.items; + } else if(node instanceof AbstractItemGroup) { + return node.children; + } else { + return []; + } + } + + ngOnInit() { + this.dataSource.data = this.gameModel!.itemgroups; + } + + protected readonly ModelComponentType = ModelComponentType; + + onSelectItem(node: FlatNode) { + this.selectedItem = node; + } + + openItemEditor(node: FlatNode) { + if(node.type == ModelComponentType.ITEMGROUP) { + const itemGroup = GameModel.findItemgroupByName(node.name, this.gameModel!.itemgroups); + if(itemGroup) { + this.openItemgroupEmitter.emit(itemGroup); + } + } else if(node.type == ModelComponentType.ITEM) { + const item = this.searchItemByName(node.name); + if(item !== undefined) { + this.onOpenItemEditor.emit(item); + } + } + } + + private searchItemByName(itemName: string): Item | undefined { + let groupQueue: ItemGroup[] = this.gameModel!.itemgroups.concat(); + while(groupQueue.length > 0) { + const currentGroup = groupQueue.shift()!; + + if(currentGroup instanceof AbstractItemGroup) { + groupQueue = groupQueue.concat(currentGroup.children); + } else if(currentGroup instanceof ConcreteItemGroup) { + const searchResult = currentGroup.items.find(item => item.componentName === itemName); + if(searchResult != undefined) { + return searchResult; + } + } + } + return undefined; + } +} diff --git a/testModel/items/Clothing/Clothing.json b/testModel/items/Clothing/Clothing.json new file mode 100644 index 0000000..af1c0a1 --- /dev/null +++ b/testModel/items/Clothing/Clothing.json @@ -0,0 +1,11 @@ +{ + "componentName": "Clothing", + "componentDescription": "", + "itemGroupCharacteristics": [ + { + "characteristicName": "Test0", + "characteristicDescription": "" + } + ], + "itemgroupType": 1 +} \ No newline at end of file diff --git a/testModel/items/Clothing/Hose/Hose 1.json b/testModel/items/Clothing/Hose/Hose 1.json new file mode 100644 index 0000000..e2f14c9 --- /dev/null +++ b/testModel/items/Clothing/Hose/Hose 1.json @@ -0,0 +1,17 @@ +{ + "componentName": "Hose 1", + "componentDescription": "", + "manuallyInheritedGroups": [ + "Inventory" + ], + "hierarchyInheritedGroups": [ + "Clothing", + "Hose" + ], + "itemCharacteristicValues": [ + { + "key": "Test0", + "value": 0 + } + ] +} \ No newline at end of file diff --git a/testModel/items/Clothing/Hose/Hose 2.json b/testModel/items/Clothing/Hose/Hose 2.json new file mode 100644 index 0000000..50ef84c --- /dev/null +++ b/testModel/items/Clothing/Hose/Hose 2.json @@ -0,0 +1,15 @@ +{ + "componentName": "Hose 2", + "componentDescription": "", + "manuallyInheritedGroups": [], + "hierarchyInheritedGroups": [ + "Clothing", + "Hose" + ], + "itemCharacteristicValues": [ + { + "key": "Test0", + "value": 0 + } + ] +} \ No newline at end of file diff --git a/testModel/items/Clothing/Hose/Hose.json b/testModel/items/Clothing/Hose/Hose.json new file mode 100644 index 0000000..241268e --- /dev/null +++ b/testModel/items/Clothing/Hose/Hose.json @@ -0,0 +1,7 @@ +{ + "componentName": "Hose", + "componentDescription": "", + "itemGroupCharacteristics": [], + "itemgroupType": 0, + "parentgroup": "Clothing" +} \ No newline at end of file diff --git a/testModel/items/Clothing/Oberteil/Oberteil.json b/testModel/items/Clothing/Oberteil/Oberteil.json new file mode 100644 index 0000000..1079ae4 --- /dev/null +++ b/testModel/items/Clothing/Oberteil/Oberteil.json @@ -0,0 +1,7 @@ +{ + "componentName": "Oberteil", + "componentDescription": "", + "itemGroupCharacteristics": [], + "itemgroupType": 0, + "parentgroup": "Clothing" +} \ No newline at end of file diff --git a/testModel/items/Inventory/Inventory.json b/testModel/items/Inventory/Inventory.json new file mode 100644 index 0000000..27b2fe9 --- /dev/null +++ b/testModel/items/Inventory/Inventory.json @@ -0,0 +1,11 @@ +{ + "componentName": "Inventory", + "componentDescription": "", + "itemGroupCharacteristics": [ + { + "characteristicName": "Test0", + "characteristicDescription": "" + } + ], + "itemgroupType": 1 +} \ No newline at end of file