feat: game strings context

This commit is contained in:
TrèsAbhi committed 2025-05-29 20:22:13 -05:00
1 parent 9bf1554c30
commit 1eca71d28c
21 files changed
+208 -137

No files matched your search

-2
View File
@@ -19,8 +19,6 @@ export * from './idToRegion';
export * from './isOnGoingRatingSeason';
export * from './isValidBlitzId';
export * from './metadata';
export * from './metadata.remote';
export * from './metadata.socket';
export * from './nations';
export * from './normalizeExtra';
export * from './normalizeIds';
-35
View File
@@ -1,35 +0,0 @@
import { BlitzkitAllAvatarsComponent } from '@protos/blitzkit_static_all_avatars_component';
import { CatalogItemAccessor } from './catalogItemAccessor';
export abstract class MetadataAccessor {
abstract get(item: string): Promise<CatalogItemAccessor>;
abstract add(item: CatalogItemAccessor): void;
abstract filter(predicate: (item: string) => boolean): CatalogItemAccessor[];
injectBlitzkit() {
this.injectBlitzkitProfileAvatars();
return this;
}
injectBlitzkitProfileAvatars() {
const allAvatars: BlitzkitAllAvatarsComponent = {
avatars: this.filter((item) =>
item.startsWith('ProfileAvatarEntity.'),
).map((avatar) => avatar.pack()),
};
this.add(
CatalogItemAccessor.fromComponent(
'BlitzkitAllAvatarsEntity.blitzkit_all_avatars',
{
type_url:
'./blitzkit_static_all_avatars_component.BlitzkitAllAvatarsComponent',
value: BlitzkitAllAvatarsComponent.encode(allAvatars).finish(),
},
),
);
}
}
@@ -0,0 +1,113 @@
import { LocalizationResourcesComponent } from '@protos/blitz_static_localization_resources_component';
import { RemoteStorageComponent } from '@protos/blitz_static_remote_storage_component';
import { BlitzkitAllAvatarsComponent } from '@protos/blitzkit_static_all_avatars_component';
import { load } from 'js-yaml';
import { minimatch } from 'minimatch';
import { CatalogItemAccessor } from '../catalogItemAccessor';
interface LocalizationConfig {
namespaces: string[];
}
export abstract class MetadataAccessor {
abstract get(item: string): Promise<CatalogItemAccessor>;
abstract add(item: CatalogItemAccessor): void;
abstract filter(predicate: (item: string) => boolean): CatalogItemAccessor[];
async strings(locale: string) {
const clientConfig = await this.get(
'ClientConfigsEntity.default_client_config',
);
const localizationResources = clientConfig.get(
LocalizationResourcesComponent,
'localizationResourcesComponent',
);
if (!localizationResources.remote_storage) {
throw new Error('Localization resources not found');
}
const { relative_path } = localizationResources.remote_storage;
let remoteStorage: RemoteStorageComponent | undefined = undefined;
for (const candidateId of localizationResources.remote_storage.production) {
const item = await this.get(candidateId);
const candidate = item.get(
RemoteStorageComponent,
'remoteStorageComponent',
);
if (
remoteStorage === undefined ||
candidate.download_speed_weight > remoteStorage.download_speed_weight
) {
remoteStorage = candidate;
}
}
if (remoteStorage === undefined) {
throw new Error('No suitable production remote storage found');
}
const config = await fetch(
`${remoteStorage.url}/${relative_path}/config.yaml`,
)
.then((response) => response.text())
.then((text) => load(text) as LocalizationConfig);
const strings: Record<string, string> = {};
for (const namespace of config.namespaces) {
Object.assign(
strings,
await fetch(
`${remoteStorage.url}/${relative_path}/${namespace}/${locale}.yaml`,
)
.then((response) => response.text())
.then((text) => load(text) as Record<string, string>),
);
}
return strings;
}
async stringsPartial(locale: string, patterns: string[]) {
const strings = await this.strings(locale);
const filtered: Record<string, string> = {};
for (const key in strings) {
if (patterns.some((pattern) => minimatch(key, pattern))) {
filtered[key] = strings[key];
}
}
return filtered;
}
injectBlitzkit() {
this.injectBlitzkitProfileAvatars();
return this;
}
injectBlitzkitProfileAvatars() {
const allAvatars: BlitzkitAllAvatarsComponent = {
avatars: this.filter((item) =>
item.startsWith('ProfileAvatarEntity.'),
).map((avatar) => avatar.pack()),
};
this.add(
CatalogItemAccessor.fromComponent(
'BlitzkitAllAvatarsEntity.blitzkit_all_avatars',
{
type_url:
'./blitzkit_static_all_avatars_component.BlitzkitAllAvatarsComponent',
value: BlitzkitAllAvatarsComponent.encode(allAvatars).finish(),
},
),
);
}
}
@@ -0,0 +1,3 @@
export * from './abstract';
export * from './remote';
export * from './socket';
@@ -1,6 +1,6 @@
import { CatalogItem } from '@protos/blitz_items';
import { CatalogItemAccessor } from './catalogItemAccessor';
import { MetadataAccessor } from './metadata';
import { CatalogItemAccessor } from '../catalogItemAccessor';
import { MetadataAccessor } from './abstract';
export class RemoteMetadataAccessor extends MetadataAccessor {
constructor(private base: string) {
@@ -1,7 +1,7 @@
import { CatalogItem } from '@protos/blitz_items';
import { Metadata } from '@protos/blitz_metadata';
import { CatalogItemAccessor } from './catalogItemAccessor';
import { MetadataAccessor } from './metadata';
import { CatalogItemAccessor } from '../catalogItemAccessor';
import { MetadataAccessor } from './abstract';
export class SocketMetadataAccessor extends MetadataAccessor {
items: Record<string, CatalogItem> = {};
@@ -16,6 +16,7 @@ export class SocketMetadataAccessor extends MetadataAccessor {
async get(item: string) {
if (item in this.items) return new CatalogItemAccessor(this.items[item]);
throw new Error(`Item ${item} does not exist in socket metadata`);
}