mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:30:43 +00:00
Fix bigint serialization error (#916)
## Description: - JSON serialization, bigint to string handling - JSON deserialization, string to bigint handling ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors --------- Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { consolex } from "../core/Consolex";
|
||||
import { GameConfig, GameID, GameRecord } from "../core/Schemas";
|
||||
import { replacer } from "../core/Util";
|
||||
|
||||
export interface LocalStatsData {
|
||||
[key: GameID]: {
|
||||
@@ -19,7 +20,7 @@ function getStats(): LocalStatsData {
|
||||
function save(stats: LocalStatsData) {
|
||||
// To execute asynchronously
|
||||
setTimeout(
|
||||
() => localStorage.setItem("game-records", JSON.stringify(stats)),
|
||||
() => localStorage.setItem("game-records", JSON.stringify(stats, replacer)),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
ServerStartGameMessageSchema,
|
||||
Turn,
|
||||
} from "../core/Schemas";
|
||||
import { createGameRecord, decompressGameRecord } from "../core/Util";
|
||||
import { createGameRecord, decompressGameRecord, replacer } from "../core/Util";
|
||||
import { LobbyConfig } from "./ClientGameRunner";
|
||||
import { getPersistentID } from "./Main";
|
||||
|
||||
@@ -199,9 +199,12 @@ export class LocalServer {
|
||||
record.turns = [];
|
||||
}
|
||||
// For unload events, sendBeacon is the only reliable method
|
||||
const blob = new Blob([JSON.stringify(GameRecordSchema.parse(record))], {
|
||||
type: "application/json",
|
||||
});
|
||||
const blob = new Blob(
|
||||
[JSON.stringify(GameRecordSchema.parse(record), replacer)],
|
||||
{
|
||||
type: "application/json",
|
||||
},
|
||||
);
|
||||
const workerPath = this.lobbyConfig.serverConfig.workerPath(
|
||||
this.lobbyConfig.gameStartInfo.gameID,
|
||||
);
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
ServerMessageSchema,
|
||||
Winner,
|
||||
} from "../core/Schemas";
|
||||
import { replacer } from "../core/Util";
|
||||
import { LobbyConfig } from "./ClientGameRunner";
|
||||
import { LocalServer } from "./LocalServer";
|
||||
|
||||
@@ -536,7 +537,7 @@ export class Transport {
|
||||
winner: event.winner,
|
||||
allPlayersStats: event.allPlayersStats,
|
||||
} satisfies ClientSendWinnerMessage;
|
||||
this.sendMsg(JSON.stringify(msg));
|
||||
this.sendMsg(JSON.stringify(msg, replacer));
|
||||
} else {
|
||||
console.log(
|
||||
"WebSocket is not open. Current state:",
|
||||
|
||||
@@ -84,13 +84,19 @@ export const OTHER_INDEX_DESTROY = 1; // Structures and warships destroyed
|
||||
export const OTHER_INDEX_CAPTURE = 2; // Structures captured
|
||||
export const OTHER_INDEX_LOST = 3; // Structures/warships destroyed/captured by others
|
||||
|
||||
const AtLeastOneNumberSchema = z.bigint().array().min(1);
|
||||
const BigIntStringSchema = z.preprocess((val) => {
|
||||
if (typeof val === "string" && /^\d+$/.test(val)) return BigInt(val);
|
||||
if (typeof val === "bigint") return val;
|
||||
return val;
|
||||
}, z.bigint());
|
||||
|
||||
const AtLeastOneNumberSchema = BigIntStringSchema.array().min(1);
|
||||
export type AtLeastOneNumber = z.infer<typeof AtLeastOneNumberSchema>;
|
||||
|
||||
export const PlayerStatsSchema = z
|
||||
.object({
|
||||
attacks: AtLeastOneNumberSchema.optional(),
|
||||
betrayals: z.bigint().positive().optional(),
|
||||
betrayals: BigIntStringSchema.optional(),
|
||||
boats: z.record(BoatUnitSchema, AtLeastOneNumberSchema).optional(),
|
||||
bombs: z.record(BombUnitSchema, AtLeastOneNumberSchema).optional(),
|
||||
gold: AtLeastOneNumberSchema.optional(),
|
||||
|
||||
@@ -308,3 +308,10 @@ export const emojiTable: string[][] = [
|
||||
];
|
||||
// 2d to 1d array
|
||||
export const flattenedEmojiTable: string[] = emojiTable.flat();
|
||||
|
||||
/**
|
||||
* JSON.stringify replacer function that converts bigint values to strings.
|
||||
*/
|
||||
export function replacer(_key: string, value: any): any {
|
||||
return typeof value === "bigint" ? value.toString() : value;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { S3 } from "@aws-sdk/client-s3";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { AnalyticsRecord, GameID, GameRecord } from "../core/Schemas";
|
||||
import { replacer } from "../core/Util";
|
||||
import { logger } from "./Logger";
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
@@ -147,10 +148,3 @@ export async function gameRecordExists(gameId: GameID): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON.stringify replacer function that converts bigint values to strings.
|
||||
*/
|
||||
export function replacer(_key: string, value: any): any {
|
||||
return typeof value === "bigint" ? value.toString() : value;
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import {
|
||||
} from "../src/core/game/Game";
|
||||
import { Stats } from "../src/core/game/Stats";
|
||||
import { StatsImpl } from "../src/core/game/StatsImpl";
|
||||
import { replacer } from "../src/server/Archive";
|
||||
import { replacer } from "../src/core/Util";
|
||||
import { setup } from "./util/Setup";
|
||||
|
||||
let stats: Stats;
|
||||
|
||||
Reference in New Issue
Block a user