mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: use decorators
This commit is contained in:
1 parent
44711a58c7
commit
8e3b5de249
5 files changed
+278
-316
No files matched your search
@@ -13,16 +13,23 @@ import type { Tanks } from "../../protos/tanks";
|
||||
export abstract class AbstractAPI {
|
||||
abstract tankList(): Promise<TankList>;
|
||||
abstract tank(id: string): Promise<Tank>;
|
||||
abstract tanks(): Promise<Tanks>;
|
||||
abstract popularTanks(): Promise<PopularTanks>;
|
||||
|
||||
private _tanksCache: Tanks | undefined;
|
||||
protected abstract _tanks(): Promise<Tanks>;
|
||||
async tanks() {
|
||||
if (this._tanksCache === undefined) {
|
||||
this._tanksCache = await this._tanks();
|
||||
}
|
||||
abstract strings(locale: string): Promise<Strings>;
|
||||
abstract gameStrings(locale: string): Promise<Record<string, string>>;
|
||||
protected abstract _groupedGameStrings(
|
||||
locale: string,
|
||||
group: string,
|
||||
): Promise<Record<string, string>>;
|
||||
abstract gameStringGroups(): Promise<string[]>;
|
||||
|
||||
return this._tanksCache;
|
||||
}
|
||||
abstract avatar(id: string): Promise<Avatar>;
|
||||
abstract avatars(): Promise<Avatars>;
|
||||
abstract avatarList(): Promise<AvatarList>;
|
||||
|
||||
abstract background(id: string): Promise<Background>;
|
||||
abstract backgrounds(): Promise<Backgrounds>;
|
||||
|
||||
private assertLocale(locale: string) {
|
||||
const supported = locales.supported.find(
|
||||
@@ -36,137 +43,26 @@ export abstract class AbstractAPI {
|
||||
return supported;
|
||||
}
|
||||
|
||||
private _stringsCache: Record<string, Strings> = {};
|
||||
protected abstract _strings(locale: string): Promise<Strings>;
|
||||
async strings(locale: string) {
|
||||
this.assertLocale(locale);
|
||||
|
||||
if (this._stringsCache[locale] === undefined) {
|
||||
this._stringsCache[locale] = await this._strings(locale);
|
||||
}
|
||||
|
||||
return this._stringsCache[locale];
|
||||
}
|
||||
|
||||
private _gameStringsCache: Record<string, Record<string, string>> = {};
|
||||
protected abstract _gameStrings(
|
||||
locale: string,
|
||||
): Promise<Record<string, string>>;
|
||||
async gameStrings(locale: string) {
|
||||
this.assertLocale(locale);
|
||||
|
||||
if (this._gameStringsCache[locale] === undefined) {
|
||||
this._gameStringsCache[locale] = await this._gameStrings(locale);
|
||||
}
|
||||
|
||||
return this._gameStringsCache[locale];
|
||||
}
|
||||
|
||||
private _groupedGameStringsCache: Record<
|
||||
string,
|
||||
Record<string, Record<string, string>>
|
||||
> = {};
|
||||
protected abstract _groupedGameStrings(
|
||||
locale: string,
|
||||
group: string,
|
||||
): Promise<Record<string, string>>;
|
||||
@Cache<[string, string, boolean]>((...args) => args.join("-"))
|
||||
async groupedGameStrings(locale: string, group: string, prefix: boolean) {
|
||||
this.assertLocale(locale);
|
||||
|
||||
if (this._groupedGameStringsCache[locale] === undefined) {
|
||||
this._groupedGameStringsCache[locale] = {};
|
||||
}
|
||||
const gameStrings = await this._groupedGameStrings(locale, group);
|
||||
|
||||
if (this._groupedGameStringsCache[locale][group] === undefined) {
|
||||
this._groupedGameStringsCache[locale][group] =
|
||||
await this._groupedGameStrings(locale, group);
|
||||
}
|
||||
|
||||
if (!prefix) return this._groupedGameStringsCache[locale][group];
|
||||
if (!prefix) return gameStrings;
|
||||
|
||||
const strings: Record<string, string> = {};
|
||||
|
||||
for (const key in this._groupedGameStringsCache[locale][group]) {
|
||||
strings[`${group}__${key}`] =
|
||||
this._groupedGameStringsCache[locale][group][key];
|
||||
for (const key in gameStrings) {
|
||||
strings[`${group}__${key}`] = gameStrings[key];
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
private _avatarCache: Record<string, Avatar> = {};
|
||||
protected abstract _avatar(id: string): Promise<Avatar>;
|
||||
async avatar(id: string) {
|
||||
if (this._avatarCache[id] === undefined) {
|
||||
this._avatarCache[id] = await this._avatar(id);
|
||||
}
|
||||
|
||||
return this._avatarCache[id];
|
||||
}
|
||||
|
||||
private _avatarsCache: Avatars | undefined;
|
||||
protected abstract _avatars(): Promise<Avatars>;
|
||||
async avatars() {
|
||||
if (this._avatarsCache === undefined) {
|
||||
this._avatarsCache = await this._avatars();
|
||||
}
|
||||
|
||||
return this._avatarsCache;
|
||||
}
|
||||
|
||||
private _avatarListCache: AvatarList | undefined;
|
||||
protected abstract _avatarList(): Promise<AvatarList>;
|
||||
async avatarList() {
|
||||
if (this._avatarListCache === undefined) {
|
||||
this._avatarListCache = await this._avatarList();
|
||||
}
|
||||
|
||||
return this._avatarListCache;
|
||||
}
|
||||
|
||||
private _backgroundCache: Record<string, Background> = {};
|
||||
protected abstract _background(id: string): Promise<Background>;
|
||||
async background(id: string) {
|
||||
if (this._backgroundCache[id] === undefined) {
|
||||
this._backgroundCache[id] = await this._background(id);
|
||||
}
|
||||
|
||||
return this._backgroundCache[id];
|
||||
}
|
||||
|
||||
private _backgroundsCache: Backgrounds | undefined;
|
||||
protected abstract _backgrounds(): Promise<Backgrounds>;
|
||||
async backgrounds() {
|
||||
if (this._backgroundsCache === undefined) {
|
||||
this._backgroundsCache = await this._backgrounds();
|
||||
}
|
||||
|
||||
return this._backgroundsCache;
|
||||
}
|
||||
|
||||
private _gameStringGroupsCache: string[] | undefined;
|
||||
protected abstract _gameStringGroups(): Promise<string[]>;
|
||||
async gameStringGroups() {
|
||||
if (this._gameStringGroupsCache === undefined) {
|
||||
this._gameStringGroupsCache = await this._gameStringGroups();
|
||||
}
|
||||
|
||||
return this._gameStringGroupsCache;
|
||||
}
|
||||
|
||||
private _popularTanksCache: PopularTanks | undefined;
|
||||
protected abstract _popularTanks(): Promise<PopularTanks>;
|
||||
async popularTanks() {
|
||||
if (this._popularTanksCache === undefined) {
|
||||
this._popularTanksCache = await this._popularTanks();
|
||||
}
|
||||
|
||||
return this._popularTanksCache;
|
||||
}
|
||||
}
|
||||
|
||||
export function Cache<Arguments extends unknown[]>(
|
||||
discriminator: (...args: Arguments) => string = () => "",
|
||||
discriminator: (...args: Arguments) => string = (...args) => args.join("-"),
|
||||
) {
|
||||
const cache = new WeakMap<object, Map<string, unknown>>();
|
||||
|
||||
|
||||
@@ -3,34 +3,89 @@ import type { Strings } from "@blitzkit/i18n";
|
||||
import { Avatars } from "../../protos/avatars";
|
||||
import { PopularTanks } from "../../protos/popular_tanks";
|
||||
import { Tank } from "../../protos/tank";
|
||||
import { AbstractAPI } from "./abstract";
|
||||
import { AbstractAPI, Cache } from "./abstract";
|
||||
|
||||
const rejected = Promise.reject("Not implemented on client");
|
||||
|
||||
export class ClientAPI extends AbstractAPI {
|
||||
protected _avatars() {
|
||||
return fetchPB("/api/avatars/all.pb", Avatars);
|
||||
@UnimplementedOnClient
|
||||
tankList() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
protected _gameStrings(): Promise<Record<string, string>> {
|
||||
throw new Error("Cannot fetch full game strings on client");
|
||||
@Cache()
|
||||
tank(id: string) {
|
||||
return fetchPB(`/api/tanks/${id}.pb`, Tank);
|
||||
}
|
||||
|
||||
protected async _groupedGameStrings(locale: string, group: string) {
|
||||
const response = await fetch(`/api/game-strings/${locale}/${group}.json`);
|
||||
const json = (await response.json()) as Record<string, string>;
|
||||
return json;
|
||||
@UnimplementedOnClient
|
||||
tanks() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
protected async _strings(locale: string) {
|
||||
const response = await fetch(`/api/strings/${locale}.json`);
|
||||
const json = (await response.json()) as Strings;
|
||||
return json;
|
||||
}
|
||||
|
||||
protected _popularTanks() {
|
||||
@Cache()
|
||||
popularTanks() {
|
||||
return fetchPB("/api/tanks/popular.pb", PopularTanks);
|
||||
}
|
||||
|
||||
protected _tank(id: string) {
|
||||
return fetchPB(`/api/tanks/${id}.pb`, Tank);
|
||||
@Cache()
|
||||
async strings(locale: string) {
|
||||
const response = await fetch(`/api/strings/${locale}.json`);
|
||||
const json = (await response.json()) as Strings;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
gameStrings() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
@Cache()
|
||||
protected async _groupedGameStrings(locale: string, group: string) {
|
||||
const response = await fetch(`/api/game-strings/${locale}/${group}.json`);
|
||||
const json = (await response.json()) as Record<string, string>;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
gameStringGroups() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
avatar() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
avatars() {
|
||||
return fetchPB("/api/avatars/all.pb", Avatars);
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
avatarList() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
background() {
|
||||
return rejected;
|
||||
}
|
||||
|
||||
@UnimplementedOnClient
|
||||
backgrounds() {
|
||||
return rejected;
|
||||
}
|
||||
}
|
||||
|
||||
function UnimplementedOnClient(
|
||||
_target: unknown,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor,
|
||||
) {
|
||||
descriptor.value = function () {
|
||||
throw new Error(`${propertyKey} is not implemented on the client`);
|
||||
};
|
||||
}
|
||||
@@ -35,104 +35,6 @@ export class ServerAPI extends AbstractAPI {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _gameStrings(locale: string) {
|
||||
const group = this.metadata.group("ClientConfigsEntity");
|
||||
|
||||
if (group.length !== 1) {
|
||||
throw new RangeError(
|
||||
`Don't know how to handle ${group.length} ClientConfigsEntities`,
|
||||
);
|
||||
}
|
||||
|
||||
const clientConfig = this.metadata.item(group[0].id);
|
||||
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 strings: Record<string, string> = {};
|
||||
const configPath = `${remoteStorage.url}/${remoteStorage.relative_path}/config.yaml`;
|
||||
|
||||
try {
|
||||
const config = await fetch(configPath)
|
||||
.then((response) => response.text())
|
||||
.then((text) => parse(text) as LocalizationConfig);
|
||||
|
||||
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;
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Failed to fetch config from ${configPath}. Returning empty strings. This will throw an error in production. Error:`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
protected async _groupedGameStrings(locale: string, group: string) {
|
||||
const strings = await this.gameStrings(locale);
|
||||
const filtered: Record<string, string> = {};
|
||||
|
||||
for (const key in strings) {
|
||||
if (key.startsWith(`${group}__`)) {
|
||||
const trimmed = key.substring(group.length + 2);
|
||||
filtered[trimmed] = strings[key];
|
||||
}
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
protected async _strings(locale: string) {
|
||||
const localized = (await globbedStrings[
|
||||
`../../../../i18n/strings/${locale}.json`
|
||||
]()) as DeepPartial<Strings>;
|
||||
const defaults = (await globbedStrings[
|
||||
`../../../../i18n/strings/${locales.default}.json`
|
||||
]()) as Strings;
|
||||
const strings = merge({}, defaults, localized);
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async tankList() {
|
||||
const group = this.metadata.group("TankEntity");
|
||||
@@ -157,18 +59,7 @@ export class ServerAPI extends AbstractAPI {
|
||||
return { list };
|
||||
}
|
||||
|
||||
protected async _tanks() {
|
||||
const tankList = await this.tankList();
|
||||
const data: Tanks = { tanks: {} };
|
||||
|
||||
for (const { id } of tankList.list) {
|
||||
data.tanks[id] = await this.tank(id);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Cache<[string]>((id) => id)
|
||||
@Cache()
|
||||
async tank(id: string) {
|
||||
const tankList = await this.tankList();
|
||||
const tankListEntry = tankList.list.find((tank) => tank.id === id);
|
||||
@@ -185,70 +76,20 @@ export class ServerAPI extends AbstractAPI {
|
||||
return { id, slug, tank, compensation } satisfies Tank;
|
||||
}
|
||||
|
||||
protected async _avatars() {
|
||||
const avatars: Avatar[] = [];
|
||||
@Cache()
|
||||
async tanks() {
|
||||
const tankList = await this.tankList();
|
||||
const data: Tanks = { tanks: {} };
|
||||
|
||||
for (const item of this.metadata.group("ProfileAvatarEntity")) {
|
||||
avatars.push(await this.avatar(item.name));
|
||||
for (const { id } of tankList.list) {
|
||||
data.tanks[id] = await this.tank(id);
|
||||
}
|
||||
|
||||
return { avatars };
|
||||
return data;
|
||||
}
|
||||
|
||||
protected async _avatarList() {
|
||||
const avatars = await this.avatars();
|
||||
const list = avatars.avatars.map((avatar) => avatar.name);
|
||||
|
||||
return { list };
|
||||
}
|
||||
|
||||
protected async _avatar(id: string) {
|
||||
const avatar = this.metadata.item(`ProfileAvatarEntity.${id}`);
|
||||
const name = avatar.name;
|
||||
const stuff_ui = avatar.StuffUI("UIComponent");
|
||||
const profile_avatar = avatar.ProfileAvatar();
|
||||
const sellable = avatar.components.sellableComponent
|
||||
? avatar.Sellable()
|
||||
: undefined;
|
||||
|
||||
return { name, stuff_ui, profile_avatar, sellable };
|
||||
}
|
||||
|
||||
protected async _backgrounds() {
|
||||
const backgrounds: Background[] = [];
|
||||
|
||||
for (const item of this.metadata.group("ProfileBackgroundEntity")) {
|
||||
backgrounds.push(await this.background(item.name));
|
||||
}
|
||||
|
||||
return { backgrounds };
|
||||
}
|
||||
|
||||
protected async _background(id: string) {
|
||||
const background = this.metadata.item(`ProfileBackgroundEntity.${id}`);
|
||||
const name = background.name;
|
||||
const stuff_ui = background.StuffUI("UIComponent");
|
||||
const profile_background = background.ProfileBackground();
|
||||
const sellable = background.components.sellableComponent
|
||||
? background.Sellable()
|
||||
: undefined;
|
||||
|
||||
return { name, stuff_ui, profile_background, sellable };
|
||||
}
|
||||
|
||||
protected async _gameStringGroups() {
|
||||
const defaultGameStrings = await this.gameStrings(locales.default);
|
||||
const groups = new Set<string>();
|
||||
|
||||
for (const key in defaultGameStrings) {
|
||||
const [group] = key.split("__");
|
||||
groups.add(group);
|
||||
}
|
||||
|
||||
return Array.from(groups.values());
|
||||
}
|
||||
|
||||
protected async _popularTanks() {
|
||||
@Cache()
|
||||
async popularTanks() {
|
||||
if (!existsSync("../../temp/popular.json")) {
|
||||
const { tanks } = await this.tanks();
|
||||
const tanksArray = Object.values(tanks);
|
||||
@@ -332,4 +173,174 @@ export class ServerAPI extends AbstractAPI {
|
||||
const data = await readFile("../../temp/popular.json", "utf-8");
|
||||
return JSON.parse(data) as PopularTanks;
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async strings(locale: string) {
|
||||
const localized = (await globbedStrings[
|
||||
`../../../../i18n/strings/${locale}.json`
|
||||
]()) as DeepPartial<Strings>;
|
||||
const defaults = (await globbedStrings[
|
||||
`../../../../i18n/strings/${locales.default}.json`
|
||||
]()) as Strings;
|
||||
const strings = merge({}, defaults, localized);
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async gameStrings(locale: string) {
|
||||
const group = this.metadata.group("ClientConfigsEntity");
|
||||
|
||||
if (group.length !== 1) {
|
||||
throw new RangeError(
|
||||
`Don't know how to handle ${group.length} ClientConfigsEntities`,
|
||||
);
|
||||
}
|
||||
|
||||
const clientConfig = this.metadata.item(group[0].id);
|
||||
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 strings: Record<string, string> = {};
|
||||
const configPath = `${remoteStorage.url}/${remoteStorage.relative_path}/config.yaml`;
|
||||
|
||||
try {
|
||||
const config = await fetch(configPath)
|
||||
.then((response) => response.text())
|
||||
.then((text) => parse(text) as LocalizationConfig);
|
||||
|
||||
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;
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Failed to fetch config from ${configPath}. Returning empty strings. This will throw an error in production. Error:`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
@Cache()
|
||||
protected async _groupedGameStrings(locale: string, group: string) {
|
||||
const strings = await this.gameStrings(locale);
|
||||
const filtered: Record<string, string> = {};
|
||||
|
||||
for (const key in strings) {
|
||||
if (key.startsWith(`${group}__`)) {
|
||||
const trimmed = key.substring(group.length + 2);
|
||||
filtered[trimmed] = strings[key];
|
||||
}
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async gameStringGroups() {
|
||||
const defaultGameStrings = await this.gameStrings(locales.default);
|
||||
const groups = new Set<string>();
|
||||
|
||||
for (const key in defaultGameStrings) {
|
||||
const [group] = key.split("__");
|
||||
groups.add(group);
|
||||
}
|
||||
|
||||
return Array.from(groups.values());
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async avatar(id: string) {
|
||||
const avatar = this.metadata.item(`ProfileAvatarEntity.${id}`);
|
||||
const name = avatar.name;
|
||||
const stuff_ui = avatar.StuffUI("UIComponent");
|
||||
const profile_avatar = avatar.ProfileAvatar();
|
||||
const sellable = avatar.components.sellableComponent
|
||||
? avatar.Sellable()
|
||||
: undefined;
|
||||
|
||||
return { name, stuff_ui, profile_avatar, sellable };
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async avatars() {
|
||||
const avatars: Avatar[] = [];
|
||||
|
||||
for (const item of this.metadata.group("ProfileAvatarEntity")) {
|
||||
avatars.push(await this.avatar(item.name));
|
||||
}
|
||||
|
||||
return { avatars };
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async avatarList() {
|
||||
const avatars = await this.avatars();
|
||||
const list = avatars.avatars.map((avatar) => avatar.name);
|
||||
|
||||
return { list };
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async background(id: string) {
|
||||
const background = this.metadata.item(`ProfileBackgroundEntity.${id}`);
|
||||
const name = background.name;
|
||||
const stuff_ui = background.StuffUI("UIComponent");
|
||||
const profile_background = background.ProfileBackground();
|
||||
const sellable = background.components.sellableComponent
|
||||
? background.Sellable()
|
||||
: undefined;
|
||||
|
||||
return { name, stuff_ui, profile_background, sellable };
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async backgrounds() {
|
||||
const backgrounds: Background[] = [];
|
||||
|
||||
for (const item of this.metadata.group("ProfileBackgroundEntity")) {
|
||||
backgrounds.push(await this.background(item.name));
|
||||
}
|
||||
|
||||
return { backgrounds };
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import { useLocale } from "./useLocale";
|
||||
export function useGameStrings(group: string) {
|
||||
const locale = useLocale();
|
||||
const strings = useAwait(
|
||||
() => api.groupedGameStrings(locale, group, true),
|
||||
`game-strings-${locale}-${group}`
|
||||
() => api._groupedGameStrings(locale, group, true),
|
||||
`game-strings-${locale}-${group}`,
|
||||
);
|
||||
return strings;
|
||||
}
|
||||
@@ -20,10 +20,10 @@ export async function GET({
|
||||
}: {
|
||||
params: { locale: string; group: string };
|
||||
}) {
|
||||
const strings = await api.groupedGameStrings(
|
||||
const strings = await api._groupedGameStrings(
|
||||
params.locale,
|
||||
params.group,
|
||||
false
|
||||
false,
|
||||
);
|
||||
return Response.json(strings);
|
||||
}
|
||||
Reference in new issue
Block a user