플레이 감사에 외교 관계 최초 관측을 기록
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { asRecord } from '@sammo-ts/common';
|
||||
import type { InMemoryTurnWorld } from '../turn/inMemoryWorld.js';
|
||||
import type { TurnDiplomacy } from '../turn/types.js';
|
||||
|
||||
@@ -99,3 +100,81 @@ export const recordTurnAuditDiplomacy = (
|
||||
after: nextState,
|
||||
});
|
||||
};
|
||||
|
||||
/** 현재 로드된 관계를 도입 시 한 번만 고정한다. 과거 발생 원인/주체는 추정하지 않는다. */
|
||||
export const initializeAuditDiplomacy = (world: InMemoryTurnWorld, observedAt = new Date()): boolean => {
|
||||
const state = world.getState();
|
||||
const serverId = state.meta.serverId;
|
||||
if (typeof serverId !== 'string' || !serverId.trim()) return false;
|
||||
const previous = asRecord(state.meta.playAuditDiplomacy);
|
||||
if (previous.serverId === serverId) {
|
||||
if (
|
||||
previous.schemaVersion !== 1 ||
|
||||
typeof previous.year !== 'number' ||
|
||||
previous.year < 0 ||
|
||||
!Number.isInteger(previous.year) ||
|
||||
!Number.isInteger(previous.month) ||
|
||||
typeof previous.month !== 'number' ||
|
||||
previous.month < 1 ||
|
||||
previous.month > 12 ||
|
||||
typeof previous.tick !== 'number' ||
|
||||
!Number.isSafeInteger(previous.tick) ||
|
||||
previous.tick < 0 ||
|
||||
typeof previous.clockRevision !== 'number' ||
|
||||
!Number.isSafeInteger(previous.clockRevision) ||
|
||||
previous.clockRevision < 0 ||
|
||||
typeof previous.relationCount !== 'number' ||
|
||||
!Number.isInteger(previous.relationCount) ||
|
||||
previous.relationCount < 0 ||
|
||||
previous.year * 12 + previous.month > state.currentYear * 12 + state.currentMonth ||
|
||||
typeof previous.observedAt !== 'string' ||
|
||||
!Number.isFinite(Date.parse(previous.observedAt))
|
||||
)
|
||||
throw new Error('Invalid play audit diplomacy boundary');
|
||||
return false;
|
||||
}
|
||||
const clock = world.getGameClockState();
|
||||
const observedAtIso = observedAt.toISOString();
|
||||
const relations = world
|
||||
.listDiplomacy()
|
||||
.filter((entry) => entry.fromNationId > 0 && entry.toNationId > 0)
|
||||
.sort((left, right) => left.fromNationId - right.fromNationId || left.toNationId - right.toNationId);
|
||||
for (const [index, entry] of relations.entries()) {
|
||||
world.queueAuditDiplomacy({
|
||||
schemaVersion: 1,
|
||||
serverId,
|
||||
srcNationId: entry.fromNationId,
|
||||
destNationId: entry.toNationId,
|
||||
category: 'RELATION',
|
||||
source: 'BASELINE',
|
||||
eventType: 'RELATION_BASELINE',
|
||||
documentId: null,
|
||||
documentHash: null,
|
||||
previousDocumentId: null,
|
||||
year: state.currentYear,
|
||||
month: state.currentMonth,
|
||||
tick: BigInt(clock.tick),
|
||||
clockRevision: BigInt(clock.revision),
|
||||
executionId: 'relation-baseline',
|
||||
ordinal: index + 1,
|
||||
requestId: null,
|
||||
inputSequence: null,
|
||||
actor: null,
|
||||
before: null,
|
||||
after: { state: entry.state, term: entry.term, dead: entry.dead },
|
||||
});
|
||||
}
|
||||
world.updateWorldMeta({
|
||||
playAuditDiplomacy: {
|
||||
schemaVersion: 1,
|
||||
serverId,
|
||||
year: state.currentYear,
|
||||
month: state.currentMonth,
|
||||
tick: clock.tick,
|
||||
clockRevision: clock.revision,
|
||||
observedAt: observedAtIso,
|
||||
relationCount: relations.length,
|
||||
},
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { initializeAuditDiplomacy } from '../playAudit/diplomacy.js';
|
||||
import { initializeAuditPolicies } from '../playAudit/policy.js';
|
||||
import { startAuditRetentionWorker } from '../playAudit/retentionWorker.js';
|
||||
import { createPlayAuditHandler, initializeAuditCollection } from '../playAudit/collection.js';
|
||||
@@ -806,6 +807,7 @@ const createTurnDaemonRuntimeWithLease = async (
|
||||
worldRef = world;
|
||||
if (!databaseFlushEnabled) {
|
||||
initializeAuditPolicies(world);
|
||||
initializeAuditDiplomacy(world, new Date(clock.nowMs()));
|
||||
initializeAuditCollection(world, new Date(clock.nowMs()));
|
||||
}
|
||||
|
||||
@@ -929,8 +931,9 @@ const createTurnDaemonRuntimeWithLease = async (
|
||||
// 복구된 clock에서 기준을 고정하고 readiness 공개 전에 원자적으로 저장한다.
|
||||
// 명령 없는 PREOPEN도 기록하며 input_event나 게임 RNG를 만들지 않는다.
|
||||
initializeAuditPolicies(world);
|
||||
const diplomacyInitialized = initializeAuditDiplomacy(world, new Date(clock.nowMs()));
|
||||
initializeAuditCollection(world, new Date(clock.nowMs()));
|
||||
if (world.hasPendingAuditRecords()) {
|
||||
if (world.hasPendingAuditRecords() || diplomacyInitialized) {
|
||||
await dbHooks.flushChanges();
|
||||
dbHooks.takeCommittedReadModelChangeReceipt();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user