fix: render neutral main nation and trait names
This commit is contained in:
@@ -18,7 +18,7 @@ import { ConflictingTurnDaemonCommandError } from '../../daemon/databaseTranspor
|
||||
import { resolveAccessWindows } from '../../services/generalAccess.js';
|
||||
import { adjustAccountIconForUser } from '../../services/accountIconSync.js';
|
||||
import { getMyGeneral } from '../shared/general.js';
|
||||
import { resolveNationNotice } from '../nation/shared.js';
|
||||
import { loadTraitNames, resolveNationNotice, type TraitNameMap } from '../nation/shared.js';
|
||||
|
||||
const zGeneralSettings = z.object({
|
||||
tnmt: z.number().int().optional(),
|
||||
@@ -34,6 +34,17 @@ const zImmediateActionInput = z
|
||||
})
|
||||
.optional();
|
||||
const MAIN_RECORD_LIMIT = 15;
|
||||
const NEUTRAL_NATION_CONTEXT = {
|
||||
id: 0,
|
||||
name: '재야',
|
||||
color: '#000000',
|
||||
level: 0,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
tech: 0,
|
||||
typeCode: 'None',
|
||||
capitalCityId: null,
|
||||
} as const;
|
||||
|
||||
const resolveImmediateActionRequestId = (
|
||||
contextRequestId: string | undefined,
|
||||
@@ -135,6 +146,18 @@ const normalizeItemCode = (value: string | null): string | null => {
|
||||
return value;
|
||||
};
|
||||
|
||||
const resolveTraitDisplayName = (code: string, names: TraitNameMap): string => {
|
||||
if (!code || code === 'None') {
|
||||
return '-';
|
||||
}
|
||||
const loadedName = names.get(code)?.name;
|
||||
if (loadedName) {
|
||||
return loadedName;
|
||||
}
|
||||
// Ref는 class getName()을 표시하므로 로더가 모르는 선택적 특기도 raw namespace는 노출하지 않는다.
|
||||
return code.replace(/^che_(?:event_)?/u, '');
|
||||
};
|
||||
|
||||
const resolveUserSettings = (meta: Record<string, unknown>) => {
|
||||
// The legacy general columns are persisted at the top level of General.meta.
|
||||
// Keep reading the short-lived nested shape for installations that ran the
|
||||
@@ -265,10 +288,16 @@ export const getGeneralContext = async (ctx: GameApiContext) => {
|
||||
capitalCityId: true,
|
||||
},
|
||||
})
|
||||
: null,
|
||||
: Promise.resolve(NEUTRAL_NATION_CONTEXT),
|
||||
ctx.db.worldState.findFirst({ select: { config: true } }),
|
||||
]);
|
||||
|
||||
const [personalityNames, domesticNames, warNames] = await Promise.all([
|
||||
loadTraitNames([general.personalCode], 'personality'),
|
||||
loadTraitNames([general.specialCode], 'domestic'),
|
||||
loadTraitNames([general.special2Code], 'war'),
|
||||
]);
|
||||
|
||||
const metaRecord = asRecord(general.meta);
|
||||
const worldConfig = asRecord(worldState?.config);
|
||||
const constValues = asRecord(worldConfig.const ?? worldConfig.consts);
|
||||
@@ -303,9 +332,9 @@ export const getGeneralContext = async (ctx: GameApiContext) => {
|
||||
turnTime: general.turnTime.toISOString(),
|
||||
crewTypeId: general.crewTypeId,
|
||||
traits: {
|
||||
personal: general.personalCode,
|
||||
specialWar: general.specialCode,
|
||||
specialDomestic: general.special2Code,
|
||||
personal: resolveTraitDisplayName(general.personalCode, personalityNames),
|
||||
specialDomestic: resolveTraitDisplayName(general.specialCode, domesticNames),
|
||||
specialWar: resolveTraitDisplayName(general.special2Code, warNames),
|
||||
},
|
||||
progression: {
|
||||
experienceLevel: readNumber(metaRecord.explevel, 0),
|
||||
|
||||
@@ -248,6 +248,40 @@ describe('in-game my information ownership', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the Ref-style neutral nation frame and trait display names on the main read model', async () => {
|
||||
const fixture = createContext({
|
||||
me: buildGeneral({
|
||||
nationId: 0,
|
||||
officerLevel: 0,
|
||||
personalCode: 'che_안전',
|
||||
specialCode: 'che_상재',
|
||||
special2Code: 'che_신산',
|
||||
}),
|
||||
});
|
||||
|
||||
await expect(appRouter.createCaller(fixture.context).general.me()).resolves.toMatchObject({
|
||||
general: {
|
||||
traits: {
|
||||
personal: '안전',
|
||||
specialDomestic: '상재',
|
||||
specialWar: '신산',
|
||||
},
|
||||
},
|
||||
nation: {
|
||||
id: 0,
|
||||
name: '재야',
|
||||
color: '#000000',
|
||||
level: 0,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
tech: 0,
|
||||
typeCode: 'None',
|
||||
capitalCityId: null,
|
||||
},
|
||||
});
|
||||
expect(fixture.db.nation.findUnique).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('reads legacy top-level settings and dispatches only the session-owned general', async () => {
|
||||
const requestCommand = vi.fn(async () => ({ type: 'setMySetting', ok: true, generalId: 7 }));
|
||||
const fixture = createContext({ requestCommand });
|
||||
|
||||
Reference in New Issue
Block a user