Files
core2026/app/game-engine/src/turn/rankData.ts
T

88 lines
2.6 KiB
TypeScript

import {
LEGACY_RANK_DATA_TYPES,
RANK_DATA_TYPES,
rankDataMetaKey,
type LegacyRankDataType,
type RankDataType,
} from '@sammo-ts/common';
export interface RankedGeneralState {
id: number;
nationId: number;
experience: number;
dedication: number;
meta: unknown;
}
export interface PersistedRankRow {
generalId: number;
nationId: number;
type: RankDataType;
value: number;
}
const asRecord = (value: unknown): Record<string, unknown> =>
typeof value === 'object' && value !== null && !Array.isArray(value)
? { ...(value as Record<string, unknown>) }
: {};
const toLegacyDatabaseInt = (value: number): number => {
if (!Number.isFinite(value)) {
return 0;
}
return value >= 0 ? Math.floor(value + 0.5) : Math.ceil(value - 0.5);
};
const readMetaNumber = (meta: Record<string, unknown>, key: string): number => {
const value = meta[key];
if (typeof value === 'number' && Number.isFinite(value)) {
return toLegacyDatabaseInt(value);
}
if (typeof value === 'string') {
const parsed = Number(value);
return Number.isFinite(parsed) ? toLegacyDatabaseInt(parsed) : 0;
}
return 0;
};
export const rankMetaKey = rankDataMetaKey;
export const buildPersistedRankRows = (general: RankedGeneralState): PersistedRankRow[] => {
const meta = asRecord(general.meta);
return RANK_DATA_TYPES.map((type) => {
const value =
type === 'experience'
? toLegacyDatabaseInt(general.experience)
: type === 'dedication'
? toLegacyDatabaseInt(general.dedication)
: readMetaNumber(meta, rankMetaKey(type));
return {
generalId: general.id,
nationId: general.nationId,
type,
value,
};
});
};
export const buildLegacyComparableRankRows = (
general: RankedGeneralState
): Array<PersistedRankRow & { type: LegacyRankDataType }> => {
const legacyTypes = new Set<RankDataType>(LEGACY_RANK_DATA_TYPES);
return buildPersistedRankRows(general).filter(
(row): row is PersistedRankRow & { type: LegacyRankDataType } => legacyTypes.has(row.type)
);
};
export const applyPersistedRankRowsToMeta = (
rawMeta: Record<string, unknown>,
rows: ReadonlyArray<{ type: string; value: number }>
): void => {
const supportedTypes = new Set<string>(RANK_DATA_TYPES);
for (const row of rows) {
if (row.type === 'experience' || row.type === 'dedication' || !supportedTypes.has(row.type)) {
continue;
}
rawMeta[rankMetaKey(row.type as RankDataType)] = row.value;
}
};