초기화 시 전투 특기를 null로 정규화하고 이전 특기 배열을 보존해 다음 월 고정 배정이 daemon 재시작 없이 동작하게 한다. 다중 변경 내역이 문서 높이를 늘리도록 하고 API, 월간 persistence, 실제 Chromium 회귀 검증을 추가한다.
762 lines
24 KiB
TypeScript
762 lines
24 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
import type { TurnDaemonCommand, TurnDaemonCommandType, TurnDaemonCommandByType } from '@sammo-ts/common';
|
|
import { isCanonicalIsoTimestamp } from '@sammo-ts/common';
|
|
|
|
export type TurnDaemonCommandEnvelope = {
|
|
requestId: string;
|
|
sentAt: string;
|
|
command: TurnDaemonCommand;
|
|
};
|
|
|
|
type CommandNormalizer<T extends TurnDaemonCommandType> = (
|
|
envelope: TurnDaemonCommandEnvelope
|
|
) => TurnDaemonCommandByType<T> | null;
|
|
|
|
type CommandNormalizerMap = {
|
|
[T in TurnDaemonCommandType]?: CommandNormalizer<T>;
|
|
};
|
|
|
|
const parseWith = <T>(schema: z.ZodType<T>, value: unknown): T | null => {
|
|
const parsed = schema.safeParse(value);
|
|
return parsed.success ? parsed.data : null;
|
|
};
|
|
|
|
const zFiniteNumber = z.number().finite();
|
|
const zRecord = z.record(z.string(), z.unknown());
|
|
|
|
const zRunReason = z.enum(['schedule', 'manual', 'poke']);
|
|
const zTurnRunBudget = z.object({
|
|
budgetMs: z.number().int().positive(),
|
|
maxGenerals: z.number().int().positive(),
|
|
catchUpCap: z.number().int().positive(),
|
|
});
|
|
|
|
const zAuctionFinalize = z.object({
|
|
type: z.literal('auctionFinalize'),
|
|
auctionId: zFiniteNumber,
|
|
});
|
|
|
|
const zAuctionOpen = z.object({
|
|
type: z.literal('auctionOpen'),
|
|
generalId: zFiniteNumber,
|
|
auctionType: z.enum(['BUY_RICE', 'SELL_RICE', 'UNIQUE_ITEM']),
|
|
amount: zFiniteNumber,
|
|
closeTurnCnt: zFiniteNumber.optional(),
|
|
startBidAmount: zFiniteNumber.optional(),
|
|
finishBidAmount: zFiniteNumber.optional(),
|
|
itemKey: z.string().optional(),
|
|
});
|
|
|
|
const zAuctionBid = z.object({
|
|
type: z.literal('auctionBid'),
|
|
auctionId: zFiniteNumber,
|
|
generalId: zFiniteNumber,
|
|
amount: zFiniteNumber,
|
|
tryExtendCloseDate: z.boolean().optional(),
|
|
});
|
|
|
|
const zTroopJoin = z.object({
|
|
type: z.literal('troopJoin'),
|
|
generalId: zFiniteNumber,
|
|
troopId: zFiniteNumber,
|
|
});
|
|
|
|
const zTroopCreate = z.object({
|
|
type: z.literal('troopCreate'),
|
|
generalId: zFiniteNumber,
|
|
troopName: z.string(),
|
|
});
|
|
|
|
const zTroopExit = z.object({
|
|
type: z.literal('troopExit'),
|
|
generalId: zFiniteNumber,
|
|
});
|
|
|
|
const zTroopKick = z.object({
|
|
type: z.literal('troopKick'),
|
|
generalId: zFiniteNumber,
|
|
troopId: zFiniteNumber,
|
|
targetGeneralId: zFiniteNumber,
|
|
});
|
|
|
|
const zTroopRename = z.object({
|
|
type: z.literal('troopRename'),
|
|
generalId: zFiniteNumber,
|
|
troopId: zFiniteNumber,
|
|
troopName: z.string(),
|
|
});
|
|
|
|
const zDieOnPrestart = z.object({
|
|
type: z.literal('dieOnPrestart'),
|
|
userId: z.string().min(1),
|
|
generalId: zFiniteNumber,
|
|
});
|
|
|
|
const zEnsureDieOnPrestartStatus = z.object({
|
|
type: z.literal('ensureDieOnPrestartStatus'),
|
|
userId: z.string().min(1),
|
|
generalId: zFiniteNumber,
|
|
});
|
|
|
|
const zBuildNationCandidate = z.object({
|
|
type: z.literal('buildNationCandidate'),
|
|
userId: z.string().min(1),
|
|
generalId: zFiniteNumber,
|
|
});
|
|
|
|
const zInstantRetreat = z.object({
|
|
type: z.literal('instantRetreat'),
|
|
userId: z.string().min(1),
|
|
generalId: zFiniteNumber,
|
|
});
|
|
|
|
const zMessageRespond = z.object({
|
|
type: z.literal('messageRespond'),
|
|
userId: z.string().min(1),
|
|
generalId: z.number().int().positive(),
|
|
messageId: z.number().int().positive(),
|
|
response: z.boolean(),
|
|
});
|
|
|
|
const zVacation = z.object({
|
|
type: z.literal('vacation'),
|
|
generalId: zFiniteNumber,
|
|
});
|
|
|
|
const zSetMySetting = z.object({
|
|
type: z.literal('setMySetting'),
|
|
generalId: zFiniteNumber,
|
|
settings: z.object({
|
|
tnmt: z.number().int().optional(),
|
|
defence_train: z.number().int().optional(),
|
|
use_treatment: z.number().int().optional(),
|
|
use_auto_nation_turn: z.number().int().optional(),
|
|
}),
|
|
});
|
|
|
|
const zDropItem = z.object({
|
|
type: z.literal('dropItem'),
|
|
generalId: zFiniteNumber,
|
|
itemType: z.string().min(1),
|
|
});
|
|
|
|
const zChangePermission = z.object({
|
|
type: z.literal('changePermission'),
|
|
generalId: zFiniteNumber,
|
|
isAmbassador: z.boolean(),
|
|
targetGeneralIds: z.array(zFiniteNumber).min(1),
|
|
});
|
|
|
|
const zKick = z.object({
|
|
type: z.literal('kick'),
|
|
generalId: zFiniteNumber,
|
|
destGeneralId: zFiniteNumber,
|
|
});
|
|
|
|
const zAppoint = z.object({
|
|
type: z.literal('appoint'),
|
|
generalId: zFiniteNumber,
|
|
destGeneralId: zFiniteNumber,
|
|
destCityId: zFiniteNumber,
|
|
officerLevel: zFiniteNumber,
|
|
});
|
|
|
|
const zTournamentRefund = z.object({
|
|
type: z.literal('tournamentRefund'),
|
|
bettingId: zFiniteNumber.optional(),
|
|
reason: z.string().optional(),
|
|
refunds: z.array(z.object({ generalId: zFiniteNumber, amount: zFiniteNumber })).min(1),
|
|
});
|
|
|
|
const zTournamentBettingPayout = z.object({
|
|
type: z.literal('tournamentBettingPayout'),
|
|
bettingId: zFiniteNumber.optional(),
|
|
reason: z.string().optional(),
|
|
payouts: z.array(z.object({ generalId: zFiniteNumber, amount: zFiniteNumber })).min(1),
|
|
});
|
|
|
|
const zTournamentReward = z.object({
|
|
type: z.literal('tournamentReward'),
|
|
tournamentType: zFiniteNumber,
|
|
winnerId: zFiniteNumber,
|
|
runnerUpId: zFiniteNumber,
|
|
top16: z.array(zFiniteNumber).min(1),
|
|
top8: z.array(zFiniteNumber),
|
|
top4: z.array(zFiniteNumber),
|
|
});
|
|
|
|
const zVoteReward = z.object({
|
|
type: z.literal('voteReward'),
|
|
voteId: zFiniteNumber,
|
|
generalId: zFiniteNumber,
|
|
goldReward: zFiniteNumber,
|
|
unique: z
|
|
.object({
|
|
expected: z.boolean(),
|
|
itemKey: z.string().nullable().optional(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
const zSetNationMeta = z.object({
|
|
type: z.literal('setNationMeta'),
|
|
nationId: zFiniteNumber,
|
|
updates: zRecord,
|
|
expectedUpdatedAt: z.string().optional(),
|
|
});
|
|
|
|
const zAdjustGeneralResources = z.object({
|
|
type: z.literal('adjustGeneralResources'),
|
|
reason: z.string().optional(),
|
|
adjustments: z
|
|
.array(
|
|
z
|
|
.object({
|
|
generalId: zFiniteNumber,
|
|
goldDelta: zFiniteNumber.optional(),
|
|
riceDelta: zFiniteNumber.optional(),
|
|
minGoldAfter: zFiniteNumber.optional(),
|
|
})
|
|
.refine((value) => value.goldDelta !== undefined || value.riceDelta !== undefined)
|
|
)
|
|
.min(1),
|
|
});
|
|
|
|
const zAdjustGeneralMeta = z.object({
|
|
type: z.literal('adjustGeneralMeta'),
|
|
reason: z.string().optional(),
|
|
adjustments: z
|
|
.array(
|
|
z.object({
|
|
generalId: zFiniteNumber,
|
|
metaDelta: z.record(z.string(), zFiniteNumber),
|
|
})
|
|
)
|
|
.min(1),
|
|
});
|
|
|
|
const zTournamentMatchResult = z.object({
|
|
type: z.literal('tournamentMatchResult'),
|
|
tournamentType: zFiniteNumber,
|
|
attackerId: zFiniteNumber,
|
|
defenderId: zFiniteNumber,
|
|
result: z.enum(['attacker', 'defender', 'draw']),
|
|
});
|
|
|
|
const zPatchGeneral = z.object({
|
|
type: z.literal('patchGeneral'),
|
|
generalId: zFiniteNumber,
|
|
patch: z.object({
|
|
meta: zRecord.optional(),
|
|
turnTime: z.string().optional(),
|
|
stats: z
|
|
.object({
|
|
leadership: zFiniteNumber.optional(),
|
|
strength: zFiniteNumber.optional(),
|
|
intelligence: zFiniteNumber.optional(),
|
|
})
|
|
.optional(),
|
|
specialWar: z.string().nullable().optional(),
|
|
}),
|
|
});
|
|
|
|
const zAdjustGeneralIcon = z
|
|
.object({
|
|
type: z.literal('adjustGeneralIcon'),
|
|
requestId: z.string().min(1).optional(),
|
|
userId: z.string().min(1),
|
|
picture: z.string().min(1),
|
|
imageServer: z.number().int().nonnegative(),
|
|
iconRevision: z.string().refine(isCanonicalIsoTimestamp),
|
|
enforceCooldown: z.boolean().optional(),
|
|
})
|
|
.strict();
|
|
|
|
const zJoinCreateGeneral = z
|
|
.object({
|
|
type: z.literal('joinCreateGeneral'),
|
|
requestId: z.string().optional(),
|
|
userId: z.string().min(1),
|
|
ownerDisplayName: z.string(),
|
|
seedOwnerIdentity: z.union([z.string().min(1), zFiniteNumber]),
|
|
name: z.string().min(1).max(18),
|
|
leadership: zFiniteNumber,
|
|
strength: zFiniteNumber,
|
|
intel: zFiniteNumber,
|
|
pic: z.boolean(),
|
|
character: z.string().min(1),
|
|
profileId: z.string().min(1),
|
|
ownerPicture: z.string().optional(),
|
|
ownerImageServer: zFiniteNumber.optional(),
|
|
ownerIconRevision: z.string().refine(isCanonicalIsoTimestamp).optional(),
|
|
ownerCanUsePicture: z.boolean().optional(),
|
|
ownerLegacyPenalty: zRecord.optional(),
|
|
inheritSpecial: z.string().optional(),
|
|
inheritTurntimeZone: zFiniteNumber.optional(),
|
|
inheritCity: zFiniteNumber.optional(),
|
|
inheritBonusStat: z.tuple([zFiniteNumber, zFiniteNumber, zFiniteNumber]).optional(),
|
|
})
|
|
.strict();
|
|
|
|
const zNpcPossessGeneral = z
|
|
.object({
|
|
type: z.literal('npcPossessGeneral'),
|
|
requestId: z.string().optional(),
|
|
userId: z.string().min(1),
|
|
ownerDisplayName: z.string(),
|
|
profileId: z.string().min(1),
|
|
ownerLegacyPenalty: zRecord.optional(),
|
|
generalId: z.number().int().positive(),
|
|
tokenNonce: z.number().int().nonnegative(),
|
|
acceptedGameAt: z.string().refine(isCanonicalIsoTimestamp).optional(),
|
|
})
|
|
.strict();
|
|
|
|
const zSelectPoolCreate = z
|
|
.object({
|
|
type: z.literal('selectPoolCreate'),
|
|
requestId: z.string().optional(),
|
|
userId: z.string().min(1),
|
|
ownerDisplayName: z.string().min(1),
|
|
uniqueName: z.string().min(1).max(20),
|
|
personality: z.string().min(1),
|
|
seedOwnerIdentity: z.union([z.string().min(1), zFiniteNumber]),
|
|
ownerPicture: z.string().optional(),
|
|
ownerImageServer: z.number().int().nonnegative().optional(),
|
|
ownerIconRevision: z.string().refine(isCanonicalIsoTimestamp).optional(),
|
|
})
|
|
.strict();
|
|
|
|
const zSelectPoolReselect = z
|
|
.object({
|
|
type: z.literal('selectPoolReselect'),
|
|
requestId: z.string().optional(),
|
|
userId: z.string().min(1),
|
|
ownerDisplayName: z.string().min(1),
|
|
uniqueName: z.string().min(1).max(20),
|
|
})
|
|
.strict();
|
|
|
|
const zGetStatus = z.object({
|
|
type: z.literal('getStatus'),
|
|
requestId: z.string().optional(),
|
|
});
|
|
|
|
const zRun = z.object({
|
|
type: z.literal('run'),
|
|
reason: zRunReason,
|
|
targetTime: z.string().optional(),
|
|
budget: zTurnRunBudget.optional(),
|
|
});
|
|
|
|
const zPause = z.object({
|
|
type: z.literal('pause'),
|
|
reason: z.string().optional(),
|
|
});
|
|
|
|
const zResume = z.object({
|
|
type: z.literal('resume'),
|
|
reason: z.string().optional(),
|
|
});
|
|
|
|
const zShutdown = z.object({
|
|
type: z.literal('shutdown'),
|
|
reason: z.string().optional(),
|
|
});
|
|
|
|
const zShiftSchedule = z.object({
|
|
type: z.literal('shiftSchedule'),
|
|
actionId: z.string().uuid(),
|
|
deltaMinutes: z
|
|
.number()
|
|
.int()
|
|
.min(-1440)
|
|
.max(1440)
|
|
.refine((value) => value !== 0),
|
|
});
|
|
|
|
const zRuntimeAutorunOption = z.enum(['develop', 'warp', 'recruit', 'recruit_high', 'train', 'battle', 'chief']);
|
|
|
|
const zUpdateRuntimeSettings = z.object({
|
|
type: z.literal('updateRuntimeSettings'),
|
|
actionId: z.string().uuid(),
|
|
settings: z
|
|
.object({
|
|
turnTermMinutes: z
|
|
.number()
|
|
.int()
|
|
.refine((value) => [1, 2, 5, 10, 20, 30, 60, 120].includes(value))
|
|
.optional(),
|
|
blockGeneralCreate: z.union([z.literal(0), z.literal(1), z.literal(2)]).optional(),
|
|
autorunUser: z
|
|
.object({
|
|
limitMinutes: z.number().int().min(1).max(43200),
|
|
options: z.array(zRuntimeAutorunOption).min(1),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
})
|
|
.refine((settings) => Object.values(settings).some((value) => value !== undefined)),
|
|
});
|
|
|
|
const normalizeAuctionFinalize: CommandNormalizer<'auctionFinalize'> = (envelope) => {
|
|
const command = parseWith(zAuctionFinalize, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeAuctionOpen: CommandNormalizer<'auctionOpen'> = (envelope) => {
|
|
const command = parseWith(zAuctionOpen, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeAuctionBid: CommandNormalizer<'auctionBid'> = (envelope) => {
|
|
const command = parseWith(zAuctionBid, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTroopJoin: CommandNormalizer<'troopJoin'> = (envelope) => {
|
|
const command = parseWith(zTroopJoin, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTroopCreate: CommandNormalizer<'troopCreate'> = (envelope) => {
|
|
const command = parseWith(zTroopCreate, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTroopExit: CommandNormalizer<'troopExit'> = (envelope) => {
|
|
const command = parseWith(zTroopExit, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTroopKick: CommandNormalizer<'troopKick'> = (envelope) => {
|
|
const command = parseWith(zTroopKick, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTroopRename: CommandNormalizer<'troopRename'> = (envelope) => {
|
|
const command = parseWith(zTroopRename, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeDieOnPrestart: CommandNormalizer<'dieOnPrestart'> = (envelope) => {
|
|
const command = parseWith(zDieOnPrestart, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeEnsureDieOnPrestartStatus: CommandNormalizer<'ensureDieOnPrestartStatus'> = (envelope) => {
|
|
const command = parseWith(zEnsureDieOnPrestartStatus, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeBuildNationCandidate: CommandNormalizer<'buildNationCandidate'> = (envelope) => {
|
|
const command = parseWith(zBuildNationCandidate, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeInstantRetreat: CommandNormalizer<'instantRetreat'> = (envelope) => {
|
|
const command = parseWith(zInstantRetreat, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeMessageRespond: CommandNormalizer<'messageRespond'> = (envelope) => {
|
|
const command = parseWith(zMessageRespond, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeVacation: CommandNormalizer<'vacation'> = (envelope) => {
|
|
const command = parseWith(zVacation, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeSetMySetting: CommandNormalizer<'setMySetting'> = (envelope) => {
|
|
const command = parseWith(zSetMySetting, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeDropItem: CommandNormalizer<'dropItem'> = (envelope) => {
|
|
const command = parseWith(zDropItem, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeChangePermission: CommandNormalizer<'changePermission'> = (envelope) => {
|
|
const command = parseWith(zChangePermission, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeKick: CommandNormalizer<'kick'> = (envelope) => {
|
|
const command = parseWith(zKick, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeAppoint: CommandNormalizer<'appoint'> = (envelope) => {
|
|
const command = parseWith(zAppoint, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTournamentRefund: CommandNormalizer<'tournamentRefund'> = (envelope) => {
|
|
const command = parseWith(zTournamentRefund, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTournamentBettingPayout: CommandNormalizer<'tournamentBettingPayout'> = (envelope) => {
|
|
const command = parseWith(zTournamentBettingPayout, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTournamentReward: CommandNormalizer<'tournamentReward'> = (envelope) => {
|
|
const command = parseWith(zTournamentReward, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeVoteReward: CommandNormalizer<'voteReward'> = (envelope) => {
|
|
const command = parseWith(zVoteReward, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeSetNationMeta: CommandNormalizer<'setNationMeta'> = (envelope) => {
|
|
const command = parseWith(zSetNationMeta, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeAdjustGeneralResources: CommandNormalizer<'adjustGeneralResources'> = (envelope) => {
|
|
const command = parseWith(zAdjustGeneralResources, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeAdjustGeneralMeta: CommandNormalizer<'adjustGeneralMeta'> = (envelope) => {
|
|
const command = parseWith(zAdjustGeneralMeta, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeTournamentMatchResult: CommandNormalizer<'tournamentMatchResult'> = (envelope) => {
|
|
const command = parseWith(zTournamentMatchResult, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizePatchGeneral: CommandNormalizer<'patchGeneral'> = (envelope) => {
|
|
const command = parseWith(zPatchGeneral, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeAdjustGeneralIcon: CommandNormalizer<'adjustGeneralIcon'> = (envelope) => {
|
|
const command = parseWith(zAdjustGeneralIcon, envelope.command);
|
|
if (!command || (command.requestId !== undefined && command.requestId !== envelope.requestId)) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeJoinCreateGeneral: CommandNormalizer<'joinCreateGeneral'> = (envelope) => {
|
|
const command = parseWith(zJoinCreateGeneral, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeNpcPossessGeneral: CommandNormalizer<'npcPossessGeneral'> = (envelope) => {
|
|
const command = parseWith(zNpcPossessGeneral, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeSelectPoolCreate: CommandNormalizer<'selectPoolCreate'> = (envelope) => {
|
|
const command = parseWith(zSelectPoolCreate, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeSelectPoolReselect: CommandNormalizer<'selectPoolReselect'> = (envelope) => {
|
|
const command = parseWith(zSelectPoolReselect, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeGetStatus: CommandNormalizer<'getStatus'> = (envelope) => {
|
|
const command = parseWith(zGetStatus, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: 'getStatus',
|
|
requestId: command.requestId ?? envelope.requestId,
|
|
};
|
|
};
|
|
|
|
const normalizeRun: CommandNormalizer<'run'> = (envelope) => {
|
|
const command = parseWith(zRun, envelope.command);
|
|
return command ? { ...command, requestId: envelope.requestId } : null;
|
|
};
|
|
const normalizePause: CommandNormalizer<'pause'> = (envelope) => {
|
|
const command = parseWith(zPause, envelope.command);
|
|
return command ? { ...command, requestId: envelope.requestId } : null;
|
|
};
|
|
const normalizeResume: CommandNormalizer<'resume'> = (envelope) => {
|
|
const command = parseWith(zResume, envelope.command);
|
|
return command ? { ...command, requestId: envelope.requestId } : null;
|
|
};
|
|
const normalizeShutdown: CommandNormalizer<'shutdown'> = (envelope) => {
|
|
const command = parseWith(zShutdown, envelope.command);
|
|
return command ? { ...command, requestId: envelope.requestId } : null;
|
|
};
|
|
|
|
const normalizeShiftSchedule: CommandNormalizer<'shiftSchedule'> = (envelope) => {
|
|
const command = parseWith(zShiftSchedule, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizeUpdateRuntimeSettings: CommandNormalizer<'updateRuntimeSettings'> = (envelope) => {
|
|
const command = parseWith(zUpdateRuntimeSettings, envelope.command);
|
|
if (!command) {
|
|
return null;
|
|
}
|
|
return { ...command, requestId: envelope.requestId };
|
|
};
|
|
|
|
const normalizers: CommandNormalizerMap = {
|
|
auctionFinalize: normalizeAuctionFinalize,
|
|
auctionOpen: normalizeAuctionOpen,
|
|
auctionBid: normalizeAuctionBid,
|
|
troopCreate: normalizeTroopCreate,
|
|
troopJoin: normalizeTroopJoin,
|
|
troopExit: normalizeTroopExit,
|
|
troopKick: normalizeTroopKick,
|
|
troopRename: normalizeTroopRename,
|
|
dieOnPrestart: normalizeDieOnPrestart,
|
|
ensureDieOnPrestartStatus: normalizeEnsureDieOnPrestartStatus,
|
|
buildNationCandidate: normalizeBuildNationCandidate,
|
|
instantRetreat: normalizeInstantRetreat,
|
|
messageRespond: normalizeMessageRespond,
|
|
vacation: normalizeVacation,
|
|
setMySetting: normalizeSetMySetting,
|
|
dropItem: normalizeDropItem,
|
|
changePermission: normalizeChangePermission,
|
|
kick: normalizeKick,
|
|
appoint: normalizeAppoint,
|
|
tournamentRefund: normalizeTournamentRefund,
|
|
tournamentBettingPayout: normalizeTournamentBettingPayout,
|
|
tournamentReward: normalizeTournamentReward,
|
|
voteReward: normalizeVoteReward,
|
|
setNationMeta: normalizeSetNationMeta,
|
|
adjustGeneralResources: normalizeAdjustGeneralResources,
|
|
adjustGeneralMeta: normalizeAdjustGeneralMeta,
|
|
tournamentMatchResult: normalizeTournamentMatchResult,
|
|
patchGeneral: normalizePatchGeneral,
|
|
adjustGeneralIcon: normalizeAdjustGeneralIcon,
|
|
joinCreateGeneral: normalizeJoinCreateGeneral,
|
|
npcPossessGeneral: normalizeNpcPossessGeneral,
|
|
selectPoolCreate: normalizeSelectPoolCreate,
|
|
selectPoolReselect: normalizeSelectPoolReselect,
|
|
getStatus: normalizeGetStatus,
|
|
run: normalizeRun,
|
|
pause: normalizePause,
|
|
resume: normalizeResume,
|
|
shutdown: normalizeShutdown,
|
|
shiftSchedule: normalizeShiftSchedule,
|
|
updateRuntimeSettings: normalizeUpdateRuntimeSettings,
|
|
};
|
|
|
|
export const normalizeTurnDaemonCommand = (envelope: TurnDaemonCommandEnvelope): TurnDaemonCommand | null => {
|
|
const commandType = envelope.command.type as TurnDaemonCommandType;
|
|
const normalizer = normalizers[commandType];
|
|
if (!normalizer) {
|
|
return null;
|
|
}
|
|
return normalizer(envelope) as TurnDaemonCommand | null;
|
|
};
|