feat: make general creation daemon-atomic

This commit is contained in:
2026-07-31 00:33:03 +00:00
parent 115218ded8
commit c6a2a0da93
34 changed files with 2227 additions and 655 deletions
@@ -16,6 +16,11 @@ export const PERSONALITY_TRAIT_KEYS = [
export type PersonalityTraitKey = (typeof PERSONALITY_TRAIT_KEYS)[number];
// Ref GameConst::$availablePersonality에는 은둔이 포함되지 않는다.
export const JOIN_PERSONALITY_TRAIT_KEYS = PERSONALITY_TRAIT_KEYS.filter(
(key): key is Exclude<PersonalityTraitKey, 'che_은둔'> => key !== 'che_은둔'
);
export type PersonalityTraitModule = TraitModule;
export type PersonalityTraitImporter = () => Promise<TraitModuleExport>;
+15 -4
View File
@@ -179,11 +179,14 @@ const readNameParts = (value: unknown, fallback: readonly string[]): string[] =>
return result.length > 0 ? result : [...fallback];
};
export const buildAuctionAlias = (
generalId: number,
export const buildAuctionAliasPool = (
hiddenSeed: string | number,
configConst: Record<string, unknown> = {}
): string => {
): string[] => {
const persistedPool = readNameParts(configConst.obfuscatedNamePool, []);
if (persistedPool.length > 0) {
return persistedPool;
}
const firstNames = readNameParts(configConst.randGenFirstName, LEGACY_RANDOM_GENERAL_FIRST_NAMES);
const middleNames = readNameParts(configConst.randGenMiddleName, ['']);
const lastNames = readNameParts(configConst.randGenLastName, LEGACY_RANDOM_GENERAL_LAST_NAMES);
@@ -195,7 +198,15 @@ export const buildAuctionAlias = (
}
}
}
const shuffled = new RandUtil(new LiteHashDRBG(simpleSerialize(hiddenSeed, 'obfuscatedNamePool'))).shuffle(pool);
return new RandUtil(new LiteHashDRBG(simpleSerialize(hiddenSeed, 'obfuscatedNamePool'))).shuffle(pool);
};
export const buildAuctionAlias = (
generalId: number,
hiddenSeed: string | number,
configConst: Record<string, unknown> = {}
): string => {
const shuffled = buildAuctionAliasPool(hiddenSeed, configConst);
const normalizedId = Math.max(0, Math.floor(generalId));
const duplicateIndex = Math.floor(normalizedId / shuffled.length);
const name = shuffled[normalizedId % shuffled.length] ?? `익명${normalizedId}`;
+15 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { buildAuctionAlias } from '../src/auction/alias.js';
import { buildAuctionAlias, buildAuctionAliasPool } from '../src/auction/alias.js';
describe('buildAuctionAlias', () => {
it('returns a stable alias for the same world seed and general id', () => {
@@ -22,4 +22,18 @@ describe('buildAuctionAlias', () => {
expect(buildAuctionAlias(1, 'seed', config)).toMatch(/^청운(객|상)$/);
expect(buildAuctionAlias(2, 'seed', config)).toMatch(/^청운(객|상)1$/);
});
it('reuses the world-persisted alias pool after general creation changes RNG inputs', () => {
const config = {
obfuscatedNamePool: ['고정별호A', '고정별호B'],
randGenFirstName: ['변경'],
randGenMiddleName: ['된'],
randGenLastName: ['이름'],
};
expect(buildAuctionAliasPool('new-seed', config)).toEqual(['고정별호A', '고정별호B']);
expect(buildAuctionAlias(0, 'new-seed', config)).toBe('고정별호A');
expect(buildAuctionAlias(1, 'new-seed', config)).toBe('고정별호B');
expect(buildAuctionAlias(2, 'new-seed', config)).toBe('고정별호A1');
});
});