Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 92970f1cbe | |||
| ee42245ebb | |||
| dfc702992b | |||
| 6307780b9c | |||
| d48f5a19a9 | |||
| 1b4e34a4ce | |||
| 8cf7cb66de | |||
| 4b222948ba | |||
| df52d2ae92 |
94 changed files with 208771 additions and 9 deletions
49
.gitignore
vendored
49
.gitignore
vendored
|
|
@ -1,3 +1,46 @@
|
||||||
# Include your project-specific ignores in this file
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
# Read about how to use .gitignore: https://help.github.com/articles/ignoring-files
|
|
||||||
# Useful .gitignore templates: https://github.com/github/gitignore
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
|
||||||
2
.idea/dictionaries/Tom.xml
generated
2
.idea/dictionaries/Tom.xml
generated
|
|
@ -2,6 +2,8 @@
|
||||||
<dictionary name="Tom">
|
<dictionary name="Tom">
|
||||||
<words>
|
<words>
|
||||||
<w>deparse</w>
|
<w>deparse</w>
|
||||||
|
<w>gameplay</w>
|
||||||
|
<w>pegjs</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
<module type="WEB_MODULE" version="4">
|
<module type="WEB_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="jquery-3.4.1" level="application" />
|
<orderEntry type="library" name="jquery-3.4.1" level="application" />
|
||||||
<orderEntry type="library" name="popper" level="application" />
|
<orderEntry type="library" name="popper" level="application" />
|
||||||
|
|
|
||||||
27
README.md
Normal file
27
README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# AtlasConfigGenerator
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.12.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||||
134
angular.json
Normal file
134
angular.json
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"atlas-config-generator": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/atlas-config-generator",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"aot": false,
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets",
|
||||||
|
{ "glob": "worker-javascript.js", "input": "./node_modules/ace-builds/src-min/", "output": "/" },
|
||||||
|
{ "glob": "worker-css.js", "input": "./node_modules/ace-builds/src-min/", "output": "/" },
|
||||||
|
{ "glob": "worker-json.js", "input": "./node_modules/ace-builds/src-min/", "output": "/" }
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "6kb",
|
||||||
|
"maximumError": "10kb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "atlas-config-generator:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "atlas-config-generator:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "atlas-config-generator:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"karmaConfig": "karma.conf.js",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"tsconfig.app.json",
|
||||||
|
"tsconfig.spec.json",
|
||||||
|
"e2e/tsconfig.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "atlas-config-generator:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "atlas-config-generator:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "atlas-config-generator",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
browserslist
Normal file
12
browserslist
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
|
||||||
|
# You can see what browsers were selected by your queries by running:
|
||||||
|
# npx browserslist
|
||||||
|
|
||||||
|
> 0.5%
|
||||||
|
last 2 versions
|
||||||
|
Firefox ESR
|
||||||
|
not dead
|
||||||
|
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||||
32
e2e/protractor.conf.js
Normal file
32
e2e/protractor.conf.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// @ts-check
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type { import("protractor").Config }
|
||||||
|
*/
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./src/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
browserName: 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: require('path').join(__dirname, './tsconfig.json')
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||||
|
}
|
||||||
|
};
|
||||||
23
e2e/src/app.e2e-spec.ts
Normal file
23
e2e/src/app.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { AppPage } from './app.po';
|
||||||
|
import { browser, logging } from 'protractor';
|
||||||
|
|
||||||
|
describe('workspace-project App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', () => {
|
||||||
|
page.navigateTo();
|
||||||
|
expect(page.getTitleText()).toEqual('atlas-config-generator app is running!');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Assert that there are no errors emitted from the browser
|
||||||
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
|
expect(logs).not.toContain(jasmine.objectContaining({
|
||||||
|
level: logging.Level.SEVERE,
|
||||||
|
} as logging.Entry));
|
||||||
|
});
|
||||||
|
});
|
||||||
11
e2e/src/app.po.ts
Normal file
11
e2e/src/app.po.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
navigateTo() {
|
||||||
|
return browser.get(browser.baseUrl) as Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitleText() {
|
||||||
|
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
e2e/tsconfig.json
Normal file
13
e2e/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/e2e",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1986,7 +1986,7 @@
|
||||||
<button class="close" data-bind="click: cancelDeparseEdit">×</button>
|
<button class="close" data-bind="click: cancelDeparseEdit">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>JSON! Its all JSON. Only magical ones are the 'BlueprintGeneratedClass' and 'SoundWave' items - these
|
<p>JSON! Its all JSON. Only magical ones are the 'BlueprintGeneratedClassModel' and 'SoundWave' items - these
|
||||||
appear as an array of two items, the 'class' name and the argument for them.</p>
|
appear as an array of two items, the 'class' name and the argument for them.</p>
|
||||||
<div id="deparse-editor"></div>
|
<div id="deparse-editor"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ ws "whitespace" = [ \t\n\r]*
|
||||||
value = false / null / true / object / array / number / stringval / class / empty
|
value = false / null / true / object / array / number / stringval / class / empty
|
||||||
|
|
||||||
empty = "" { return undefined; }
|
empty = "" { return undefined; }
|
||||||
null = "None" / "none" { return null; }
|
null = "None" { return null; }
|
||||||
false = "False" / "false" { return false; }
|
false = "False" { return false; }
|
||||||
true = "True" / "true" { return true; }
|
true = "True" { return true; }
|
||||||
|
|
||||||
// ----- Objects -----
|
// ----- Objects -----
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ function deparseArray(input) {
|
||||||
function deparseNumber(input, key) {
|
function deparseNumber(input, key) {
|
||||||
// Any number which has a decimal is stored to 6 decimal places
|
// Any number which has a decimal is stored to 6 decimal places
|
||||||
// Except for IDs. Unless they actually have such a number... erm...
|
// Except for IDs. Unless they actually have such a number... erm...
|
||||||
if (key && key.substr(key.length - 2, 2) === "ID") {
|
if (key.substr(key.length - 2, 2) === "ID") {
|
||||||
if (input % 1 === 0) {
|
if (input % 1 === 0) {
|
||||||
return Number(input).toString();
|
return Number(input).toString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
karma.conf.js
Normal file
32
karma.conf.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, './coverage/atlas-config-generator'),
|
||||||
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
||||||
13150
package-lock.json
generated
Normal file
13150
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
52
package.json
Normal file
52
package.json
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"name": "atlas-config-generator",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "~8.2.11",
|
||||||
|
"@angular/common": "~8.2.11",
|
||||||
|
"@angular/compiler": "~8.2.11",
|
||||||
|
"@angular/core": "~8.2.11",
|
||||||
|
"@angular/forms": "~8.2.11",
|
||||||
|
"@angular/platform-browser": "~8.2.11",
|
||||||
|
"@angular/platform-browser-dynamic": "~8.2.11",
|
||||||
|
"@angular/router": "~8.2.11",
|
||||||
|
"@ng-bootstrap/ng-bootstrap": "^5.1.1",
|
||||||
|
"@types/pegjs": "^0.10.1",
|
||||||
|
"ace-builds": "^1.4.7",
|
||||||
|
"bootstrap": "^4.3.1",
|
||||||
|
"rxjs": "~6.4.0",
|
||||||
|
"ts-pegjs": "^0.2.6",
|
||||||
|
"tslib": "^1.10.0",
|
||||||
|
"zone.js": "~0.9.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "~0.803.12",
|
||||||
|
"@angular/cli": "~8.3.12",
|
||||||
|
"@angular/compiler-cli": "~8.2.11",
|
||||||
|
"@angular/language-service": "~8.2.11",
|
||||||
|
"@types/node": "~8.9.4",
|
||||||
|
"@types/jasmine": "~3.3.8",
|
||||||
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
"codelyzer": "^5.0.0",
|
||||||
|
"jasmine-core": "~3.4.0",
|
||||||
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
|
"karma": "~4.1.0",
|
||||||
|
"karma-chrome-launcher": "~2.2.0",
|
||||||
|
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||||
|
"karma-jasmine": "~2.0.1",
|
||||||
|
"karma-jasmine-html-reporter": "^1.4.0",
|
||||||
|
"protractor": "~5.4.0",
|
||||||
|
"ts-node": "~7.0.0",
|
||||||
|
"tslint": "~5.15.0",
|
||||||
|
"typescript": "~3.5.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/app/app-routing.module.ts
Normal file
33
src/app/app-routing.module.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { RawEditorComponent } from "./pages/raw-editor/raw-editor.component";
|
||||||
|
import { ConfigComponent } from "./pages/config/config.component";
|
||||||
|
import { QuestsComponent } from "./pages/config/quests/quests.component";
|
||||||
|
import { GridComponent } from "./pages/config/grid/grid.component";
|
||||||
|
import { DbsComponent } from "./pages/config/dbs/dbs.component";
|
||||||
|
import { ServersComponent } from "./pages/config/servers/servers.component";
|
||||||
|
import { ServerComponent } from "./pages/config/servers/server/server.component";
|
||||||
|
import { IslandInstanceComponent } from "./pages/config/servers/island-instance/island-instance.component";
|
||||||
|
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{path: 'raw', component: RawEditorComponent},
|
||||||
|
{
|
||||||
|
path: 'config', component: ConfigComponent, children: [
|
||||||
|
{path: '', redirectTo: 'grid', pathMatch: 'full'},
|
||||||
|
{path: 'grid', component: GridComponent},
|
||||||
|
{path: 'dbs', component: DbsComponent},
|
||||||
|
{path: 'quests', component: QuestsComponent},
|
||||||
|
{path: 'servers', component: ServersComponent},
|
||||||
|
{path: 'server/:index', component: ServerComponent},
|
||||||
|
{path: 'server/:index/island/:islandIndex', component: IslandInstanceComponent}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule {
|
||||||
|
}
|
||||||
23
src/app/app.component.html
Normal file
23
src/app/app.component.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="#">Atlas Config</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTop">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarTop">
|
||||||
|
<ul class="navbar-nav ml-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" routerLink="/raw" routerLinkActive="active">Raw</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" routerLink="/config" routerLinkActive="active">Config</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
0
src/app/app.component.scss
Normal file
0
src/app/app.component.scss
Normal file
19
src/app/app.component.ts
Normal file
19
src/app/app.component.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Server } from "./server";
|
||||||
|
import { ServerGridModel } from "./models/serverGrid.model";
|
||||||
|
import * as data from '../serverGridExample.json';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
title = 'atlas-config-generator';
|
||||||
|
|
||||||
|
constructor(private server: Server) {
|
||||||
|
// Temporary just load all the grid. Remove later.
|
||||||
|
this.server.serverGrid = new ServerGridModel().deserialize((data as any).default);
|
||||||
|
console.log(this.server.serverGrid);
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/app/app.module.ts
Normal file
57
src/app/app.module.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { RawEditorComponent } from "./pages/raw-editor/raw-editor.component";
|
||||||
|
import { CodeEditorComponent } from './components/code-editor/code-editor.component';
|
||||||
|
import { ConfigComponent } from './pages/config/config.component';
|
||||||
|
import { FormsModule } from "@angular/forms";
|
||||||
|
import { Server } from "./server";
|
||||||
|
import { PegjsService } from "./services/pegjs.service";
|
||||||
|
import { QuestsComponent } from './pages/config/quests/quests.component';
|
||||||
|
import { GridComponent } from './pages/config/grid/grid.component';
|
||||||
|
import { NumberComponent } from './components/form/number/number.component';
|
||||||
|
import { TextComponent } from './components/form/text/text.component';
|
||||||
|
import { PasswordComponent } from './components/form/password/password.component';
|
||||||
|
import { DbsComponent } from './pages/config/dbs/dbs.component';
|
||||||
|
import { CheckboxComponent } from './components/form/checkbox/checkbox.component';
|
||||||
|
import { ServersComponent } from './pages/config/servers/servers.component';
|
||||||
|
import { ServerComponent } from './pages/config/servers/server/server.component';
|
||||||
|
import { TemplateComponent } from './pages/config/servers/template/template.component';
|
||||||
|
import { SelectListComponent } from './components/form/select-list/select-list.component';
|
||||||
|
import { SelectObjectComponent } from './components/form/select-object/select-object.component';
|
||||||
|
import { IslandInstanceComponent } from './pages/config/servers/island-instance/island-instance.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
RawEditorComponent,
|
||||||
|
CodeEditorComponent,
|
||||||
|
ConfigComponent,
|
||||||
|
QuestsComponent,
|
||||||
|
GridComponent,
|
||||||
|
NumberComponent,
|
||||||
|
TextComponent,
|
||||||
|
PasswordComponent,
|
||||||
|
DbsComponent,
|
||||||
|
CheckboxComponent,
|
||||||
|
ServersComponent,
|
||||||
|
ServerComponent,
|
||||||
|
TemplateComponent,
|
||||||
|
SelectListComponent,
|
||||||
|
SelectObjectComponent,
|
||||||
|
IslandInstanceComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
NgbModule,
|
||||||
|
FormsModule
|
||||||
|
],
|
||||||
|
providers: [Server, PegjsService],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<div class="code-editor" #codeEditor></div>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
25
src/app/components/code-editor/code-editor.component.spec.ts
Normal file
25
src/app/components/code-editor/code-editor.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CodeEditorComponent } from './code-editor.component';
|
||||||
|
|
||||||
|
describe('CodeEditorComponent', () => {
|
||||||
|
let component: CodeEditorComponent;
|
||||||
|
let fixture: ComponentFixture<CodeEditorComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ CodeEditorComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CodeEditorComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
62
src/app/components/code-editor/code-editor.component.ts
Normal file
62
src/app/components/code-editor/code-editor.component.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||||
|
|
||||||
|
import * as ace from 'ace-builds';
|
||||||
|
|
||||||
|
import 'ace-builds/src-noconflict/mode-json';
|
||||||
|
import 'ace-builds/src-noconflict/theme-monokai';
|
||||||
|
import 'ace-builds/src-noconflict/ext-language_tools';
|
||||||
|
import 'ace-builds/src-noconflict/ext-beautify';
|
||||||
|
|
||||||
|
const THEME = 'ace/theme/monokai';
|
||||||
|
const LANG = 'ace/mode/json';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'code-editor',
|
||||||
|
templateUrl: './code-editor.component.html',
|
||||||
|
styleUrls: ['./code-editor.component.scss']
|
||||||
|
})
|
||||||
|
export class CodeEditorComponent implements OnInit {
|
||||||
|
|
||||||
|
private codeEditor: ace.Ace.Editor;
|
||||||
|
@ViewChild('codeEditor', {static: true}) private codeEditorElmRef: ElementRef;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
ace.require('ace/ext/language_tools');
|
||||||
|
const element = this.codeEditorElmRef.nativeElement;
|
||||||
|
const editorOptions = CodeEditorComponent.getEditorOptions();
|
||||||
|
this.codeEditor = ace.edit(element, editorOptions);
|
||||||
|
this.codeEditor.setTheme(THEME);
|
||||||
|
this.codeEditor.getSession().setMode(LANG);
|
||||||
|
this.codeEditor.setShowFoldWidgets(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// missing property on EditorOptions 'enableBasicAutocompletion' so this is a workaround still using ts
|
||||||
|
private static getEditorOptions(): Partial<ace.Ace.EditorOptions> & { enableBasicAutocompletion?: boolean; } {
|
||||||
|
const basicEditorOptions: Partial<ace.Ace.EditorOptions> = {
|
||||||
|
highlightActiveLine: true,
|
||||||
|
minLines: 14,
|
||||||
|
maxLines: Infinity,
|
||||||
|
};
|
||||||
|
const extraEditorOptions = {enableBasicAutocompletion: true};
|
||||||
|
return Object.assign(basicEditorOptions, extraEditorOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns - the current editor's content.
|
||||||
|
*/
|
||||||
|
public getContent() {
|
||||||
|
if (this.codeEditor) {
|
||||||
|
return this.codeEditor.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setContent(text) {
|
||||||
|
if (this.codeEditor) {
|
||||||
|
this.codeEditor.setValue(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
7
src/app/components/form/checkbox/checkbox.component.html
Normal file
7
src/app/components/form/checkbox/checkbox.component.html
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="check-{{ id }}" class="col-2">{{ label }}</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<input id="check-{{ id }}" type="checkbox" class="form-control" (ngModelChange)="checkboxChange.emit($event)" [ngModel]="checkbox">
|
||||||
|
<small class="form-text text-muted" *ngIf="help">{{ help }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
19
src/app/components/form/checkbox/checkbox.component.ts
Normal file
19
src/app/components/form/checkbox/checkbox.component.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-checkbox',
|
||||||
|
templateUrl: './checkbox.component.html'
|
||||||
|
})
|
||||||
|
export class CheckboxComponent implements OnInit {
|
||||||
|
@Input() checkbox: boolean;
|
||||||
|
@Output() checkboxChange = new EventEmitter();
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() id: string;
|
||||||
|
@Input() help: string;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
src/app/components/form/number/number.component.html
Normal file
13
src/app/components/form/number/number.component.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="num-{{ id }}" class="col-2">{{ label }}</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="num-{{ id }}" type="number" class="form-control" (ngModelChange)="numberChange.emit($event)"
|
||||||
|
[ngModel]="number" min="{{ min }}" max="{{ max }}" step="{{ step }}">
|
||||||
|
<div class="input-group-append" *ngIf="postButtonText">
|
||||||
|
<button class="btn btn-outline-primary" (click)="postButton.emit($event)">{{ postButtonText }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<small class="form-text text-muted" *ngIf="help">{{ help }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
24
src/app/components/form/number/number.component.ts
Normal file
24
src/app/components/form/number/number.component.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-number',
|
||||||
|
templateUrl: './number.component.html'
|
||||||
|
})
|
||||||
|
export class NumberComponent implements OnInit {
|
||||||
|
@Input() number: number;
|
||||||
|
@Output() numberChange = new EventEmitter();
|
||||||
|
@Input() postButtonText: string;
|
||||||
|
@Output() postButton = new EventEmitter();
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() id: string;
|
||||||
|
@Input() help: string;
|
||||||
|
@Input() min: number;
|
||||||
|
@Input() max: number;
|
||||||
|
@Input() step: number;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
src/app/components/form/password/password.component.html
Normal file
13
src/app/components/form/password/password.component.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="text-{{ id }}" class="col-2">{{ label }}</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="text-{{ id }}" type="{{ show ? 'text' : 'password' }}" class="form-control"
|
||||||
|
(ngModelChange)="passwordChange.emit($event)" [ngModel]="password">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-warning" (click)="toggleShow()">{{ show ? 'Hide' : 'Show' }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<small class="form-text text-muted" *ngIf="help">{{ help }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
23
src/app/components/form/password/password.component.ts
Normal file
23
src/app/components/form/password/password.component.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-password',
|
||||||
|
templateUrl: './password.component.html'
|
||||||
|
})
|
||||||
|
export class PasswordComponent implements OnInit {
|
||||||
|
@Input() password: string;
|
||||||
|
@Output() passwordChange = new EventEmitter();
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() id: string;
|
||||||
|
@Input() help: string;
|
||||||
|
private show: boolean = false;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
private toggleShow() {
|
||||||
|
this.show = !this.show;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="select-{{ id }}" class="col-2">{{ label }}</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<select id="select-{{ id }}" class="form-control" (ngModelChange)="optionChange.emit($event)" [ngModel]="option">
|
||||||
|
<option *ngIf="withEmptyOption" value=""></option>
|
||||||
|
<option *ngFor="let option of optionList" value="{{ option }}">{{ option }}</option>
|
||||||
|
</select>
|
||||||
|
<small class="form-text text-muted" *ngIf="help">{{ help }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
21
src/app/components/form/select-list/select-list.component.ts
Normal file
21
src/app/components/form/select-list/select-list.component.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-select-list',
|
||||||
|
templateUrl: './select-list.component.html'
|
||||||
|
})
|
||||||
|
export class SelectListComponent implements OnInit {
|
||||||
|
@Input() withEmptyOption: boolean = false;
|
||||||
|
@Input() optionList: any[];
|
||||||
|
@Input() option: any;
|
||||||
|
@Output() optionChange = new EventEmitter();
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() id: string;
|
||||||
|
@Input() help: string;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="select-{{ id }}" class="col-2">{{ label }}</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<select id="select-{{ id }}" class="form-control" (ngModelChange)="optionChange.emit($event)" [ngModel]="option">
|
||||||
|
<option *ngIf="withEmptyOption" value=""></option>
|
||||||
|
<option *ngFor="let option of optionObject | keyvalue" value="{{ option.key }}">{{ option.value }}</option>
|
||||||
|
</select>
|
||||||
|
<small class="form-text text-muted" *ngIf="help">{{ help }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-select-object',
|
||||||
|
templateUrl: './select-object.component.html'
|
||||||
|
})
|
||||||
|
export class SelectObjectComponent implements OnInit {
|
||||||
|
@Input() withEmptyOption: boolean = false;
|
||||||
|
@Input() optionObject: object;
|
||||||
|
@Input() option: any;
|
||||||
|
@Output() optionChange = new EventEmitter();
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() id: string;
|
||||||
|
@Input() help: string;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
src/app/components/form/text/text.component.html
Normal file
12
src/app/components/form/text/text.component.html
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="text-{{ id }}" class="col-2">{{ label }}</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="text-{{ id }}" type="text" class="form-control" (ngModelChange)="textChange.emit($event)" [ngModel]="text">
|
||||||
|
<div class="input-group-append" *ngIf="postButtonText">
|
||||||
|
<button class="btn btn-outline-primary" (click)="postButton.emit($event)">{{ postButtonText || "click me" }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<small class="form-text text-muted" *ngIf="help">{{ help }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
20
src/app/components/form/text/text.component.ts
Normal file
20
src/app/components/form/text/text.component.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-text',
|
||||||
|
templateUrl: './text.component.html'
|
||||||
|
})
|
||||||
|
export class TextComponent implements OnInit {
|
||||||
|
@Input() text: string;
|
||||||
|
@Output() textChange = new EventEmitter();
|
||||||
|
@Input() postButtonText: string;
|
||||||
|
@Output() postButton = new EventEmitter();
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() id: string;
|
||||||
|
@Input() help: string;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/app/models/abstract/baseConfig.model.ts
Normal file
11
src/app/models/abstract/baseConfig.model.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
export abstract class BaseConfig {
|
||||||
|
public BackupMode: string = "off";
|
||||||
|
public MaxFileHistory: number = 10;
|
||||||
|
public HttpBackupURL: string = "";
|
||||||
|
public HttpAPIKey: string = "";
|
||||||
|
public S3URL: string = "";
|
||||||
|
public S3AccessKeyId: string = "";
|
||||||
|
public S3SecretKey: string = "";
|
||||||
|
public S3BucketName: string = "";
|
||||||
|
public S3KeyPrefix: string = "";
|
||||||
|
}
|
||||||
15
src/app/models/atlasData/blueprintGeneratedClass.model.ts
Normal file
15
src/app/models/atlasData/blueprintGeneratedClass.model.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import {Deserialize} from "../util/deserialize.model";
|
||||||
|
|
||||||
|
export class BlueprintGeneratedClassModel implements Deserialize {
|
||||||
|
public blueprint: string;
|
||||||
|
|
||||||
|
public deserialize(raw: any): this {
|
||||||
|
if( raw[0] !== 'BlueprintGeneratedClass') Error('wrong type, expecting BlueprintGeneratedClassModel, got [' + raw[0] + ']!');
|
||||||
|
this.blueprint = raw[1];
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
public toJSON(): object {
|
||||||
|
return [ 'BlueprintGeneratedClass', this.blueprint ];
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/app/models/atlasData/coordinate-3d-string.model.ts
Normal file
20
src/app/models/atlasData/coordinate-3d-string.model.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
|
||||||
|
export class Coordinate3dStringModel implements Deserialize {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
const array = input.split(' ');
|
||||||
|
if (array.length !== 3) throw Error(`Bad string [${input}] for Coordinate3d`);
|
||||||
|
this.x = Number.parseFloat(array[0]);
|
||||||
|
this.y = Number.parseFloat(array[1]);
|
||||||
|
this.z = Number.parseFloat(array[2]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): string {
|
||||||
|
return `${this.x} ${this.y} ${this.z}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
118
src/app/models/atlasData/island-instance.model.ts
Normal file
118
src/app/models/atlasData/island-instance.model.ts
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
import { IslandDataModel } from "../../../data/models/island-data.model";
|
||||||
|
import { Coordinate3dStringModel } from "./coordinate-3d-string.model";
|
||||||
|
|
||||||
|
export class IslandInstanceModel implements Deserialize {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
spawnerOverrides: object; // TODO Figure out what this actually does
|
||||||
|
treasureMapSpawnPoints: Coordinate3dStringModel[];
|
||||||
|
wildPirateCampSpawnPoints: Coordinate3dStringModel[];
|
||||||
|
minTreasureQuality: number;
|
||||||
|
maxTreasureQuality: number;
|
||||||
|
useNpcVolumesForTreasures: boolean;
|
||||||
|
useLevelBoundsForTreasures: boolean;
|
||||||
|
prioritizeVolumesForTreasures: boolean;
|
||||||
|
islandPoints: number;
|
||||||
|
islandTreasureBottleSupplyCrateOverrides: string; // TODO figure out what this actually is
|
||||||
|
islandWidth: number;
|
||||||
|
islandHeight: number;
|
||||||
|
singleSpawnPointX: number;
|
||||||
|
singleSpawnPointY: number;
|
||||||
|
singleSpawnPointZ: number;
|
||||||
|
worldX: number;
|
||||||
|
worldY: number;
|
||||||
|
rotation: number;
|
||||||
|
|
||||||
|
// Specify extra player spawn points. Unique within entire grid
|
||||||
|
spawnPointRegionOverride: number = -1;
|
||||||
|
finalNPCLevelMultiplier: number = 1;
|
||||||
|
finalNPCLevelOffset: number = 0;
|
||||||
|
instanceTreasureQualityMultiplier: number = 1;
|
||||||
|
instanceTreasureQualityAddition: number = 0;
|
||||||
|
|
||||||
|
// Linked comma separated values normally. Lets just fix that...
|
||||||
|
public IslandInstanceCustomData: object = {};
|
||||||
|
public IslandInstanceClientCustomData: object = {};
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
// Do this before actually assigning to current object
|
||||||
|
const string1 = input.IslandInstanceCustomDatas1;
|
||||||
|
delete input.IslandInstanceCustomDatas1;
|
||||||
|
const string2 = input.IslandInstanceCustomDatas2;
|
||||||
|
delete input.IslandInstanceCustomDatas2;
|
||||||
|
const stringClient1 = input.IslandInstanceClientCustomDatas1;
|
||||||
|
delete input.IslandInstanceClientCustomDatas1;
|
||||||
|
const stringClient2 = input.IslandInstanceClientCustomDatas2;
|
||||||
|
delete input.IslandInstanceClientCustomDatas2;
|
||||||
|
Object.assign(this, input);
|
||||||
|
|
||||||
|
// Some minor assumption about how this works, but...
|
||||||
|
if (string1) {
|
||||||
|
const array1 = string1.split(',');
|
||||||
|
const array2 = string2.split(',');
|
||||||
|
if (array1.length !== array2.length)
|
||||||
|
throw Error('IslandInstanceCustomDatas unmatched array length');
|
||||||
|
array1.forEach((i, idx) => this.IslandInstanceCustomData[i] = array2[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stringClient1) {
|
||||||
|
const array1 = stringClient1.split(',');
|
||||||
|
const array2 = stringClient2.split(',');
|
||||||
|
if (array1.length !== array2.length)
|
||||||
|
throw Error('IslandInstanceClientCustomDatas unmatched array length');
|
||||||
|
array1.forEach((i, idx) => this.IslandInstanceClientCustomData[i] = array2[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.treasureMapSpawnPoints === undefined) this.treasureMapSpawnPoints = [];
|
||||||
|
this.treasureMapSpawnPoints = this.treasureMapSpawnPoints.map(i => new Coordinate3dStringModel().deserialize(i));
|
||||||
|
if (this.wildPirateCampSpawnPoints === undefined) this.wildPirateCampSpawnPoints = [];
|
||||||
|
this.wildPirateCampSpawnPoints = this.wildPirateCampSpawnPoints.map(i => new Coordinate3dStringModel().deserialize(i));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): object {
|
||||||
|
let json = Object.assign({}, this);
|
||||||
|
// Remove some stupidity from the above
|
||||||
|
delete json.IslandInstanceCustomData;
|
||||||
|
delete json.IslandInstanceClientCustomData;
|
||||||
|
// Remap to separate variables
|
||||||
|
if (Object.keys(this.IslandInstanceCustomData).length > 0) {
|
||||||
|
json['IslandInstanceCustomDatas1'] = Object.keys(this.IslandInstanceCustomData).join(',');
|
||||||
|
json['IslandInstanceCustomDatas2'] = Object.values(this.IslandInstanceCustomData).join(',');
|
||||||
|
}
|
||||||
|
if (Object.keys(this.IslandInstanceCustomData).length > 0) {
|
||||||
|
json['IslandInstanceClientCustomDatas1'] = Object.keys(this.IslandInstanceClientCustomData).join(',');
|
||||||
|
json['IslandInstanceClientCustomDatas2'] = Object.values(this.IslandInstanceClientCustomData).join(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.spawnPointRegionOverride === -1) delete json.spawnPointRegionOverride;
|
||||||
|
if (json.finalNPCLevelMultiplier === 1) delete json.finalNPCLevelMultiplier;
|
||||||
|
if (json.finalNPCLevelOffset === 0) delete json.finalNPCLevelMultiplier;
|
||||||
|
if (json.instanceTreasureQualityMultiplier === 1) delete json.instanceTreasureQualityMultiplier;
|
||||||
|
if (json.instanceTreasureQualityAddition === 0) delete json.instanceTreasureQualityAddition;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromIslandData(data: IslandDataModel): IslandInstanceModel {
|
||||||
|
return new IslandInstanceModel().deserialize({
|
||||||
|
name: data.name,
|
||||||
|
spawnerOverrides: data.spawnerOverrides,
|
||||||
|
treasureMapSpawnPoints: data.treasureMapSpawnPoints,
|
||||||
|
wildPirateCampSpawnPoints: data.wildPirateCampSpawnPoints,
|
||||||
|
minTreasureQuality: data.minTreasureQuality,
|
||||||
|
maxTreasureQuality: data.maxTreasureQuality,
|
||||||
|
useNpcVolumesForTreasures: data.useNpcVolumesForTreasures,
|
||||||
|
useLevelBoundsForTreasures: data.useLevelBoundsForTreasures,
|
||||||
|
prioritizeVolumesForTreasures: data.prioritizeVolumesForTreasures,
|
||||||
|
islandPoints: data.islandPoints,
|
||||||
|
islandTreasureBottleSupplyCrateOverrides: data.islandTreasureBottleSupplyCrateOverrides,
|
||||||
|
islandWidth: data.x,
|
||||||
|
islandHeight: data.y,
|
||||||
|
singleSpawnPointX: data.singleSpawnPointX,
|
||||||
|
singleSpawnPointY: data.singleSpawnPointY,
|
||||||
|
singleSpawnPointZ: data.singleSpawnPointZ
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/app/models/atlasData/questEntry.model.ts
Normal file
37
src/app/models/atlasData/questEntry.model.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Texture2DModel } from "./texture2D.model";
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
import { BlueprintGeneratedClassModel } from "./blueprintGeneratedClass.model";
|
||||||
|
import { QuestPointsOfInterestModel } from "./questPointsOfInterest.model";
|
||||||
|
|
||||||
|
export class QuestEntryModel implements Deserialize {
|
||||||
|
public QuestID: number;
|
||||||
|
public CompletedIcon: Texture2DModel;
|
||||||
|
public UncompletedIcon: Texture2DModel;
|
||||||
|
public QuestName: string;
|
||||||
|
public QuestDescription: string;
|
||||||
|
public UnlockFeatNames: string[];
|
||||||
|
public CompleteGiveEngramClasses: Array<BlueprintGeneratedClassModel>;
|
||||||
|
public QuestPointsOfInterest: Array<QuestPointsOfInterestModel>;
|
||||||
|
|
||||||
|
public deserialize(raw: any): this {
|
||||||
|
Object.assign(this, raw);
|
||||||
|
this.CompletedIcon = new Texture2DModel().deserialize(raw.CompletedIcon);
|
||||||
|
this.UncompletedIcon = new Texture2DModel().deserialize(raw.UncompletedIcon);
|
||||||
|
// Some Quests dont have an engram on completion
|
||||||
|
if (this.CompleteGiveEngramClasses !== undefined)
|
||||||
|
this.CompleteGiveEngramClasses
|
||||||
|
= this.CompleteGiveEngramClasses.map(i => new BlueprintGeneratedClassModel().deserialize(i));
|
||||||
|
// Some Quests have no points of interest to complete
|
||||||
|
if (this.QuestPointsOfInterest !== undefined)
|
||||||
|
this.QuestPointsOfInterest
|
||||||
|
= this.QuestPointsOfInterest.map(i => new QuestPointsOfInterestModel().deserialize(i));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJSON() {
|
||||||
|
let json = Object.assign({}, this);
|
||||||
|
if (this.CompleteGiveEngramClasses === undefined) delete json.CompleteGiveEngramClasses;
|
||||||
|
if (this.QuestPointsOfInterest === undefined) delete json.QuestPointsOfInterest;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/app/models/atlasData/questPointsOfInterest.model.ts
Normal file
20
src/app/models/atlasData/questPointsOfInterest.model.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
import { WorldMapPositionModel } from "./worldMapPosition.model";
|
||||||
|
import { Texture2DModel } from "./texture2D.model";
|
||||||
|
|
||||||
|
export class QuestPointsOfInterestModel implements Deserialize {
|
||||||
|
public PointOfInterestID: number;
|
||||||
|
public PointOfInterestName: string;
|
||||||
|
public UnlockFeatNames: Array<string>;
|
||||||
|
public WorldMapPosition: WorldMapPositionModel;
|
||||||
|
public CompletedIcon: Texture2DModel;
|
||||||
|
public UncompletedIcon: Texture2DModel;
|
||||||
|
|
||||||
|
public deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
this.WorldMapPosition = new WorldMapPositionModel().deserialize(input.WorldMapPosition);
|
||||||
|
this.CompletedIcon = new Texture2DModel().deserialize(input.CompletedIcon);
|
||||||
|
this.UncompletedIcon = new Texture2DModel().deserialize(input.UncompletedIcon);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
77
src/app/models/atlasData/server.model.ts
Normal file
77
src/app/models/atlasData/server.model.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
import { ServerSublevelModel } from "./serverSublevel.model";
|
||||||
|
import { IslandInstanceModel } from "./island-instance.model";
|
||||||
|
|
||||||
|
export class ServerModel implements Deserialize {
|
||||||
|
// General Settings
|
||||||
|
name: string;
|
||||||
|
gridX: number;
|
||||||
|
gridY: number;
|
||||||
|
isHomeServer: boolean;
|
||||||
|
utcOffset: number;
|
||||||
|
|
||||||
|
// Connection Settings
|
||||||
|
ip: string;
|
||||||
|
port: number;
|
||||||
|
gamePort: number;
|
||||||
|
seamlessDataPort: number;
|
||||||
|
|
||||||
|
// Gameplay Settings
|
||||||
|
floorZDist: number;
|
||||||
|
transitionMinZ: number;
|
||||||
|
serverIslandPointsMultiplier: number;
|
||||||
|
|
||||||
|
// Colour & Style Settings
|
||||||
|
waterColorR: number;
|
||||||
|
waterColorG: number;
|
||||||
|
waterColorB: number;
|
||||||
|
skyStyleIndex: number;
|
||||||
|
|
||||||
|
// Override Settings
|
||||||
|
OceanDinoDepthEntriesOverride: string;
|
||||||
|
oceanFloatsamCratesOverride: string;
|
||||||
|
treasureMapLootTablesOverride: string;
|
||||||
|
OverrideShooterGameModeDefaultGameIni: object;
|
||||||
|
|
||||||
|
//Dont render if default/empty
|
||||||
|
GlobalBiomeSeamlessServerGridPreOffsetValues: string;
|
||||||
|
GlobalBiomeSeamlessServerGridPreOffsetValuesOceanWater: string;
|
||||||
|
oceanEpicSpawnEntriesOverrideTemplateName: string;
|
||||||
|
NPCShipSpawnEntriesOverrideTemplateName: string;
|
||||||
|
regionOverrides: string;
|
||||||
|
|
||||||
|
|
||||||
|
lastImageOverride: string;
|
||||||
|
|
||||||
|
extraSublevels: string[];
|
||||||
|
totalExtraSublevels: string[];
|
||||||
|
islandInstances: IslandInstanceModel[];
|
||||||
|
discoZones;
|
||||||
|
spawnRegions;
|
||||||
|
|
||||||
|
// Dont render if default/empty
|
||||||
|
serverTemplateName: string;
|
||||||
|
|
||||||
|
sublevels: ServerSublevelModel[];
|
||||||
|
|
||||||
|
// Irrelevant, used internally by Grapeshot
|
||||||
|
//MachineIdTag: string;
|
||||||
|
// Probably also irrelevant
|
||||||
|
//AdditionalCmdLineParams: string;
|
||||||
|
|
||||||
|
// Used by ServerGridEditor
|
||||||
|
//islandLocked: boolean;
|
||||||
|
//discoLocked: boolean;
|
||||||
|
//pathsLocked: boolean;
|
||||||
|
|
||||||
|
// Editing time for ServerGridEditor
|
||||||
|
//lastModified: string;
|
||||||
|
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
this.sublevels = this.sublevels.map(i => new ServerSublevelModel().deserialize(i));
|
||||||
|
this.islandInstances = this.islandInstances.map(i => new IslandInstanceModel().deserialize(i));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/app/models/atlasData/serverSublevel.model.ts
Normal file
40
src/app/models/atlasData/serverSublevel.model.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
import { IslandInstanceModel } from "./island-instance.model";
|
||||||
|
import { ServerModel } from "./server.model";
|
||||||
|
import { ServerGridModel } from "../serverGrid.model";
|
||||||
|
import { IslandDataModel } from "../../../data/models/island-data.model";
|
||||||
|
|
||||||
|
export class ServerSublevelModel implements Deserialize {
|
||||||
|
public name: string;
|
||||||
|
public additionalTranslationX: number;
|
||||||
|
public additionalTranslationY: number;
|
||||||
|
public additionalTranslationZ: number = 0;
|
||||||
|
public additionalRotationPitch: number = 0;
|
||||||
|
public additionalRotationYaw: number = 0;
|
||||||
|
public additionalRotationRoll: number = 0;
|
||||||
|
public id: number;
|
||||||
|
public landscapeMaterialOverride: number;
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
return Object.assign(this, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupFromIsland(island: IslandInstanceModel, islandData: IslandDataModel, cell: ServerModel, grid: ServerGridModel) {
|
||||||
|
this.id = island.id;
|
||||||
|
this.landscapeMaterialOverride = islandData.landscapeMaterialOverride;
|
||||||
|
this.additionalRotationYaw = island.rotation;
|
||||||
|
|
||||||
|
// XY are based on centre of the cell
|
||||||
|
// Use integers to reduce precision issues.
|
||||||
|
// 10 Million chosen as is larger than gridSize recommended setting
|
||||||
|
const multiplier = 10_000_000;
|
||||||
|
const worldX = island.worldX * multiplier;
|
||||||
|
const worldY = island.worldY * multiplier;
|
||||||
|
const gridSize = grid.gridSize * multiplier;
|
||||||
|
|
||||||
|
const newX = worldX - (gridSize * cell.gridX) - (gridSize / 2);
|
||||||
|
this.additionalTranslationX = newX / multiplier;
|
||||||
|
const newY = worldY - (gridSize * cell.gridY) - (gridSize / 2);
|
||||||
|
this.additionalTranslationY = newY / multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/app/models/atlasData/serverTemplate.model.ts
Normal file
13
src/app/models/atlasData/serverTemplate.model.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
import { ServerModel } from "./server.model";
|
||||||
|
|
||||||
|
export class ServerTemplateModel extends ServerModel implements Deserialize {
|
||||||
|
public templateColorR: number;
|
||||||
|
public templateColorG: number;
|
||||||
|
public templateColorB: number;
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/app/models/atlasData/texture2D.model.ts
Normal file
15
src/app/models/atlasData/texture2D.model.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
|
||||||
|
export class Texture2DModel implements Deserialize {
|
||||||
|
public texture: string;
|
||||||
|
|
||||||
|
public deserialize(raw: any): this {
|
||||||
|
if (raw[0] !== 'Texture2D') Error('wrong type, expecting Texture2DModel, got [' + raw[0] + ']!');
|
||||||
|
this.texture = raw[1];
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
public toJSON(): object {
|
||||||
|
return ['Texture2D', this.texture];
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/app/models/atlasData/worldMapPosition.model.ts
Normal file
11
src/app/models/atlasData/worldMapPosition.model.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Deserialize } from "../util/deserialize.model";
|
||||||
|
|
||||||
|
export class WorldMapPositionModel implements Deserialize {
|
||||||
|
public X: number;
|
||||||
|
public Y: number;
|
||||||
|
|
||||||
|
public deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/app/models/databaseConnection.model.ts
Normal file
12
src/app/models/databaseConnection.model.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import {Deserialize} from "./util/deserialize.model";
|
||||||
|
|
||||||
|
export class DatabaseConnectionModel implements Deserialize {
|
||||||
|
public Name: string;
|
||||||
|
public URL: string;
|
||||||
|
public Port: number;
|
||||||
|
public Password: string;
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
return Object.assign(this, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/app/models/globalGameplaySetupModel.ts
Normal file
18
src/app/models/globalGameplaySetupModel.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { PegjsService } from "../services/pegjs.service";
|
||||||
|
import { QuestEntryModel } from "./atlasData/questEntry.model";
|
||||||
|
import { Deserialize } from "./util/deserialize.model";
|
||||||
|
|
||||||
|
export class GlobalGameplaySetupModel implements Deserialize {
|
||||||
|
QuestEntries: QuestEntryModel[];
|
||||||
|
|
||||||
|
public deserialize(raw: string): this {
|
||||||
|
const rawData = PegjsService.parse(raw);
|
||||||
|
Object.assign(this, rawData);
|
||||||
|
this.QuestEntries = this.QuestEntries.map(i => new QuestEntryModel().deserialize(i));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJSON(): string {
|
||||||
|
return PegjsService.format(this, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/app/models/serverGrid.model.ts
Normal file
100
src/app/models/serverGrid.model.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { TribeLogConfigModel } from "./tribeLogConfig.model";
|
||||||
|
import { SharedLogConfigModel } from "./sharedLogConfig.model";
|
||||||
|
import { TravelDataConfigModel } from "./travelDataConfig.model";
|
||||||
|
import { GlobalGameplaySetupModel } from "./GlobalGameplaySetupModel";
|
||||||
|
import { Deserialize } from "./util/deserialize.model";
|
||||||
|
import { DatabaseConnectionModel } from "./databaseConnection.model";
|
||||||
|
import { ServerModel } from "./atlasData/server.model";
|
||||||
|
import { ServerTemplateModel } from "./atlasData/serverTemplate.model";
|
||||||
|
|
||||||
|
export class ServerGridModel implements Deserialize {
|
||||||
|
// Server Argument Section
|
||||||
|
// Used internally by Grapeshot
|
||||||
|
//public BaseServerArgs: string = "";
|
||||||
|
// Probably also internal to Grapeshot
|
||||||
|
//public AdditionalCmdLineParams: string = "";
|
||||||
|
|
||||||
|
// World Options
|
||||||
|
public WorldFriendlyName: string = "New Server";
|
||||||
|
public WorldAtlasId: string = "";
|
||||||
|
public WorldAtlasPassword: string = "";
|
||||||
|
public ModIDs: string = "";
|
||||||
|
|
||||||
|
// Grid Options
|
||||||
|
public gridSize: number = 1000;
|
||||||
|
public totalGridsX: number = 1;
|
||||||
|
public totalGridsY: number = 1;
|
||||||
|
public globalTransitionMinZ: number = 0.0;
|
||||||
|
|
||||||
|
// Used by ServerGridEditor for Zoom Level, so ignored
|
||||||
|
// Will be added if present in config when loading.
|
||||||
|
//public coordsScaling: number = 0.000000000001;
|
||||||
|
|
||||||
|
// Image Paths
|
||||||
|
// Used for generating tile output
|
||||||
|
//public backgroundImgPath: string = "image.png";
|
||||||
|
// Used for displaying discovery zones in ServerGridEditor
|
||||||
|
//public discoZonesImagePath: string = "image.png";
|
||||||
|
|
||||||
|
// URL Options
|
||||||
|
public MetaWorldURL: string = "";
|
||||||
|
public AuthListURL: string = "";
|
||||||
|
public MapImageURL: string = "";
|
||||||
|
|
||||||
|
// Time Options
|
||||||
|
public Day0: string = "2019-01-09 20:28:56";
|
||||||
|
public bUseUTCTime: boolean = false;
|
||||||
|
public columnUTCOffset: number = 0.0;
|
||||||
|
public lastImageOverride: string = "0001-01-01T00:00:00";
|
||||||
|
|
||||||
|
// Info Options for ServerGridEditor
|
||||||
|
// public showServerInfo: boolean = false;
|
||||||
|
// public showDiscoZoneInfo: boolean = false;
|
||||||
|
// public showShipPathsInfo: boolean = false;
|
||||||
|
// public showIslandNames: boolean = false;
|
||||||
|
// public showLines: boolean = false;
|
||||||
|
// public showBackground: boolean = false;
|
||||||
|
|
||||||
|
// S3 Options
|
||||||
|
public LocalS3URL: string = "";
|
||||||
|
public LocalS3AccessKeyId: string = "";
|
||||||
|
public LocalS3SecretKey: string = "";
|
||||||
|
public LocalS3BucketName: string = "";
|
||||||
|
public LocalS3Region: string = "";
|
||||||
|
|
||||||
|
// ID Generator current values
|
||||||
|
// Used for individual ship path
|
||||||
|
public shipPathsIdGenerator: number = 0;
|
||||||
|
// Used for Discovery Zone & Island IDs
|
||||||
|
public idGenerator: number = 0;
|
||||||
|
// Unused as far as can see in ServerGridEditor
|
||||||
|
public regionsIdGenerator: number = 0;
|
||||||
|
|
||||||
|
// Log Configs
|
||||||
|
public TribeLogConfig: TribeLogConfigModel = new TribeLogConfigModel();
|
||||||
|
public SharedLogConfig: SharedLogConfigModel = new SharedLogConfigModel();
|
||||||
|
public TravelDataConfig: TravelDataConfigModel = new TravelDataConfigModel();
|
||||||
|
|
||||||
|
// Quest Config
|
||||||
|
public globalGameplaySetup: GlobalGameplaySetupModel = new GlobalGameplaySetupModel();
|
||||||
|
|
||||||
|
public DatabaseConnections: DatabaseConnectionModel[];
|
||||||
|
public servers: ServerModel[];
|
||||||
|
public serverTemplates: ServerTemplateModel[];
|
||||||
|
|
||||||
|
public deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
this.SharedLogConfig = new SharedLogConfigModel().deserialize(input.SharedLogConfig);
|
||||||
|
this.TribeLogConfig = new TribeLogConfigModel().deserialize(input.TribeLogConfig);
|
||||||
|
this.TravelDataConfig = new TravelDataConfigModel().deserialize(input.TravelDataConfig);
|
||||||
|
this.globalGameplaySetup = new GlobalGameplaySetupModel().deserialize(input.globalGameplaySetup);
|
||||||
|
this.DatabaseConnections = this.DatabaseConnections.map(i => new DatabaseConnectionModel().deserialize(i));
|
||||||
|
this.servers = this.servers.map(i => new ServerModel().deserialize(i));
|
||||||
|
this.serverTemplates = this.serverTemplates.map(i => new ServerTemplateModel().deserialize(i));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getNextId() {
|
||||||
|
return ++this.idGenerator;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/app/models/sharedLogConfig.model.ts
Normal file
14
src/app/models/sharedLogConfig.model.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import {BaseConfig} from "./abstract/baseConfig.model";
|
||||||
|
import { Deserialize } from "./util/deserialize.model";
|
||||||
|
|
||||||
|
export class SharedLogConfigModel extends BaseConfig implements Deserialize {
|
||||||
|
public FetchRateSec: number = 60;
|
||||||
|
public SnapshotCleanupSec: number = 900;
|
||||||
|
public SnapshotRateSec: number = 1800;
|
||||||
|
public SnapshotExpirationHours: number = 48;
|
||||||
|
|
||||||
|
public deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/app/models/travelDataConfig.model.ts
Normal file
10
src/app/models/travelDataConfig.model.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import {BaseConfig} from "./abstract/baseConfig.model";
|
||||||
|
import { Deserialize } from "./util/deserialize.model";
|
||||||
|
|
||||||
|
export class TravelDataConfigModel extends BaseConfig implements Deserialize {
|
||||||
|
|
||||||
|
public deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/app/models/tribeLogConfig.model.ts
Normal file
13
src/app/models/tribeLogConfig.model.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {BaseConfig} from "./abstract/baseConfig.model";
|
||||||
|
import {Deserialize} from "./util/deserialize.model";
|
||||||
|
import {Serialize} from "./util/serialize.model";
|
||||||
|
import {PegjsService} from "../services/pegjs.service";
|
||||||
|
|
||||||
|
export class TribeLogConfigModel extends BaseConfig implements Deserialize {
|
||||||
|
public MaxRedisEntries: number = 1000;
|
||||||
|
|
||||||
|
public deserialize(raw: any): this {
|
||||||
|
Object.assign(this, raw);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/app/models/util/deserialize.model.ts
Normal file
3
src/app/models/util/deserialize.model.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface Deserialize {
|
||||||
|
deserialize(input: any): this;
|
||||||
|
}
|
||||||
3
src/app/models/util/serialize.model.ts
Normal file
3
src/app/models/util/serialize.model.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface Serialize {
|
||||||
|
serialize(): any;
|
||||||
|
}
|
||||||
9
src/app/pages/config/config.component.html
Normal file
9
src/app/pages/config/config.component.html
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-2 mt-3">
|
||||||
|
<button class="btn btn-primary btn-block" [routerLink]="['grid']">Grid Settings</button>
|
||||||
|
<button class="btn btn-primary btn-block" [routerLink]="['dbs']">DB Settings</button>
|
||||||
|
<button class="btn btn-primary btn-block" [routerLink]="['quests']">Quest Settings</button>
|
||||||
|
<button class="btn btn-primary btn-block" [routerLink]="['servers']">Server Settings</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-10"><router-outlet></router-outlet></div>
|
||||||
|
</div>
|
||||||
0
src/app/pages/config/config.component.scss
Normal file
0
src/app/pages/config/config.component.scss
Normal file
16
src/app/pages/config/config.component.ts
Normal file
16
src/app/pages/config/config.component.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Server } from "../../server";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-config',
|
||||||
|
templateUrl: './config.component.html',
|
||||||
|
styleUrls: ['./config.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfigComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(private server: Server) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/app/pages/config/dbs/dbs.component.html
Normal file
15
src/app/pages/config/dbs/dbs.component.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 mt-3">
|
||||||
|
<h2>Database Settings</h2>
|
||||||
|
<ngb-accordion>
|
||||||
|
<ngb-panel *ngFor="let db of dbs; let i = index" title="{{ db.Name }}">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="db-{{ i }}-name" label="Name" [(text)]="db.Name"></app-text>
|
||||||
|
<app-text id="db-{{ i }}-URL" label="URL" [(text)]="db.URL"></app-text>
|
||||||
|
<app-number id="db-{{ i }}-Port" label="Port" [(number)]="db.Port"></app-number>
|
||||||
|
<app-password id="db-{{ i }}-Password" label="Password" [(password)]="db.Password"></app-password>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
19
src/app/pages/config/dbs/dbs.component.ts
Normal file
19
src/app/pages/config/dbs/dbs.component.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Server } from "../../../server";
|
||||||
|
import { DatabaseConnectionModel } from "../../../models/databaseConnection.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dbs',
|
||||||
|
templateUrl: './dbs.component.html'
|
||||||
|
})
|
||||||
|
export class DbsComponent implements OnInit {
|
||||||
|
dbs: DatabaseConnectionModel[];
|
||||||
|
|
||||||
|
constructor(private server: Server) {
|
||||||
|
this.dbs = server.serverGrid.DatabaseConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
102
src/app/pages/config/grid/grid.component.html
Normal file
102
src/app/pages/config/grid/grid.component.html
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 mt-3">
|
||||||
|
<h2>Grid Settings</h2>
|
||||||
|
<ngb-accordion>
|
||||||
|
<ngb-panel id="toggle-generalSettings" title="World Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="WorldFriendlyName" label="Name" [(text)]="grid.WorldFriendlyName"
|
||||||
|
help="Name shown on Atlas server listings for your server"></app-text>
|
||||||
|
<app-text id="WorldAtlasId" label="Atlas ID" [(text)]="grid.WorldAtlasId"
|
||||||
|
help="Unique ID used for joining multiple servers together in multi-host setups"></app-text>
|
||||||
|
<app-password id="WorldAtlasPassword" label="Password"
|
||||||
|
[(password)]="grid.WorldAtlasPassword"
|
||||||
|
help="Password used for connecting to your Server"></app-password>
|
||||||
|
<app-text id="ModIDs" label="Mod IDs" [(text)]="grid.ModIDs"
|
||||||
|
help="Comma separated list of Mod IDs from Steam Workshop"></app-text>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel id="toggle-gridSettings" title="Grid Size Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="gridSize" label="Grid Size" [(number)]="grid.gridSize"
|
||||||
|
help="Size in Unreal Units per Cell. Recommended default & maximum 1,400,000"></app-number>
|
||||||
|
<app-number id="totalGridsX" label="Total Grids X" [(number)]="grid.totalGridsX"
|
||||||
|
help="Total number of Cells in X Direction"></app-number>
|
||||||
|
<app-number id="totalGridsY" label="Total Grids Y" [(number)]="grid.totalGridsY"
|
||||||
|
help="Total number of Cells in Y Direction"></app-number>
|
||||||
|
<app-number id="globalTransitionMinZ" label="Min Z Transition"
|
||||||
|
[(number)]="grid.globalTransitionMinZ"
|
||||||
|
help="Lowest Z height for transitions across cell borders"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel id="toggle-urlSettings" title="URL Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="MetaWorldURL" label="Meta World URL" [(text)]="grid.MetaWorldURL" help="Used for an in game active map"></app-text>
|
||||||
|
<app-text id="AuthListURL" label="Auth List URL" [(text)]="grid.AuthListURL"></app-text>
|
||||||
|
<app-text id="MapImageURL" label="Map Image URL" [(text)]="grid.MapImageURL" help="Used for server listing and if Meta World URL is not defined"></app-text>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel id="toggle-timeOptions" title="Time Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="Day0" label="Day Zero" [(text)]="grid.Day0"></app-text>
|
||||||
|
<app-checkbox id="bUseUTCTime" label="Use UTC" [(checkbox)]="grid.bUseUTCTime"></app-checkbox>
|
||||||
|
<app-number id="columnUTCOffset" label="UTC Offset" [(number)]="grid.columnUTCOffset"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel id="toggle-1" title="Local S3 Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="LocalS3URL" label="URL" [(text)]="grid.LocalS3URL"></app-text>
|
||||||
|
<app-text id="LocalS3AccessKeyID" label="Access Key ID"
|
||||||
|
[(text)]="grid.LocalS3AccessKeyId"></app-text>
|
||||||
|
<app-password id="LocalS3SecretKey" label="Secret Key"
|
||||||
|
[(password)]="grid.LocalS3SecretKey"></app-password>
|
||||||
|
<app-text id="LocalS3BucketName" label="Bucket Name" [(text)]="grid.LocalS3BucketName"></app-text>
|
||||||
|
<app-text id="LocalS3Region" label="Region" [(text)]="grid.LocalS3Region"></app-text>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Tribe Log Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="Tribe-MaxRedisEntries" label="Max Redis Entries" [(number)]="tribeLog.MaxRedisEntries"></app-number>
|
||||||
|
<app-text id="Tribe-BackupMode" label="Backup Mode" [(text)]="tribeLog.BackupMode"></app-text>
|
||||||
|
<app-number id="Tribe-MaxFileHistory" label="Max File History" [(number)]="tribeLog.MaxFileHistory"></app-number>
|
||||||
|
<app-text id="Tribe-HttpBackupURL" label="Http Backup URL" [(text)]="tribeLog.HttpBackupURL"></app-text>
|
||||||
|
<app-text id="Tribe-HttpAPIKey" label="HTTP API Key" [(text)]="tribeLog.HttpAPIKey"></app-text>
|
||||||
|
<app-text id="Tribe-S3URL" label="S3 URL" [(text)]="tribeLog.S3URL"></app-text>
|
||||||
|
<app-text id="Tribe-S3AccessKeyId" label="S3 Access Key ID" [(text)]="tribeLog.S3AccessKeyId"></app-text>
|
||||||
|
<app-password id="Tribe-S3SecretKey" label="S3 Secret Key" [(password)]="tribeLog.S3SecretKey"></app-password>
|
||||||
|
<app-text id="Tribe-S3BucketName" label="S3 Bucket Name" [(text)]="tribeLog.S3BucketName"></app-text>
|
||||||
|
<app-text id="Tribe-S3KeyPrefix" label="S3 Key Prefix" [(text)]="tribeLog.S3KeyPrefix"></app-text>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Shared Log Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="Shared-FetchRateSec" label="Fetch Rate (s)" [(number)]="sharedLog.FetchRateSec"></app-number>
|
||||||
|
<app-number id="Shared-SnapshotRateSec" label="Snapshot Rate (s)" [(number)]="sharedLog.SnapshotRateSec"></app-number>
|
||||||
|
<app-number id="Shared-SnapshotCleanupSec" label="Snapshot Cleanup (s)" [(number)]="sharedLog.SnapshotCleanupSec"></app-number>
|
||||||
|
<app-number id="Shared-SnapshotExpirationHours" label="Snapshot Expiration (h)" [(number)]="sharedLog.SnapshotExpirationHours"></app-number>
|
||||||
|
<app-text id="Shared-BackupMode" label="Backup Mode" [(text)]="sharedLog.BackupMode"></app-text>
|
||||||
|
<app-number id="Shared-MaxFileHistory" label="Max File History" [(number)]="sharedLog.MaxFileHistory"></app-number>
|
||||||
|
<app-text id="Shared-HttpBackupURL" label="Http Backup URL" [(text)]="sharedLog.HttpBackupURL"></app-text>
|
||||||
|
<app-text id="Shared-HttpAPIKey" label="HTTP API Key" [(text)]="sharedLog.HttpAPIKey"></app-text>
|
||||||
|
<app-text id="Shared-S3URL" label="S3 URL" [(text)]="sharedLog.S3URL"></app-text>
|
||||||
|
<app-text id="Shared-S3AccessKeyId" label="S3 Access Key ID" [(text)]="sharedLog.S3AccessKeyId"></app-text>
|
||||||
|
<app-password id="Shared-S3SecretKey" label="S3 Secret Key" [(password)]="sharedLog.S3SecretKey"></app-password>
|
||||||
|
<app-text id="Shared-S3BucketName" label="S3 Bucket Name" [(text)]="sharedLog.S3BucketName"></app-text>
|
||||||
|
<app-text id="Shared-S3KeyPrefix" label="S3 Key Prefix" [(text)]="sharedLog.S3KeyPrefix"></app-text>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Travel Data Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="Travel-BackupMode" label="Backup Mode" [(text)]="travelData.BackupMode"></app-text>
|
||||||
|
<app-number id="Travel-MaxFileHistory" label="Max File History" [(number)]="travelData.MaxFileHistory"></app-number>
|
||||||
|
<app-text id="Travel-HttpBackupURL" label="Http Backup URL" [(text)]="travelData.HttpBackupURL"></app-text>
|
||||||
|
<app-text id="Travel-HttpAPIKey" label="HTTP API Key" [(text)]="travelData.HttpAPIKey"></app-text>
|
||||||
|
<app-text id="Travel-S3URL" label="S3 URL" [(text)]="travelData.S3URL"></app-text>
|
||||||
|
<app-text id="Travel-S3AccessKeyId" label="S3 Access Key ID" [(text)]="travelData.S3AccessKeyId"></app-text>
|
||||||
|
<app-password id="Travel-S3SecretKey" label="S3 Secret Key" [(password)]="travelData.S3SecretKey"></app-password>
|
||||||
|
<app-text id="Travel-S3BucketName" label="S3 Bucket Name" [(text)]="travelData.S3BucketName"></app-text>
|
||||||
|
<app-text id="Travel-S3KeyPrefix" label="S3 Key Prefix" [(text)]="travelData.S3KeyPrefix"></app-text>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
27
src/app/pages/config/grid/grid.component.ts
Normal file
27
src/app/pages/config/grid/grid.component.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ServerGridModel } from "../../../models/serverGrid.model";
|
||||||
|
import { Server } from "../../../server";
|
||||||
|
import { TribeLogConfigModel } from "../../../models/tribeLogConfig.model";
|
||||||
|
import { SharedLogConfigModel } from "../../../models/sharedLogConfig.model";
|
||||||
|
import { TravelDataConfigModel } from "../../../models/travelDataConfig.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-grid',
|
||||||
|
templateUrl: './grid.component.html'
|
||||||
|
})
|
||||||
|
export class GridComponent implements OnInit {
|
||||||
|
private grid: ServerGridModel;
|
||||||
|
private tribeLog: TribeLogConfigModel;
|
||||||
|
private sharedLog: SharedLogConfigModel;
|
||||||
|
private travelData: TravelDataConfigModel;
|
||||||
|
|
||||||
|
constructor(private server: Server) {
|
||||||
|
this.grid = server.serverGrid;
|
||||||
|
this.tribeLog = server.serverGrid.TribeLogConfig;
|
||||||
|
this.sharedLog = server.serverGrid.SharedLogConfig;
|
||||||
|
this.travelData = server.serverGrid.TravelDataConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/app/pages/config/quests/quests.component.html
Normal file
67
src/app/pages/config/quests/quests.component.html
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 mt-3 mb-3">
|
||||||
|
<h2>Quest Entries</h2>
|
||||||
|
<ngb-accordion>
|
||||||
|
<ngb-panel *ngFor="let quest of quests; let i = index" id="toggle-{{ i }}" title="{{ quest.QuestName }}">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="{{ i }}-QuestName" label="Name" [(text)]="quest.QuestName"></app-text>
|
||||||
|
<app-number id="{{ i }}-QuestID" label="ID" [(number)]="quest.QuestID"></app-number>
|
||||||
|
<app-text id="{{ i }}-QuestDescription" label="Description"
|
||||||
|
[(text)]="quest.QuestDescription"></app-text>
|
||||||
|
<h6>Feat Unlocks
|
||||||
|
<button class="btn btn-primary btn-sm" (click)="addQuestFeat(quest)">+</button>
|
||||||
|
</h6>
|
||||||
|
<p *ngIf="quest.UnlockFeatNames === undefined">
|
||||||
|
<em>Click + above to add Feat Unlocks</em>
|
||||||
|
</p>
|
||||||
|
<app-text id="{{ i }}-{{ j }}-feat"
|
||||||
|
*ngFor="let feat of quest.UnlockFeatNames; index as j; trackBy: trackByFn"
|
||||||
|
label="Unlock {{ j }}" [(text)]="quest.UnlockFeatNames[j]" postButtonText="-"
|
||||||
|
(postButton)="removeQuestFeat(quest, j)"></app-text>
|
||||||
|
<h6>Engram Unlocks
|
||||||
|
<button class="btn btn-primary btn-sm" (click)="addEngramClass(quest)">+</button>
|
||||||
|
</h6>
|
||||||
|
<p *ngIf="quest.CompleteGiveEngramClasses === undefined">
|
||||||
|
<em>Click + above to add Engram Unlocks</em>
|
||||||
|
</p>
|
||||||
|
<app-text id="{{ i }}-{{ j }}-engram"
|
||||||
|
*ngFor="let engram of quest.CompleteGiveEngramClasses; index as j"
|
||||||
|
label="Engram {{ j }}" [(text)]="engram.blueprint" postButtonText="-"
|
||||||
|
(postButton)="removeEngramClass(quest, j)"></app-text>
|
||||||
|
<h6>Points of Interest
|
||||||
|
<button class="btn btn-primary btn-sm">+</button>
|
||||||
|
</h6>
|
||||||
|
<p *ngIf="quest.QuestPointsOfInterest === undefined">
|
||||||
|
<em>Click + above to add Point of Interest</em>
|
||||||
|
</p>
|
||||||
|
<div class="card mb-3" *ngFor="let poi of quest.QuestPointsOfInterest; index as j">
|
||||||
|
<div class="card-body">
|
||||||
|
<app-text id="{{ i }}-{{ j }}-poi-PointOfInterestName"
|
||||||
|
label="Name" [(text)]="poi.PointOfInterestName"></app-text>
|
||||||
|
<app-number id="{{ i }}-{{ j }}-poi-PointOfInterestID"
|
||||||
|
label="ID" [(number)]="poi.PointOfInterestID"></app-number>
|
||||||
|
<app-number id="{{ i }}-{{ j }}-poi-WorldMapPosition-X"
|
||||||
|
label="Map X Pos" [(number)]="poi.WorldMapPosition.X"></app-number>
|
||||||
|
<app-number id="{{ i }}-{{ j }}-poi-WorldMapPosition-Y"
|
||||||
|
label="Map Y Pos" [(number)]="poi.WorldMapPosition.Y"></app-number>
|
||||||
|
<app-text id="{{ i }}-{{ j }}-poi-CompletedIcon"
|
||||||
|
label="Completed Icon" [(text)]="poi.CompletedIcon.texture"></app-text>
|
||||||
|
<app-text id="{{ i }}-{{ j }}-poi-UncompletedIcon"
|
||||||
|
label="Uncompleted Icon" [(text)]="poi.UncompletedIcon.texture"></app-text>
|
||||||
|
<h6>Feat Unlocks
|
||||||
|
<button class="btn btn-primary btn-sm" (click)="addQuestFeat(poi)">+</button>
|
||||||
|
</h6>
|
||||||
|
<p *ngIf="poi.UnlockFeatNames === undefined">
|
||||||
|
<em>Click + above to add Feat Unlocks</em>
|
||||||
|
</p>
|
||||||
|
<app-text id="{{ i }}-{{ j }}-={{ k }}feat"
|
||||||
|
*ngFor="let feat of poi.UnlockFeatNames; index as k; trackBy: trackByFn"
|
||||||
|
label="Unlock {{ k }}" [(text)]="poi.UnlockFeatNames[k]" postButtonText="-"
|
||||||
|
(postButton)="removeQuestFeat(poi, k)"></app-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
53
src/app/pages/config/quests/quests.component.ts
Normal file
53
src/app/pages/config/quests/quests.component.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Server } from "../../../server";
|
||||||
|
import { QuestEntryModel } from "../../../models/atlasData/questEntry.model";
|
||||||
|
import { BlueprintGeneratedClassModel } from "../../../models/atlasData/blueprintGeneratedClass.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-quests',
|
||||||
|
templateUrl: './quests.component.html'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class QuestsComponent implements OnInit {
|
||||||
|
quests: QuestEntryModel[];
|
||||||
|
|
||||||
|
constructor(private server: Server) {
|
||||||
|
this.quests = server.serverGrid.globalGameplaySetup.QuestEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue with text arrays and editing jumps on each change.
|
||||||
|
trackByFn(index: any, item: any) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addQuestFeat(quest) {
|
||||||
|
if (quest.UnlockFeatNames === undefined) {
|
||||||
|
quest.UnlockFeatNames = [];
|
||||||
|
}
|
||||||
|
quest.UnlockFeatNames.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeQuestFeat(quest, j) {
|
||||||
|
quest.UnlockFeatNames.splice(j, 1);
|
||||||
|
if (quest.UnlockFeatNames.length === 0) {
|
||||||
|
quest.UnlockFeatNames = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addEngramClass(quest) {
|
||||||
|
if (quest.CompleteGiveEngramClasses === undefined) {
|
||||||
|
quest.CompleteGiveEngramClasses = [];
|
||||||
|
}
|
||||||
|
quest.CompleteGiveEngramClasses.push(new BlueprintGeneratedClassModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeEngramClass(quest, j) {
|
||||||
|
quest.CompleteGiveEngramClasses.splice(j, 1);
|
||||||
|
if (quest.CompleteGiveEngramClasses.length === 0) {
|
||||||
|
quest.UnlockFeatNames = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
<div class="mt-3">
|
||||||
|
<h2>{{ islandIndex }} - {{ server.islands[island.name].customDisplayName() }}
|
||||||
|
<button class="btn btn-primary btn-sm" [routerLink]="['/config', 'server', cellIndex]">Back to Cell</button>
|
||||||
|
</h2>
|
||||||
|
<p>{{ island.islandWidth }} by {{ island.islandHeight }}</p>
|
||||||
|
<ngb-accordion>
|
||||||
|
<ngb-panel title="General Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="worldX" label="World X" [(number)]="island.worldX"></app-number>
|
||||||
|
<app-number id="worldY" label="World Y" [(number)]="island.worldY"></app-number>
|
||||||
|
<app-number id="rotation" label="Rotation" [(number)]="island.rotation" step="0.000001" min="{{ minRot }}" max="{{ maxRot }}"></app-number>
|
||||||
|
<app-number id="islandPoints" label="Island Points" [(number)]="island.islandPoints"></app-number>
|
||||||
|
<app-number id="spawnPointRegionOverride" label="Spawn Override"
|
||||||
|
[(number)]="island.spawnPointRegionOverride" min="-1"
|
||||||
|
help="Default -1. Set to 0 or more to allow for this island to be spawned on. Must be a unique, consecutive number across the server"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Treasure Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="minTreasureQuality" label="Min Quality" [(number)]="island.minTreasureQuality"
|
||||||
|
help="Default -1. -1 means no limit"></app-number>
|
||||||
|
<app-number id="maxTreasureQuality" label="Max Quality" [(number)]="island.maxTreasureQuality"
|
||||||
|
help="Default -1. -1 means no limit"></app-number>
|
||||||
|
<app-checkbox id="useNpcVolumesForTreasures" label="Use NPC Volumes"
|
||||||
|
[(checkbox)]="island.useNpcVolumesForTreasures"
|
||||||
|
help="useNpcVolumesForTreasures"></app-checkbox>
|
||||||
|
<app-checkbox id="useLevelBoundsForTreasures" label="Use Level Bounds"
|
||||||
|
[(checkbox)]="island.useLevelBoundsForTreasures"
|
||||||
|
help="useLevelBoundsForTreasures"></app-checkbox>
|
||||||
|
<app-checkbox id="prioritizeVolumesForTreasures" label="Prioritise Volumes"
|
||||||
|
[(checkbox)]="island.prioritizeVolumesForTreasures"
|
||||||
|
help="prioritizeVolumesForTreasures"></app-checkbox>
|
||||||
|
<app-number id="instanceTreasureQualityMultiplier" label="Quality Multiplier"
|
||||||
|
[(number)]="island.instanceTreasureQualityMultiplier" min="0" step="0.000001"
|
||||||
|
help="Default 1"></app-number>
|
||||||
|
<app-number id="instanceTreasureQualityAddition" label="Quality Addition"
|
||||||
|
[(number)]="island.instanceTreasureQualityAddition" min="0" step="0.000001"
|
||||||
|
help="Default 0"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Spawn Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="finalNPCLevelMultiplier" label="Level Multiplier"
|
||||||
|
[(number)]="island.finalNPCLevelMultiplier" min="0" step="0.000001"
|
||||||
|
help="Default 1"></app-number>
|
||||||
|
<app-number id="finalNPCLevelOffset" label="Level Addition"
|
||||||
|
[(number)]="island.finalNPCLevelOffset" min="0" step="0.000001"
|
||||||
|
help="Default 0"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Single Player Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="singleSpawnPointX" label="X" [(number)]="island.singleSpawnPointX"></app-number>
|
||||||
|
<app-number id="singleSpawnPointY" label="Y" [(number)]="island.singleSpawnPointY"></app-number>
|
||||||
|
<app-number id="singleSpawnPointZ" label="Z" [(number)]="island.singleSpawnPointZ"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Treasure Locations">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<div class="row" *ngFor="let treasurePos of island.treasureMapSpawnPoints; let i = index">
|
||||||
|
<div class="col-4">
|
||||||
|
<app-number id="{{ i }}-treasure-x" label="X" [(number)]="treasurePos.x"
|
||||||
|
step="0.000001"></app-number>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<app-number id="{{ i }}-treasure-y" label="Y" [(number)]="treasurePos.y"
|
||||||
|
step="0.000001"></app-number>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<app-number id="{{ i }}-treasure-z" label="Z" [(number)]="treasurePos.z" step="0.000001"
|
||||||
|
postButtonText="-" (postButton)="removeTreasureLocation(i)"></app-number>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Pirate Camp Locations">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<div class="row" *ngFor="let campPos of island.wildPirateCampSpawnPoints; let i = index">
|
||||||
|
<div class="col-4">
|
||||||
|
<app-number id="{{ i }}-camp-x" label="X" [(number)]="campPos.x" step="0.000001"></app-number>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<app-number id="{{ i }}-camp-y" label="Y" [(number)]="campPos.y" step="0.000001"></app-number>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<app-number id="{{ i }}-camp-z" label="Z" [(number)]="campPos.z" step="0.000001"
|
||||||
|
postButtonText="-" (postButton)="removeCampLocation(i)"></app-number>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Server } from "../../../../server";
|
||||||
|
import { ServerModel } from "../../../../models/atlasData/server.model";
|
||||||
|
import { IslandInstanceModel } from "../../../../models/atlasData/island-instance.model";
|
||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-island-instance',
|
||||||
|
templateUrl: './island-instance.component.html'
|
||||||
|
})
|
||||||
|
export class IslandInstanceComponent implements OnInit {
|
||||||
|
private cell: ServerModel;
|
||||||
|
private cellIndex;
|
||||||
|
private island: IslandInstanceModel;
|
||||||
|
private islandIndex;
|
||||||
|
|
||||||
|
private minX: number;
|
||||||
|
private maxX: number;
|
||||||
|
private minY: number;
|
||||||
|
private maxY: number;
|
||||||
|
private minRot: number = 0;
|
||||||
|
private maxRot: number = 360;
|
||||||
|
|
||||||
|
constructor(private server: Server, private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.cellIndex = this.route.snapshot.paramMap.get('index');
|
||||||
|
this.islandIndex = this.route.snapshot.paramMap.get('islandIndex');
|
||||||
|
this.cell = this.server.serverGrid.servers[this.cellIndex];
|
||||||
|
this.island = this.cell.islandInstances[this.islandIndex];
|
||||||
|
this.minX = this.cell.gridX * this.server.serverGrid.gridSize;
|
||||||
|
this.maxX = this.minX + this.server.serverGrid.gridSize;
|
||||||
|
this.minY = this.cell.gridY * this.server.serverGrid.gridSize;
|
||||||
|
this.maxY = this.minY + this.server.serverGrid.gridSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue with text arrays and editing jumps on each change.
|
||||||
|
trackByFn(index: any, item: any) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeTreasureLocation(index: number) {
|
||||||
|
this.island.treasureMapSpawnPoints.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeCampLocation(index: number) {
|
||||||
|
this.island.wildPirateCampSpawnPoints.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/app/pages/config/servers/server/server.component.html
Normal file
61
src/app/pages/config/servers/server/server.component.html
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
<div class="mt-3">
|
||||||
|
<h2>{{ cell.name }}<em *ngIf="cell.name === '' || cell.name === undefined">No Name Set</em> - ({{ cell.gridX }}
|
||||||
|
, {{ cell.gridY }})</h2>
|
||||||
|
<ngb-accordion>
|
||||||
|
<ngb-panel title="General Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="name" label="Name" [(text)]="cell.name"
|
||||||
|
help="Friendly name for this server. Can be blank"></app-text>
|
||||||
|
<app-number id="gridX" label="Grid X" [(number)]="cell.gridX"
|
||||||
|
help="X position in the Grid. 0 Indexed"></app-number>
|
||||||
|
<app-number id="gridY" label="Grid Y" [(number)]="cell.gridY"
|
||||||
|
help="Y position in the Grid. 0 Indexed"></app-number>
|
||||||
|
<app-checkbox id="isHomeServer" label="Home Server" [(checkbox)]="cell.isHomeServer"
|
||||||
|
help="Whether this cell can be used for players with no beds"></app-checkbox>
|
||||||
|
<app-number id="utcOffset" label="UTC Offset" [(number)]="cell.utcOffset"
|
||||||
|
help="Cell specific UTC offset"></app-number>
|
||||||
|
<app-select-list id="serverTemplate" label="Template" [optionList]="templateOptions"
|
||||||
|
[withEmptyOption]="true" [(option)]="cell.serverTemplateName"
|
||||||
|
help="Set base Server Template for Common Options"></app-select-list>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Connection Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-text id="ip" label="IP" [(text)]="cell.ip" help="IP address of host this cell is on"></app-text>
|
||||||
|
<app-number id="port" label="Port" [(number)]="cell.port"
|
||||||
|
help="Port used for inter cell communication"></app-number>
|
||||||
|
<app-number id="gamePort" label="Game Port" [(number)]="cell.gamePort"
|
||||||
|
help="Port used for external UE4 traffic"></app-number>
|
||||||
|
<app-number id="seamlessDataPort" label="Seamless Port" [(number)]="cell.seamlessDataPort"
|
||||||
|
help="Used for transferring map images when no MetaWorldURL set"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Gameplay Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="floorZDist" label="Z Floor Height" [(number)]="cell.floorZDist"></app-number>
|
||||||
|
<app-number id="transitionMinZ" label="Minimum Z Transition"
|
||||||
|
[(number)]="cell.transitionMinZ"></app-number>
|
||||||
|
<app-number id="serverIslandPointsMultiplier" label="Island Points Multiplier"
|
||||||
|
[(number)]="cell.serverIslandPointsMultiplier" help="Default 1.0"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Colour & Style Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<app-number id="waterColorR" label="Water Red" [(number)]="cell.waterColorR"></app-number>
|
||||||
|
<app-number id="waterColorG" label="Water Green" [(number)]="cell.waterColorG"></app-number>
|
||||||
|
<app-number id="waterColorB" label="Water Blue" [(number)]="cell.waterColorB"></app-number>
|
||||||
|
<app-number id="skyStyleIndex" label="Sky Style Index" [(number)]="cell.skyStyleIndex"></app-number>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
<ngb-panel title="Island Settings">
|
||||||
|
<ng-template ngbPanelContent>
|
||||||
|
<p><em>Note that Sublevel settings are sorted in the background</em></p>
|
||||||
|
<div *ngFor="let island of cell.islandInstances; let i = index">
|
||||||
|
<h4>Island Instance {{ i }} - ID {{ island.id }} <button class="btn btn-sm btn-primary" [routerLink]="['island', i]">Edit</button></h4>
|
||||||
|
<app-select-object id="{{ i }}-island-name" label="Island Model" [optionObject]="islandOptions"
|
||||||
|
[option]="island.name" (optionChange)="changeIslandModel(i, $event)"></app-select-object>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-panel>
|
||||||
|
</ngb-accordion>
|
||||||
|
</div>
|
||||||
78
src/app/pages/config/servers/server/server.component.ts
Normal file
78
src/app/pages/config/servers/server/server.component.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
import { Server } from "../../../../server";
|
||||||
|
import { ServerModel } from "../../../../models/atlasData/server.model";
|
||||||
|
import { IslandDataModel } from "../../../../../data/models/island-data.model";
|
||||||
|
import { IslandInstanceModel } from "../../../../models/atlasData/island-instance.model";
|
||||||
|
import { ServerSublevelModel } from "../../../../models/atlasData/serverSublevel.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-server',
|
||||||
|
templateUrl: './server.component.html'
|
||||||
|
})
|
||||||
|
export class ServerComponent implements OnInit {
|
||||||
|
private cell: ServerModel;
|
||||||
|
private templateOptions: string[];
|
||||||
|
private islandOptions: object = {};
|
||||||
|
|
||||||
|
constructor(private server: Server, private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
let index = this.route.snapshot.paramMap.get('index');
|
||||||
|
this.cell = this.server.serverGrid.servers[index];
|
||||||
|
this.templateOptions = this.server.serverGrid.serverTemplates.map(i => i.name);
|
||||||
|
Object.values(this.server.islands).forEach((i: IslandDataModel) => this.islandOptions[i.name] = i.customDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private changeIslandModel(index: number, name: string) {
|
||||||
|
let oldIsland = this.cell.islandInstances[index];
|
||||||
|
const newIslandData = this.server.islands[name];
|
||||||
|
const oldIslandData = this.server.islands[oldIsland.name];
|
||||||
|
|
||||||
|
let newIsland = IslandInstanceModel.fromIslandData(newIslandData);
|
||||||
|
|
||||||
|
// keep X, Y and Rotation the same
|
||||||
|
newIsland.worldX = oldIsland.worldX;
|
||||||
|
newIsland.worldY = oldIsland.worldY;
|
||||||
|
newIsland.rotation = oldIsland.rotation;
|
||||||
|
|
||||||
|
// Remove old Sublevels
|
||||||
|
oldIslandData.sublevelNames.forEach(i => {
|
||||||
|
const j = this.cell.sublevels.findIndex(sublevel => sublevel.name === i);
|
||||||
|
if (j > -1) {
|
||||||
|
this.cell.sublevels.splice(j, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get new unique ID
|
||||||
|
newIsland.id = this.server.serverGrid.getNextId();
|
||||||
|
|
||||||
|
// Add new Sublevels
|
||||||
|
newIslandData.sublevelNames.forEach(i => {
|
||||||
|
let newSublevel = new ServerSublevelModel();
|
||||||
|
newSublevel.name = i;
|
||||||
|
newSublevel.setupFromIsland(newIsland, newIslandData, this.cell, this.server.serverGrid);
|
||||||
|
this.cell.sublevels.push(newSublevel);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cell.islandInstances[index] = newIsland;
|
||||||
|
|
||||||
|
this.updateExtraSublevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateExtraSublevels() {
|
||||||
|
// Extra Sublevels can be identical across multiple islands,
|
||||||
|
// so need to merge any changes. Easiest to just merge through
|
||||||
|
// all of the available islands instead.
|
||||||
|
this.cell.totalExtraSublevels = [];
|
||||||
|
this.cell.islandInstances.forEach(i => {
|
||||||
|
const islandData = this.server.islands[i.name];
|
||||||
|
islandData.extraSublevels.forEach(j => {
|
||||||
|
if (this.cell.totalExtraSublevels.indexOf(j) === -1) {
|
||||||
|
this.cell.totalExtraSublevels.push(j);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/app/pages/config/servers/servers.component.html
Normal file
26
src/app/pages/config/servers/servers.component.html
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<div class="mt-3 mb-3">
|
||||||
|
<h2>Cell Grid</h2>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th *ngFor="let x of xArray">{{ x }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody *ngFor="let y of xArray">
|
||||||
|
<tr>
|
||||||
|
<th>{{ y }}</th>
|
||||||
|
<td *ngFor="let x of xArray">
|
||||||
|
<button class="btn btn-sm btn-outline-primary" [routerLink]="['/config','server', serverLookup[x][y]]" *ngIf="serverLookup[x][y] !== undefined">{{ serverLookup[x][y] }}</button>
|
||||||
|
<button class="btn btn-sm btn-outline-danger" (click)="addNewServer(x, y)" *ngIf="serverLookup[x][y] === undefined">+</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h2 *ngIf="unknownServers.length > 0">Cells Outside Grid</h2>
|
||||||
|
<button class="btn btn-warning" *ngFor="let u of unknownServers">{{ u }}</button>
|
||||||
|
<h2>Server Templates</h2>
|
||||||
|
<p>Allows for modifying or applying settings to multiple servers at the same time. Mostly useful for environmental
|
||||||
|
changes, rather than Island position</p>
|
||||||
|
<button class="btn btn-primary" *ngFor="let template of grid.serverTemplates">{{ template.name }}</button>
|
||||||
|
</div>
|
||||||
49
src/app/pages/config/servers/servers.component.ts
Normal file
49
src/app/pages/config/servers/servers.component.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Server } from "../../../server";
|
||||||
|
import { ServerGridModel } from "../../../models/serverGrid.model";
|
||||||
|
import { ServerModel } from "../../../models/atlasData/server.model";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-servers',
|
||||||
|
templateUrl: './servers.component.html'
|
||||||
|
})
|
||||||
|
export class ServersComponent implements OnInit {
|
||||||
|
private grid: ServerGridModel;
|
||||||
|
|
||||||
|
private xArray: number[];
|
||||||
|
private yArray: number[];
|
||||||
|
|
||||||
|
private serverLookup: number[][] = [];
|
||||||
|
private unknownServers: number[] = [];
|
||||||
|
|
||||||
|
constructor(private server: Server, private router: Router) {
|
||||||
|
this.grid = server.serverGrid;
|
||||||
|
this.xArray = Array.from(Array(this.grid.totalGridsX).keys());
|
||||||
|
this.yArray = Array.from(Array(this.grid.totalGridsY).keys());
|
||||||
|
|
||||||
|
// Initialise the serverLookup with x at least
|
||||||
|
this.xArray.forEach(i => this.serverLookup[i] = []);
|
||||||
|
|
||||||
|
this.grid.servers.forEach((i, index) => {
|
||||||
|
if (i.gridX < this.grid.totalGridsX && i.gridY < this.grid.totalGridsY) {
|
||||||
|
if (this.serverLookup[i.gridX] === undefined)
|
||||||
|
this.serverLookup[i.gridX] = [];
|
||||||
|
this.serverLookup[i.gridX][i.gridY] = index;
|
||||||
|
} else {
|
||||||
|
this.unknownServers.push(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private addNewServer(x: number, y: number) {
|
||||||
|
let newServer = new ServerModel();
|
||||||
|
newServer.gridX = x;
|
||||||
|
newServer.gridY = y;
|
||||||
|
const newLength = this.grid.servers.push(newServer);
|
||||||
|
return this.router.navigate(['/config', 'server', newLength - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<p>template works!</p>
|
||||||
14
src/app/pages/config/servers/template/template.component.ts
Normal file
14
src/app/pages/config/servers/template/template.component.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-template',
|
||||||
|
templateUrl: './template.component.html'
|
||||||
|
})
|
||||||
|
export class TemplateComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
8
src/app/pages/raw-editor/raw-editor.component.html
Normal file
8
src/app/pages/raw-editor/raw-editor.component.html
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h2>Raw Editor</h2>
|
||||||
|
<textarea [(ngModel)]="rawData" rows="20" style="width: 100%"></textarea>
|
||||||
|
<button (click)="loadData()">Load from JSON</button>
|
||||||
|
<button (click)="saveData()">Save to JSON</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
21
src/app/pages/raw-editor/raw-editor.component.ts
Normal file
21
src/app/pages/raw-editor/raw-editor.component.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { Server } from "../../server";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./raw-editor.component.html",
|
||||||
|
})
|
||||||
|
export class RawEditorComponent {
|
||||||
|
rawData = "{}";
|
||||||
|
|
||||||
|
constructor(private server: Server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadData() {
|
||||||
|
this.server.load(this.rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveData() {
|
||||||
|
this.rawData = this.server.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/app/server.ts
Normal file
34
src/app/server.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ServerGridModel } from "./models/serverGrid.model";
|
||||||
|
import * as islandData from '../data/islands.json';
|
||||||
|
import { IslandDataModel } from "../data/models/island-data.model";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class Server {
|
||||||
|
private rawData: string = "";
|
||||||
|
private jsonData: object = {};
|
||||||
|
public serverGrid: ServerGridModel = new ServerGridModel();
|
||||||
|
public islands;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.islands = (islandData as any).default;
|
||||||
|
Object.keys(this.islands).forEach(i => {
|
||||||
|
this.islands[i] = new IslandDataModel().deserialize(this.islands[i])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public load(raw) {
|
||||||
|
this.rawData = raw;
|
||||||
|
try {
|
||||||
|
this.jsonData = JSON.parse(this.rawData);
|
||||||
|
this.serverGrid = new ServerGridModel().deserialize(this.jsonData);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public save() {
|
||||||
|
this.rawData = JSON.stringify(this.serverGrid, null, 2);
|
||||||
|
return this.rawData;
|
||||||
|
}
|
||||||
|
}
|
||||||
1624
src/app/services/atlas.pegjs.ts
Normal file
1624
src/app/services/atlas.pegjs.ts
Normal file
File diff suppressed because it is too large
Load diff
137
src/app/services/pegjs.service.ts
Normal file
137
src/app/services/pegjs.service.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { parse } from './atlas.pegjs';
|
||||||
|
|
||||||
|
const beginObject = '(';
|
||||||
|
const endObject = ')';
|
||||||
|
const nameSeparator = '=';
|
||||||
|
const valueSeparator = ',';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class PegjsService {
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
public static parse(input: string): object {
|
||||||
|
let output = {};
|
||||||
|
try {
|
||||||
|
output = parse(input);
|
||||||
|
} catch (e) {
|
||||||
|
// TODO put a popover somewhere with a location of the error
|
||||||
|
console.log(e);
|
||||||
|
console.log(e.location);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static format(input: object, skipCurrentObject?: boolean): string {
|
||||||
|
return PegjsService.deparseJson(input, undefined, skipCurrentObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static deparseJson(input, key?, skip?: boolean) {
|
||||||
|
// Call possible toJSON on object
|
||||||
|
if(!skip && typeof input === 'object' && typeof input.toJSON === 'function') {
|
||||||
|
input = input.toJSON();
|
||||||
|
}
|
||||||
|
switch (typeof input) {
|
||||||
|
case "object":
|
||||||
|
return PegjsService.deparseObject(input);
|
||||||
|
case "number":
|
||||||
|
return PegjsService.deparseNumber(input, key);
|
||||||
|
case "string":
|
||||||
|
return PegjsService.deparseString(input);
|
||||||
|
case "undefined":
|
||||||
|
return "";
|
||||||
|
case "boolean":
|
||||||
|
return PegjsService.deparseBoolean(input);
|
||||||
|
default:
|
||||||
|
console.log("Unknown type for input", input);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static deparseObject(input) {
|
||||||
|
if (Array.isArray(input)) {
|
||||||
|
return this.deparseArray(input);
|
||||||
|
}
|
||||||
|
if (input === null) {
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = '';
|
||||||
|
output += beginObject;
|
||||||
|
|
||||||
|
Object.keys(input).forEach(function (key, idx, array) {
|
||||||
|
output += key;
|
||||||
|
output += nameSeparator;
|
||||||
|
output += PegjsService.deparseJson(input[key], key);
|
||||||
|
|
||||||
|
if (idx !== array.length - 1) {
|
||||||
|
// Not the last item
|
||||||
|
output += valueSeparator
|
||||||
|
}
|
||||||
|
});
|
||||||
|
output += endObject;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static deparseArray(input) {
|
||||||
|
// We have one funky array option, where its 2 values and one of them is a recognised class.
|
||||||
|
// These are here for easier maintenance, as adding any new ones should just work. These all
|
||||||
|
// Work off string equality, see found below.
|
||||||
|
const specialCases = [
|
||||||
|
'BlueprintGeneratedClass',
|
||||||
|
'Blueprint',
|
||||||
|
'SoundWave',
|
||||||
|
'Texture2D'
|
||||||
|
];
|
||||||
|
|
||||||
|
const found = specialCases.indexOf(input[0]);
|
||||||
|
if (found > -1) {
|
||||||
|
// We found one of our special cases!
|
||||||
|
const val = specialCases[found];
|
||||||
|
return val + "'" + input[1] + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = '';
|
||||||
|
output += beginObject;
|
||||||
|
|
||||||
|
input.forEach(function (data, idx, array) {
|
||||||
|
output += PegjsService.deparseJson(data);
|
||||||
|
|
||||||
|
if (idx !== array.length - 1) {
|
||||||
|
output += valueSeparator;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
output += endObject;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static deparseNumber(input, key) {
|
||||||
|
// Any number which has a decimal is stored to 6 decimal places
|
||||||
|
// Except for IDs. Unless they actually have such a number... erm...
|
||||||
|
if (key.substr(key.length - 2, 2) === "ID") {
|
||||||
|
if (input % 1 === 0) {
|
||||||
|
return Number(input).toString();
|
||||||
|
}
|
||||||
|
// Else drop out and return as normal
|
||||||
|
}
|
||||||
|
return Number(input).toFixed(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static deparseString(input) {
|
||||||
|
// We need to re-encode the strings properly
|
||||||
|
return JSON.stringify(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static deparseBoolean(input) {
|
||||||
|
if ( input ) {
|
||||||
|
return 'True';
|
||||||
|
} else {
|
||||||
|
return 'False';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/assets/.gitkeep
Normal file
0
src/assets/.gitkeep
Normal file
21199
src/data/islands.json
Normal file
21199
src/data/islands.json
Normal file
File diff suppressed because it is too large
Load diff
75
src/data/models/island-data.model.ts
Normal file
75
src/data/models/island-data.model.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { Deserialize } from "../../app/models/util/deserialize.model";
|
||||||
|
import { IslandInstanceModel } from "../../app/models/atlasData/island-instance.model";
|
||||||
|
|
||||||
|
export class IslandDataModel implements Deserialize {
|
||||||
|
name: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
imagePath: string;
|
||||||
|
landscapeMaterialOverride: number;
|
||||||
|
sublevelNames: string[];
|
||||||
|
spawnerOverrides: object;
|
||||||
|
extraSublevels: string[];
|
||||||
|
treasureMapSpawnPoints: string[];
|
||||||
|
wildPirateCampSpawnPoints: string[];
|
||||||
|
minTreasureQuality: number;
|
||||||
|
maxTreasureQuality: number;
|
||||||
|
useNpcVolumesForTreasures: boolean;
|
||||||
|
useLevelBoundsForTreasures: boolean;
|
||||||
|
prioritizeVolumesForTreasures: boolean;
|
||||||
|
islandTreasureBottleSupplyCrateOverrides: string;
|
||||||
|
islandPoints: number;
|
||||||
|
singleSpawnPointX: number;
|
||||||
|
singleSpawnPointY: number;
|
||||||
|
singleSpawnPointZ: number;
|
||||||
|
|
||||||
|
// De-parsed from the name
|
||||||
|
islandType: string;
|
||||||
|
islandShape: string;
|
||||||
|
climate: string;
|
||||||
|
variant: string;
|
||||||
|
|
||||||
|
private _climateLookup = {
|
||||||
|
CH: "High Desert",
|
||||||
|
CL: "Low Desert",
|
||||||
|
CP: "Polar",
|
||||||
|
EE: "Equatorial",
|
||||||
|
ET: "Eastern Temperate",
|
||||||
|
PO: "Polar",
|
||||||
|
TR: "Tropical",
|
||||||
|
WF: "West Temperate",
|
||||||
|
WR: "West Tropical",
|
||||||
|
WT: "West Temperate",
|
||||||
|
WU: "West Tundra",
|
||||||
|
ER: "East Tropical",
|
||||||
|
EU: "East Tundra",
|
||||||
|
BO: "Tropical",
|
||||||
|
CU: "Central Tundra"
|
||||||
|
};
|
||||||
|
|
||||||
|
private _variantLookup = {
|
||||||
|
E: 'Freeport',
|
||||||
|
PVE: 'Event'
|
||||||
|
};
|
||||||
|
|
||||||
|
deserialize(input: any): this {
|
||||||
|
Object.assign(this, input);
|
||||||
|
|
||||||
|
const parsedName = this.name.split('_');
|
||||||
|
|
||||||
|
this.islandType = parsedName[0];
|
||||||
|
this.islandShape = parsedName[1];
|
||||||
|
this.climate = this._climateLookup[parsedName[2]];
|
||||||
|
this.variant = parsedName[3] === undefined
|
||||||
|
? 'Original'
|
||||||
|
: this._variantLookup[parsedName[3]] === undefined
|
||||||
|
? parsedName[3]
|
||||||
|
: this._variantLookup[parsedName[3]];
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
customDisplayName(): string {
|
||||||
|
return `${this.islandType} (${this.islandShape}) - ${this.climate} (${this.variant})`
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/environments/environment.prod.ts
Normal file
3
src/environments/environment.prod.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const environment = {
|
||||||
|
production: true
|
||||||
|
};
|
||||||
16
src/environments/environment.ts
Normal file
16
src/environments/environment.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// This file can be replaced during build by using the `fileReplacements` array.
|
||||||
|
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||||
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
production: false
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For easier debugging in development mode, you can import the following file
|
||||||
|
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||||
|
*
|
||||||
|
* This import should be commented out in production mode because it will have a negative impact
|
||||||
|
* on performance if an error is thrown.
|
||||||
|
*/
|
||||||
|
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||||
BIN
src/favicon.ico
Normal file
BIN
src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 948 B |
13
src/index.html
Normal file
13
src/index.html
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>AtlasConfigGenerator</title>
|
||||||
|
<base href="/">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
12
src/main.ts
Normal file
12
src/main.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch(err => console.error(err));
|
||||||
63
src/polyfills.ts
Normal file
63
src/polyfills.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||||
|
* You can add your own extra polyfills to this file.
|
||||||
|
*
|
||||||
|
* This file is divided into 2 sections:
|
||||||
|
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||||
|
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||||
|
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||||
|
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||||
|
*
|
||||||
|
* Learn more in https://angular.io/guide/browser-support
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* BROWSER POLYFILLS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||||
|
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web Animations `@angular/platform-browser/animations`
|
||||||
|
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||||
|
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||||
|
*/
|
||||||
|
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||||
|
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||||
|
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||||
|
* will put import in the top of bundle, so user need to create a separate file
|
||||||
|
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||||
|
* into that file, and then add the following code before importing zone.js.
|
||||||
|
* import './zone-flags.ts';
|
||||||
|
*
|
||||||
|
* The flags allowed in zone-flags.ts are listed here.
|
||||||
|
*
|
||||||
|
* The following flags will work for all browsers.
|
||||||
|
*
|
||||||
|
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||||
|
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||||
|
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||||
|
*
|
||||||
|
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||||
|
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||||
|
*
|
||||||
|
* (window as any).__Zone_enable_cross_context_check = true;
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Zone JS is required by default for Angular itself.
|
||||||
|
*/
|
||||||
|
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* APPLICATION IMPORTS
|
||||||
|
*/
|
||||||
170203
src/serverGridExample.json
Normal file
170203
src/serverGridExample.json
Normal file
File diff suppressed because one or more lines are too long
2
src/styles.scss
Normal file
2
src/styles.scss
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
@import "../node_modules/bootstrap/scss/bootstrap";
|
||||||
20
src/test.ts
Normal file
20
src/test.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'zone.js/dist/zone-testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
declare const require: any;
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
// Then we find all the tests.
|
||||||
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
// And load the modules.
|
||||||
|
context.keys().map(context);
|
||||||
18
tsconfig.app.json
Normal file
18
tsconfig.app.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts",
|
||||||
|
"src/polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/test.ts",
|
||||||
|
"src/**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "es2015",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es2018",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"fullTemplateTypeCheck": true,
|
||||||
|
"strictInjectionParameters": true
|
||||||
|
}
|
||||||
|
}
|
||||||
18
tsconfig.spec.json
Normal file
18
tsconfig.spec.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts",
|
||||||
|
"src/polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
91
tslint.json
Normal file
91
tslint.json
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
"extends": "tslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"array-type": false,
|
||||||
|
"arrow-parens": false,
|
||||||
|
"deprecation": {
|
||||||
|
"severity": "warning"
|
||||||
|
},
|
||||||
|
"component-class-suffix": true,
|
||||||
|
"contextual-lifecycle": true,
|
||||||
|
"directive-class-suffix": true,
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
"app",
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
"app",
|
||||||
|
"kebab-case"
|
||||||
|
],
|
||||||
|
"import-blacklist": [
|
||||||
|
true,
|
||||||
|
"rxjs/Rx"
|
||||||
|
],
|
||||||
|
"interface-name": false,
|
||||||
|
"max-classes-per-file": false,
|
||||||
|
"max-line-length": [
|
||||||
|
true,
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"member-access": false,
|
||||||
|
"member-ordering": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"order": [
|
||||||
|
"static-field",
|
||||||
|
"instance-field",
|
||||||
|
"static-method",
|
||||||
|
"instance-method"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-consecutive-blank-lines": false,
|
||||||
|
"no-console": [
|
||||||
|
true,
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"time",
|
||||||
|
"timeEnd",
|
||||||
|
"trace"
|
||||||
|
],
|
||||||
|
"no-empty": false,
|
||||||
|
"no-inferrable-types": [
|
||||||
|
true,
|
||||||
|
"ignore-params"
|
||||||
|
],
|
||||||
|
"no-non-null-assertion": true,
|
||||||
|
"no-redundant-jsdoc": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-var-requires": false,
|
||||||
|
"object-literal-key-quotes": [
|
||||||
|
true,
|
||||||
|
"as-needed"
|
||||||
|
],
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"ordered-imports": false,
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"trailing-comma": false,
|
||||||
|
"no-conflicting-lifecycle": true,
|
||||||
|
"no-host-metadata-property": true,
|
||||||
|
"no-input-rename": true,
|
||||||
|
"no-inputs-metadata-property": true,
|
||||||
|
"no-output-native": true,
|
||||||
|
"no-output-on-prefix": true,
|
||||||
|
"no-output-rename": true,
|
||||||
|
"no-outputs-metadata-property": true,
|
||||||
|
"template-banana-in-box": true,
|
||||||
|
"template-no-negated-async": true,
|
||||||
|
"use-lifecycle-interface": true,
|
||||||
|
"use-pipe-transform-interface": true
|
||||||
|
},
|
||||||
|
"rulesDirectory": [
|
||||||
|
"codelyzer"
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue