fix(game-ui): 메인 턴과 장수 상태 표시를 보완

This commit is contained in:
2026-08-29 03:30:50 +00:00
parent fa9fe71539
commit 26952fcdc7
11 changed files with 120 additions and 49 deletions
+3 -2
View File
@@ -333,6 +333,7 @@ export const getGeneralContext = async (ctx: GameApiContext) => {
troopLeaderFirstTurn,
accessLog,
rankRows,
gameTime,
] = await Promise.all([
general.cityId > 0
? ctx.db.city.findUnique({
@@ -413,6 +414,7 @@ export const getGeneralContext = async (ctx: GameApiContext) => {
where: { generalId: general.id, type: { in: [...PERSONAL_RECORD_TYPES] } },
select: { type: true, value: true },
}),
loadCurrentGameTime(ctx.db),
]);
const nation = queriedNation ?? NEUTRAL_NATION_CONTEXT;
@@ -588,8 +590,7 @@ export const getGeneralContext = async (ctx: GameApiContext) => {
killTurn: readNumber(metaRecord.killturn ?? metaRecord.killTurn, 0),
remainingMinutes: resolveRemainingMinutes(
general.turnTime,
parsedLastExecuted,
worldState?.tickSeconds ?? 0
gameTime.now
),
crewTypeId: general.crewTypeId,
crewTypeName: crewTypeDetails.get(general.crewTypeId)?.name ?? '-',
+4 -12
View File
@@ -23,6 +23,7 @@ import {
resolveRefreshScoreText,
resolveRemainingMinutes,
} from '../../services/generalBasicCardProjection.js';
import { loadCurrentGameTime } from '../../services/gameClock.js';
import { loadTraitNames } from '../nation/shared.js';
import { getAuthenticatedUserId, getMyGeneral } from '../shared/general.js';
import { throwIfCommandRejected } from '../shared/turnDaemon.js';
@@ -72,7 +73,7 @@ export const troopRouter = router({
throw new TRPCError({ code: 'PRECONDITION_FAILED', message: '국가에 소속되어 있지 않습니다.' });
}
const [nation, troops, generals, cities, worldState] = await Promise.all([
const [nation, troops, generals, cities, worldState, gameTime] = await Promise.all([
ctx.db.nation.findUnique({
where: { id: me.nationId },
select: { id: true, name: true, color: true, level: true, meta: true },
@@ -121,6 +122,7 @@ export const troopRouter = router({
select: { id: true, name: true },
}),
ctx.db.worldState.findFirst({ select: { tickSeconds: true, config: true, meta: true } }),
loadCurrentGameTime(ctx.db),
]);
if (!nation) {
throw new TRPCError({ code: 'NOT_FOUND', message: '국가 정보를 찾을 수 없습니다.' });
@@ -214,15 +216,6 @@ export const troopRouter = router({
const traitName = (code: string, names: Map<string, { name: string }>): string =>
names.get(code)?.name ?? sanitizeInternalDisplayCode(code);
const itemName = (code: string): string => itemNames.get(code) ?? sanitizeInternalDisplayCode(code);
const worldMeta = asRecord(worldState?.meta);
const rawLastExecuted = worldMeta.lastTurnTime ?? worldMeta.turntime;
const lastExecuted =
rawLastExecuted instanceof Date
? rawLastExecuted
: typeof rawLastExecuted === 'string'
? new Date(rawLastExecuted)
: null;
const mappedTroops = troops
.map((troop) => {
const leader = generalMap.get(troop.troopLeaderId);
@@ -348,8 +341,7 @@ export const troopRouter = router({
killTurn: readNumber(meta.killturn ?? meta.killTurn),
remainingMinutes: resolveRemainingMinutes(
general.turnTime,
lastExecuted,
worldState?.tickSeconds ?? 0
gameTime.now
),
troopId: general.troopId,
troop: {
@@ -45,15 +45,10 @@ export const resolveRefreshScoreText = (score: number): string => {
export const resolveRemainingMinutes = (
turnTime: Date,
lastExecuted: Date | null,
turnTermSeconds: number
currentGameTime: Date | null
): number | null => {
if (!lastExecuted || !Number.isFinite(lastExecuted.getTime()) || turnTermSeconds <= 0) return null;
let nextTurnMillis = turnTime.getTime();
if (nextTurnMillis < lastExecuted.getTime()) {
nextTurnMillis += turnTermSeconds * 1_000;
}
return Math.floor(Math.min(999, Math.max(0, (nextTurnMillis - lastExecuted.getTime()) / 60_000)));
if (!currentGameTime || !Number.isFinite(currentGameTime.getTime())) return null;
return Math.floor(Math.max(0, (turnTime.getTime() - currentGameTime.getTime()) / 60_000));
};
export interface NextTurnMonthOffsetInput {