Files
core2026/tools/seed-parity/create-user-generals.mjs
T

80 lines
3.1 KiB
JavaScript

#!/usr/bin/env node
import { DatabaseTurnDaemonTransport } from '../../app/game-api/dist/index.js';
import {
createTurnDaemonRuntime,
resolveDatabaseUrl,
} from '../../app/game-engine/dist/index.js';
import { createGamePostgresConnector } from '../../packages/infra/dist/index.js';
const userCount = Number.parseInt(process.env.SEED_PARITY_USER_COUNT ?? '2', 10);
if (!Number.isInteger(userCount) || userCount < 1 || userCount > 10) {
throw new Error('SEED_PARITY_USER_COUNT must be an integer between 1 and 10');
}
const databaseUrl = await resolveDatabaseUrl();
const profile = process.env.PROFILE ?? 'hwe';
const connector = createGamePostgresConnector({ url: databaseUrl });
await connector.connect();
const runtime = await createTurnDaemonRuntime({
profile,
databaseUrl,
enableDatabaseFlush: true,
enableLeaseHeartbeat: false,
leaseOwnerId: `${profile}-seed-parity-user-setup`,
gameClockMode: 'manual',
});
const daemon = new DatabaseTurnDaemonTransport(connector.prisma, 30_000);
// Manual mode intentionally advances scheduled turns without wall-clock waits.
// Pause before the loop starts so this setup command cannot consume month 1.
runtime.lifecycle.pause('seed parity user setup');
const daemonLoop = runtime.lifecycle.start();
try {
await daemon.requestStatus(30_000);
for (let number = 1; number <= userCount; number += 1) {
const userId = `gc2400-user-${String(number).padStart(2, '0')}`;
const ownerDisplayName = `올스타${String(number).padStart(2, '0')}`;
const generalName = `비교유저${String(number).padStart(2, '0')}`;
const result = await daemon.requestCommand(
{
type: 'joinCreateGeneral',
userId,
ownerDisplayName,
seedOwnerIdentity: number + 1,
name: generalName,
leadership: 100,
strength: 105,
intel: 105,
pic: false,
character: 'che_안전',
profileId: profile,
},
30_000
);
if (result?.type !== 'joinCreateGeneral' || !result.ok) {
throw new Error(`Failed to create ${userId}: ${JSON.stringify(result)}`);
}
// Match the one explicit legacy appointment reservation. The remaining
// slots stay as Rest so the scenario's autorun-user policy owns them.
await connector.prisma.$transaction([
connector.prisma.generalTurn.update({
where: { generalId_turnIdx: { generalId: result.generalId, turnIdx: 0 } },
data: { actionCode: 'che_랜덤임관', arg: {} },
}),
connector.prisma.generalTurnRevision.update({
where: { generalId: result.generalId },
data: { revision: { increment: 1 } },
}),
]);
console.log(`${userId} created ${generalName} as general ${result.generalId}`);
}
} finally {
await runtime.lifecycle.stop('seed parity user setup complete');
await daemonLoop;
await runtime.close();
await connector.disconnect();
}