mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: some unification
This commit is contained in:
1 parent
f5ed2c2c40
commit
1366579dd1
7 files changed
+153
-50
No files matched your search
@@ -3,6 +3,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
margin-top: calc(var(--space-4) * -1);
|
||||
padding: var(--space-6) var(--space-4);
|
||||
|
||||
background-color: var(--gray-3);
|
||||
|
||||
@@ -1,20 +1,32 @@
|
||||
import type { CatalogItemAccessor } from "@blitzkit/closed";
|
||||
import type { Strings } from "@blitzkit/i18n";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import type { Avatar } from "../../protos/avatar";
|
||||
import type { Avatars } from "../../protos/avatars";
|
||||
import type { Tank } from "../../protos/tank";
|
||||
import type { TankList } from "../../protos/tank_list";
|
||||
import type { Tanks } from "../../protos/tanks";
|
||||
|
||||
export abstract class AbstractAPI {
|
||||
abstract tanks(): Promise<Tanks>;
|
||||
private _tanksCache: Tanks | undefined;
|
||||
protected abstract _tanks(): Promise<Tanks>;
|
||||
async tanks() {
|
||||
if (this._tanksCache === undefined) {
|
||||
this._tanksCache = await this._tanks();
|
||||
}
|
||||
|
||||
abstract tankList(): Promise<TankList>;
|
||||
return this._tanksCache;
|
||||
}
|
||||
|
||||
abstract _strings(locale: string): Promise<Strings>;
|
||||
abstract _gameStrings(
|
||||
locale: string,
|
||||
prefix: string
|
||||
): Promise<Record<string, string>>;
|
||||
private _tankListCache: TankList | undefined;
|
||||
protected abstract _tankList(): Promise<TankList>;
|
||||
async tankList() {
|
||||
if (this._tankListCache === undefined) {
|
||||
this._tankListCache = await this._tankList();
|
||||
}
|
||||
|
||||
return this._tankListCache;
|
||||
}
|
||||
|
||||
private assertLocale(locale: string) {
|
||||
const supported = locales.supported.find(
|
||||
@@ -27,19 +39,73 @@ 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);
|
||||
return await this._strings(locale);
|
||||
|
||||
if (this._stringsCache[locale] === undefined) {
|
||||
this._stringsCache[locale] = await this._strings(locale);
|
||||
}
|
||||
|
||||
return this._stringsCache[locale];
|
||||
}
|
||||
|
||||
private _gameStringsCache: Record<
|
||||
string,
|
||||
Record<string, Record<string, string>>
|
||||
> = {};
|
||||
protected abstract _gameStrings(
|
||||
locale: string,
|
||||
prefix: string
|
||||
): Promise<Record<string, string>>;
|
||||
async gameStrings(locale: string, prefix: string) {
|
||||
this.assertLocale(locale);
|
||||
return await this._gameStrings(locale, prefix);
|
||||
|
||||
if (this._gameStringsCache[locale] === undefined) {
|
||||
this._gameStringsCache[locale] = {};
|
||||
}
|
||||
|
||||
if (this._gameStringsCache[locale][prefix] === undefined) {
|
||||
this._gameStringsCache[locale][prefix] = await this._gameStrings(
|
||||
locale,
|
||||
prefix
|
||||
);
|
||||
}
|
||||
|
||||
return this._gameStringsCache[locale][prefix];
|
||||
}
|
||||
|
||||
abstract tank(id: string): Promise<Tank>;
|
||||
private _tankCache: Record<string, Tank> = {};
|
||||
protected abstract _tank(id: string): Promise<Tank>;
|
||||
async tank(id: string) {
|
||||
if (this._tankCache[id] === undefined) {
|
||||
this._tankCache[id] = await this._tank(id);
|
||||
}
|
||||
|
||||
abstract avatars(): Promise<CatalogItemAccessor[]>;
|
||||
abstract avatar(id: string): Promise<CatalogItemAccessor>;
|
||||
return this._tankCache[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 _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];
|
||||
}
|
||||
|
||||
abstract backgrounds(): Promise<CatalogItemAccessor[]>;
|
||||
abstract background(id: string): Promise<CatalogItemAccessor>;
|
||||
|
||||
@@ -20,3 +20,5 @@ if (typeof window === "undefined") {
|
||||
}
|
||||
|
||||
export const api = dynamicAPI;
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ import locales from "@blitzkit/i18n/locales.json";
|
||||
import type { RemoteStorageComponent } from "@protos/blitz_static_remote_storage_component";
|
||||
import { merge } from "lodash-es";
|
||||
import { parse } from "yaml";
|
||||
import type { Avatar } from "../../protos/avatar";
|
||||
import type { Tank } from "../../protos/tank";
|
||||
import type { TankList, TankListEntry } from "../../protos/tank_list";
|
||||
import type { TankListEntry } from "../../protos/tank_list";
|
||||
import type { Tanks } from "../../protos/tanks";
|
||||
import { AbstractAPI } from "./abstract";
|
||||
|
||||
@@ -27,7 +28,7 @@ export class ServerAPI extends AbstractAPI {
|
||||
super();
|
||||
}
|
||||
|
||||
async _gameStrings(locale: string, prefix: string) {
|
||||
protected async _gameStrings(locale: string, prefix: string) {
|
||||
const group = this.metadata.group("ClientConfigsEntity");
|
||||
|
||||
if (group.length !== 1) {
|
||||
@@ -107,7 +108,7 @@ export class ServerAPI extends AbstractAPI {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
async _strings(locale: string) {
|
||||
protected async _strings(locale: string) {
|
||||
const localized = (await globbedStrings[
|
||||
`../../../../i18n/strings/${locale}.json`
|
||||
]()) as DeepPartial<Strings>;
|
||||
@@ -119,35 +120,30 @@ export class ServerAPI extends AbstractAPI {
|
||||
return strings;
|
||||
}
|
||||
|
||||
_tankList: TankList | undefined;
|
||||
async tankList() {
|
||||
if (this._tankList === undefined) {
|
||||
const group = this.metadata.group("TankEntity");
|
||||
const list: TankListEntry[] = [];
|
||||
const strings = await this.gameStrings("en", "TankEntity");
|
||||
protected async _tankList() {
|
||||
const group = this.metadata.group("TankEntity");
|
||||
const list: TankListEntry[] = [];
|
||||
const strings = await this.gameStrings("en", "TankEntity");
|
||||
|
||||
for (const item of group) {
|
||||
const tankCatalog = item.TankCatalog();
|
||||
for (const item of group) {
|
||||
const tankCatalog = item.TankCatalog();
|
||||
|
||||
if (!tankCatalog.name) continue;
|
||||
if (!tankCatalog.name) continue;
|
||||
|
||||
const name = strings[tankCatalog.name.value];
|
||||
const name = strings[tankCatalog.name.value];
|
||||
|
||||
if (!name) continue;
|
||||
if (!name) continue;
|
||||
|
||||
const id = item.name;
|
||||
const slug = sluggify(name);
|
||||
const id = item.name;
|
||||
const slug = sluggify(name);
|
||||
|
||||
list.push({ id, slug });
|
||||
}
|
||||
|
||||
this._tankList = { list };
|
||||
list.push({ id, slug });
|
||||
}
|
||||
|
||||
return this._tankList;
|
||||
return { list };
|
||||
}
|
||||
|
||||
async tanks() {
|
||||
protected async _tanks() {
|
||||
const tankList = await this.tankList();
|
||||
const data: Tanks = { tanks: {} };
|
||||
|
||||
@@ -158,7 +154,7 @@ export class ServerAPI extends AbstractAPI {
|
||||
return data;
|
||||
}
|
||||
|
||||
async tank(id: string) {
|
||||
protected async _tank(id: string) {
|
||||
const tankList = await this.tankList();
|
||||
const tankListEntry = tankList.list.find((tank) => tank.id === id);
|
||||
|
||||
@@ -174,12 +170,26 @@ export class ServerAPI extends AbstractAPI {
|
||||
return { tank, compensation, slug } satisfies Tank;
|
||||
}
|
||||
|
||||
async avatars() {
|
||||
return this.metadata.group("ProfileAvatarEntity");
|
||||
async _avatars() {
|
||||
const avatars: Avatar[] = [];
|
||||
|
||||
for (const item of this.metadata.group("ProfileAvatarEntity")) {
|
||||
avatars.push(await this.avatar(item.name));
|
||||
}
|
||||
|
||||
return { avatars };
|
||||
}
|
||||
|
||||
async avatar(id: string) {
|
||||
return this.metadata.item(`ProfileAvatarEntity.${id}`);
|
||||
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 };
|
||||
}
|
||||
|
||||
async backgrounds() {
|
||||
|
||||
@@ -6,30 +6,31 @@ import BaseLayout from "../../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
const avatars = await api.avatars();
|
||||
const { avatars } = await api.avatars();
|
||||
---
|
||||
|
||||
<BaseLayout accent="gold">
|
||||
{
|
||||
avatars.map((avatar) => {
|
||||
const ui = avatar.StuffUI("UIComponent");
|
||||
const profileAvatar = avatar.ProfileAvatar();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>
|
||||
{ui.display_name} {Grade[ui.grade]}{" "}
|
||||
{ProfileAvatarComponent_Category[profileAvatar.category]}
|
||||
{avatar.stuff_ui!.display_name} {Grade[avatar.stuff_ui!.grade]}{" "}
|
||||
{ProfileAvatarComponent_Category[avatar.profile_avatar!.category]}
|
||||
</h3>
|
||||
|
||||
{ui.description && <p>{ui.description}</p>}
|
||||
{ui.obtaining_methods && <p>{ui.obtaining_methods}</p>}
|
||||
{ui.features && <p>{ui.features}</p>}
|
||||
{avatar.stuff_ui!.description && (
|
||||
<p>{avatar.stuff_ui!.description}</p>
|
||||
)}
|
||||
{avatar.stuff_ui!.obtaining_methods && (
|
||||
<p>{avatar.stuff_ui!.obtaining_methods}</p>
|
||||
)}
|
||||
{avatar.stuff_ui!.features && <p>{avatar.stuff_ui!.features}</p>}
|
||||
|
||||
<img width="128" src={`/api/avatars/${avatar.name}.webp`} />
|
||||
|
||||
{avatar.components.sellableComponent && (
|
||||
<pre>{JSON.stringify(avatar.Sellable(), null, 2)}</pre>
|
||||
{avatar.sellable && (
|
||||
<pre>{JSON.stringify(avatar.sellable, null, 2)}</pre>
|
||||
)}
|
||||
|
||||
<br />
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package blitzkit;
|
||||
|
||||
import "blitz_static_profile_avatar_component.proto";
|
||||
import "blitz_static_sellable_component.proto";
|
||||
import "blitz_static_stuff_ui_component.proto";
|
||||
|
||||
message Avatar {
|
||||
string name = 1;
|
||||
blitz_static_stuff_ui_component.StuffUIComponent stuff_ui = 2;
|
||||
blitz_static_profile_avatar_component.ProfileAvatarComponent profile_avatar = 3;
|
||||
optional blitz_static_sellable_component.SellableComponent sellable = 4;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package blitzkit;
|
||||
|
||||
import "avatar.proto";
|
||||
|
||||
message Avatars {
|
||||
repeated Avatar avatars = 1;
|
||||
}
|
||||
Reference in new issue
Block a user