mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-02 14:28:18 +00:00
store & reference pattern by name (#1766)
## Description: Store pattern by name instead of value. The worker replaces the pattern name with it's base64 when joining. This ensures the client & server are never out of sync after patterns are updated. * removed resizeObserver on the territory modal, it was causing some race conditions, and the modal is not resizable so it's unnecessary. * Moved PatternSchema to CosmeticSchema ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I have read and accepted the CLA agreement (only required once). ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
import { base64url } from "jose";
|
||||
import { z } from "zod/v4";
|
||||
import { RequiredPatternSchema } from "./Schemas";
|
||||
import { PatternDecoder } from "./PatternDecoder";
|
||||
|
||||
export type Cosmetics = z.infer<typeof CosmeticsSchema>;
|
||||
export type Pattern = z.infer<typeof PatternInfoSchema>;
|
||||
export type PatternName = z.infer<typeof PatternNameSchema>;
|
||||
export type Product = z.infer<typeof ProductSchema>;
|
||||
|
||||
export const ProductSchema = z.object({
|
||||
productId: z.string(),
|
||||
@@ -7,15 +13,43 @@ export const ProductSchema = z.object({
|
||||
price: z.string(),
|
||||
});
|
||||
|
||||
const PatternSchema = z.object({
|
||||
name: z.string(),
|
||||
pattern: RequiredPatternSchema,
|
||||
export const PatternNameSchema = z
|
||||
.string()
|
||||
.regex(/^[a-z0-9_]+$/)
|
||||
.max(32);
|
||||
|
||||
export const PatternSchema = z
|
||||
.string()
|
||||
.max(1403)
|
||||
.base64url()
|
||||
.refine(
|
||||
(val) => {
|
||||
try {
|
||||
new PatternDecoder(val, base64url.decode);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
console.error(JSON.stringify(e.message, null, 2));
|
||||
} else {
|
||||
console.error(String(e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "Invalid pattern",
|
||||
},
|
||||
);
|
||||
|
||||
export const PatternInfoSchema = z.object({
|
||||
name: PatternNameSchema,
|
||||
pattern: PatternSchema,
|
||||
product: ProductSchema.nullable(),
|
||||
});
|
||||
|
||||
// Schema for resources/cosmetics/cosmetics.json
|
||||
export const CosmeticsSchema = z.object({
|
||||
patterns: z.record(z.string(), PatternSchema),
|
||||
patterns: z.record(z.string(), PatternInfoSchema),
|
||||
flag: z
|
||||
.object({
|
||||
layers: z.record(
|
||||
@@ -36,6 +70,3 @@ export const CosmeticsSchema = z.object({
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
export type Cosmetics = z.infer<typeof CosmeticsSchema>;
|
||||
export type Pattern = z.infer<typeof PatternSchema>;
|
||||
export type Product = z.infer<typeof ProductSchema>;
|
||||
|
||||
+3
-31
@@ -1,7 +1,7 @@
|
||||
import { base64url } from "jose";
|
||||
import { z } from "zod";
|
||||
import quickChatData from "../../resources/QuickChat.json" with { type: "json" };
|
||||
import countries from "../client/data/countries.json" with { type: "json" };
|
||||
import { PatternSchema } from "./CosmeticSchemas";
|
||||
import {
|
||||
AllPlayers,
|
||||
Difficulty,
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
Trios,
|
||||
UnitType,
|
||||
} from "./game/Game";
|
||||
import { PatternDecoder } from "./PatternDecoder";
|
||||
import { PlayerStatsSchema } from "./StatsSchemas";
|
||||
import { flattenedEmojiTable } from "./Util";
|
||||
|
||||
@@ -203,29 +202,6 @@ export const FlagSchema = z
|
||||
},
|
||||
{ message: "Invalid flag: must be a valid country code or start with !" },
|
||||
);
|
||||
export const RequiredPatternSchema = z
|
||||
.string()
|
||||
.max(1403)
|
||||
.base64url()
|
||||
.refine(
|
||||
(val) => {
|
||||
try {
|
||||
new PatternDecoder(val, base64url.decode);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
console.error(JSON.stringify(e.message, null, 2));
|
||||
} else {
|
||||
console.error(String(e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "Invalid pattern",
|
||||
},
|
||||
);
|
||||
export const PatternSchema = RequiredPatternSchema.optional();
|
||||
|
||||
export const QuickChatKeySchema = z.enum(
|
||||
Object.entries(quickChatData).flatMap(([category, entries]) =>
|
||||
@@ -254,10 +230,6 @@ export const AttackIntentSchema = BaseIntentSchema.extend({
|
||||
|
||||
export const SpawnIntentSchema = BaseIntentSchema.extend({
|
||||
type: z.literal("spawn"),
|
||||
name: UsernameSchema,
|
||||
flag: FlagSchema,
|
||||
pattern: PatternSchema,
|
||||
playerType: PlayerTypeSchema,
|
||||
tile: z.number(),
|
||||
});
|
||||
|
||||
@@ -397,7 +369,7 @@ export const PlayerSchema = z.object({
|
||||
clientID: ID,
|
||||
username: UsernameSchema,
|
||||
flag: FlagSchema,
|
||||
pattern: PatternSchema,
|
||||
pattern: PatternSchema.optional(),
|
||||
});
|
||||
|
||||
export const GameStartInfoSchema = z.object({
|
||||
@@ -503,7 +475,7 @@ export const ClientJoinMessageSchema = z.object({
|
||||
lastTurn: z.number(), // The last turn the client saw.
|
||||
username: UsernameSchema,
|
||||
flag: FlagSchema,
|
||||
pattern: PatternSchema,
|
||||
patternName: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ClientMessageSchema = z.discriminatedUnion("type", [
|
||||
|
||||
@@ -381,13 +381,13 @@ export class GameView implements GameMap {
|
||||
private _mapData: TerrainMapData,
|
||||
private _myClientID: ClientID,
|
||||
private _gameID: GameID,
|
||||
private _hunans: Player[],
|
||||
private humans: Player[],
|
||||
) {
|
||||
this._map = this._mapData.gameMap;
|
||||
this.lastUpdate = null;
|
||||
this.unitGrid = new UnitGrid(this._map);
|
||||
this._cosmetics = new Map(
|
||||
this._hunans.map((h) => [
|
||||
this.humans.map((h) => [
|
||||
h.clientID,
|
||||
{ flag: h.flag, pattern: h.pattern } satisfies PlayerCosmetics,
|
||||
]),
|
||||
|
||||
@@ -111,11 +111,11 @@ export class UserSettings {
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedPattern(): string | undefined {
|
||||
getSelectedPatternName(): string | undefined {
|
||||
return localStorage.getItem(PATTERN_KEY) ?? undefined;
|
||||
}
|
||||
|
||||
setSelectedPattern(base64: string | undefined): void {
|
||||
setSelectedPatternName(base64: string | undefined): void {
|
||||
if (base64 === undefined) {
|
||||
localStorage.removeItem(PATTERN_KEY);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user