Move to Renderer V2

This commit is contained in:
duckietm
2024-04-03 09:27:56 +02:00
parent 110c3ad393
commit b3134ce50b
4080 changed files with 115593 additions and 66375 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"extends": [ "@nitrots/eslint-config" ]
}
+51
View File
@@ -0,0 +1,51 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# 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
.git
# System Files
.DS_Store
Thumbs.db
*.zip
*.as
*.bin
+1
View File
@@ -0,0 +1 @@
export * from './src';
+23
View File
@@ -0,0 +1,23 @@
{
"name": "@nitrots/localization",
"description": "Nitro localization module",
"version": "1.0.0",
"type": "module",
"license": "GPL-3.0",
"scripts": {
"compile": "tsc --project ./tsconfig.json --noEmit false",
"eslint": "eslint ./src --fix"
},
"main": "./index",
"dependencies": {
"@nitrots/api": "1.0.0",
"@nitrots/communication": "1.0.0",
"@nitrots/configuration": "1.0.0",
"@nitrots/eslint-config": "1.0.0",
"@nitrots/events": "1.0.0",
"pixi.js": "^8.0.4"
},
"devDependencies": {
"typescript": "~5.4.2"
}
}
@@ -0,0 +1,53 @@
export class BadgeBaseAndLevel
{
private _badgeId: string = '';
private _level: number = 1;
private _base: string = '';
constructor(badgeId: string)
{
this._badgeId = badgeId;
this.parseText();
}
private parseText():void
{
let length = (this._badgeId.length - 1);
while(length > 0 && this.isNumber(this._badgeId.charAt(length))) length--;
this._base = this._badgeId.substr(0, (length + 1));
const level = this._badgeId.substr((length + 1), this._badgeId.length);
if(level && (level !== '')) this._level = Number.parseInt(level);
}
private isNumber(text: string): boolean
{
const char = text.charCodeAt(0);
return (char >= 48 && char <= 57);
}
public get level(): number
{
return this._level;
}
public set level(k : number)
{
this._level = Math.max(1, k);
}
public get getBadgeId(): string
{
return this._base + this._level;
}
public get base(): string
{
return this._base;
}
}
@@ -0,0 +1,5 @@
import { LocalizationManager } from './LocalizationManager';
const localization = new LocalizationManager();
export const GetLocalizationManager = () => localization;
@@ -0,0 +1,304 @@
import { ILocalizationManager } from '@nitrots/api';
import { BadgePointLimitsEvent, GetCommunication } from '@nitrots/communication';
import { GetConfiguration } from '@nitrots/configuration';
import { BadgeBaseAndLevel } from './BadgeBaseAndLevel';
export class LocalizationManager implements ILocalizationManager
{
private _definitions: Map<string, string> = new Map();
private _parameters: Map<string, Map<string, string>> = new Map();
private _badgePointLimits: Map<string, number> = new Map();
private _romanNumerals: string[] = [ 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX' ];
public async init(): Promise<void>
{
try
{
const urls = GetConfiguration().getValue<string[]>('external.texts.url').slice();
if(!urls || !urls.length) throw new Error('Invalid localization urls');
for(let url of urls)
{
if(!url || !url.length) return;
url = GetConfiguration().interpolate(url);
const response = await fetch(url);
if(response.status !== 200) throw new Error('Invalid localization file');
this.parseLocalization(await response.json());
}
GetCommunication().registerMessageEvent(new BadgePointLimitsEvent(this.onBadgePointLimitsEvent.bind(this)));
}
catch (err)
{
throw new Error(err);
}
}
private parseLocalization(data: { [index: string]: any }): boolean
{
if(!data) return false;
for(const key in data) this._definitions.set(key, data[key]);
return true;
}
private onBadgePointLimitsEvent(event: BadgePointLimitsEvent): void
{
const parser = event.getParser();
for(const data of parser.data) this.setBadgePointLimit(data.badgeId, data.limit);
}
public getBadgePointLimit(badge: string): number
{
return (this._badgePointLimits.get(badge) || -1);
}
public setBadgePointLimit(badge: string, point: number): void
{
this._badgePointLimits.set(badge, point);
}
public getRomanNumeral(number: number): string
{
return this._romanNumerals[Math.max(0, (number - 1))];
}
public getPreviousLevelBadgeId(badgeName: string): string
{
const badge = new BadgeBaseAndLevel(badgeName);
badge.level--;
return badge.getBadgeId;
}
public hasValue(key: string): boolean
{
return this._definitions.has(key);
}
public getValue(key: string, doParams: boolean = true): string
{
if(!key || !key.length) return null;
const keys = key.match(/\$\{.[^}]*\}/g);
if(keys && keys.length)
{
for(const splitKey of keys) key = key.replace(splitKey, this.getValue(splitKey.slice(2, -1), doParams));
}
let value = (this._definitions.get(key) || null);
if(!value)
{
value = (GetConfiguration().definitions.get(key) as any);
if(value) return value;
}
if(value && doParams)
{
const parameters = this._parameters.get(key);
if(parameters)
{
for(const [parameter, replacement] of parameters)
{
value = value.replace('%' + parameter + '%', replacement);
}
}
}
return (value || key);
}
public getValueWithParameter(key: string, parameter: string, replacement: string): string
{
const value = this.getValue(key, false);
const replacedValue = value.replace('%' + parameter + '%', replacement);
if(value.startsWith('%{'))
{
// This adds support for multi-optioned texts like
// catalog.vip.item.header.months=%{NUM_MONTHS|0 months|1 month|%% months}
// It only checks for this multi-optioned thext if the value of the key starts with %{
// If it does, it will create a RegEx with the provided parameter, eg. NUM_DAYS or NUM_MONTS
// Then, based on the provided replacement it searches for the resultgroup based on the replacement.
// If the replacement is not either 0, 1 - it will be assumed it will be plural. (eg. Months)
const regex = new RegExp('%{' + parameter.toUpperCase() + '\\|([^|]*)\\|([^|]*)\\|([^|]*)}');
const result = value.match(regex);
if(!result) return replacedValue;
let indexKey = -1;
const replacementAsNumber = Number.parseInt(replacement);
let replace = false;
switch(replacementAsNumber)
{
case 0:
indexKey = 1;
break;
case 1:
indexKey = 2;
break;
default:
case 2:
indexKey = 3;
replace = true;
break;
}
if(indexKey == -1 || typeof result[indexKey] == 'undefined')
{
return replacedValue;
}
const valueFromResults = result[indexKey];
if(valueFromResults)
{
return valueFromResults.replace('%%', replacement);
}
}
return replacedValue;
}
public getValueWithParameters(key: string, parameters: string[], replacements: string[]): string
{
let value = this.getValue(key, false);
if(parameters)
{
for(let i = 0; i < parameters.length; i++)
{
const parameter = parameters[i];
const replacement = replacements[i];
if(replacement === undefined) continue;
value = value.replace('%' + parameter + '%', replacement);
if(value.startsWith('%{'))
{
const regex = new RegExp('%{' + parameter.toUpperCase() + '\\|([^|]*)\\|([^|]*)\\|([^|]*)}');
const result = value.match(regex);
if(!result) continue;
const replacementAsNumber = parseInt(replacement);
let indexKey = -1;
let replace = false;
switch(replacementAsNumber)
{
case 0:
indexKey = 1;
break;
case 1:
indexKey = 2;
break;
case 2:
default:
indexKey = 3;
replace = true;
break;
}
if((indexKey === -1) || (typeof result[indexKey] === 'undefined')) continue;
const valueFromResults = result[indexKey];
if(valueFromResults)
{
value = valueFromResults.replace('%%', replacement);
}
}
}
}
return value;
}
public setValue(key: string, value: string): void
{
this._definitions.set(key, value);
}
public registerParameter(key: string, parameter: string, value: string): void
{
if(!key || (key.length === 0) || !parameter || (parameter.length === 0)) return;
let existing = this._parameters.get(key);
if(!existing)
{
existing = new Map();
this._parameters.set(key, existing);
}
existing.set(parameter, value);
}
public getBadgeName(key: string): string
{
const badge = new BadgeBaseAndLevel(key);
const keys = ['badge_name_' + key, 'badge_name_' + badge.base];
let name = this.fixBadLocalization(this.getExistingKey(keys));
name = name.replace('%roman%', this.getRomanNumeral(badge.level));
return name;
}
public getBadgeDesc(key: string): string
{
const badge = new BadgeBaseAndLevel(key);
const keys = ['badge_desc_' + key, 'badge_desc_' + badge.base];
let desc = this.fixBadLocalization(this.getExistingKey(keys));
const limit = this.getBadgePointLimit(key);
if(limit > -1) desc = desc.replace('%limit%', limit.toString());
desc = desc.replace('%roman%', this.getRomanNumeral(badge.level));
return desc;
}
private getExistingKey(keys: string[]): string
{
for(const entry of keys)
{
const item = this.getValue(entry);
if(item != entry) return item;
}
return '';
}
private fixBadLocalization(k: string): string
{
return k.replace('${', '$')
.replace('{', '$')
.replace('}', '$');
}
}
+3
View File
@@ -0,0 +1,3 @@
export * from './BadgeBaseAndLevel';
export * from './GetLocalization';
export * from './LocalizationManager';
+31
View File
@@ -0,0 +1,31 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./src",
"outDir": "./dist",
"sourceMap": false,
"declaration": true,
"experimentalDecorators": true,
"moduleResolution": "Node",
"esModuleInterop": true,
"importHelpers": true,
"isolatedModules": true,
"resolveJsonModule": true,
"downlevelIteration": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"skipLibCheck": true,
"noEmit": true,
"strict": false,
"strictNullChecks": false,
"target": "ES6",
"lib": [
"DOM",
"DOM.Iterable",
"ESNext"
],
"module": "ES6"
},
"include": [
"src" ]
}