2025-11-28 13:51:17 -06:00
|
|
|
import type { MetadataAccessor } from "@blitzkit/closed";
|
2025-11-28 14:13:03 -06:00
|
|
|
import { sluggify } from "@blitzkit/core";
|
|
|
|
|
import type { RemoteStorageComponent } from "@protos/blitz_static_remote_storage_component";
|
|
|
|
|
import { parse } from "yaml";
|
2025-11-28 13:51:17 -06:00
|
|
|
import type { TanksEntry } from "../../protos/tanks";
|
|
|
|
|
import { AbstractAPI } from "./abstract";
|
|
|
|
|
|
2025-11-28 14:13:03 -06:00
|
|
|
interface LocalizationConfig {
|
|
|
|
|
namespaces: string[];
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 13:51:17 -06:00
|
|
|
export class ServerAPI extends AbstractAPI {
|
|
|
|
|
constructor(private metadata: MetadataAccessor) {
|
|
|
|
|
super();
|
2025-11-28 14:13:03 -06:00
|
|
|
}
|
2025-11-28 13:51:17 -06:00
|
|
|
|
2025-11-28 14:13:03 -06:00
|
|
|
async strings(locale: string) {
|
|
|
|
|
const clientConfig = this.metadata.item("ClientConfigsEntity.prod");
|
|
|
|
|
const localizationResources = clientConfig.LocalizationResources();
|
|
|
|
|
|
|
|
|
|
if (!localizationResources.remote_storage) {
|
|
|
|
|
throw new Error("Localization resources not found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
|
|
|
|
|
|
|
|
|
for (const candidateId of localizationResources.remote_storage
|
|
|
|
|
.remote_urls) {
|
|
|
|
|
const item = this.metadata.item(candidateId);
|
|
|
|
|
const candidate = item.RemoteStorage();
|
|
|
|
|
|
|
|
|
|
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}/${remoteStorage.relative_path}/config.yaml`
|
|
|
|
|
)
|
|
|
|
|
.then((response) => response.text())
|
|
|
|
|
.then((text) => parse(text) as LocalizationConfig);
|
|
|
|
|
const strings: Record<string, string> = {};
|
|
|
|
|
|
|
|
|
|
for (const namespace of config.namespaces) {
|
|
|
|
|
Object.assign(
|
|
|
|
|
strings,
|
|
|
|
|
await fetch(
|
|
|
|
|
`${remoteStorage.url}/${remoteStorage.relative_path}/${namespace}/${locale}.yaml`
|
|
|
|
|
)
|
|
|
|
|
.then((response) => response.text())
|
|
|
|
|
.then((text) => {
|
|
|
|
|
const strings: Record<string, string> = {};
|
|
|
|
|
const parsed = parse(text) as Record<string, string>;
|
|
|
|
|
|
|
|
|
|
for (const key in parsed) {
|
|
|
|
|
strings[key] = parsed[key].replaceAll('\\"', '"');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strings;
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strings;
|
2025-11-28 13:51:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async tanks() {
|
|
|
|
|
const group = this.metadata.group("TankEntity");
|
|
|
|
|
const tanks: TanksEntry[] = [];
|
2025-11-28 14:13:03 -06:00
|
|
|
const strings = await this.strings("en");
|
2025-11-28 13:51:17 -06:00
|
|
|
|
|
|
|
|
for (const item of group) {
|
|
|
|
|
const tankCatalog = item.TankCatalog();
|
2025-11-28 14:13:03 -06:00
|
|
|
const name = strings[tankCatalog.name!.value];
|
2025-11-28 13:51:17 -06:00
|
|
|
|
2025-11-28 14:13:03 -06:00
|
|
|
const id = item.name;
|
|
|
|
|
const slug = sluggify(name);
|
2025-11-28 13:51:17 -06:00
|
|
|
|
|
|
|
|
tanks.push({ id, slug });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { tanks };
|
|
|
|
|
}
|
|
|
|
|
}
|