가오픈 장수 턴의 오픈 전 적체 방지
This commit is contained in:
@@ -656,6 +656,16 @@ export class InMemoryTurnWorld {
|
||||
return this.getGameClock().now(wallNow);
|
||||
}
|
||||
|
||||
getRunnableGameNow(wallNow: Date): Date {
|
||||
const clock = this.getGameClock();
|
||||
// PREOPEN still needs negative game ticks for cooldowns, but executable
|
||||
// turn schedules must not precede the wall-clock opening boundary.
|
||||
if (clock.mode === 'realtime' && wallNow.getTime() < clock.wallAnchor.getTime()) {
|
||||
return clock.now(clock.wallAnchor);
|
||||
}
|
||||
return clock.now(wallNow);
|
||||
}
|
||||
|
||||
dateToGameTick(date: Date): number {
|
||||
return this.getGameClock().dateToTick(date);
|
||||
}
|
||||
|
||||
@@ -383,7 +383,9 @@ export const resolveJoinTurnTime = (
|
||||
}
|
||||
let turnTime = new Date(turnTimeBase.getTime() + offsetSeconds * 1000 + offsetMicros / 1000);
|
||||
if (turnTime.getTime() <= acceptedAt.getTime()) {
|
||||
turnTime = new Date(turnTime.getTime() + tickSeconds * 1000);
|
||||
const termMs = tickSeconds * 1000;
|
||||
const missedTerms = Math.floor((acceptedAt.getTime() - turnTime.getTime()) / termMs) + 1;
|
||||
turnTime = new Date(turnTime.getTime() + missedTerms * termMs);
|
||||
}
|
||||
return turnTime;
|
||||
};
|
||||
@@ -523,9 +525,11 @@ export const createGeneralFromJoin = async (options: {
|
||||
worldState: WorldStateRow;
|
||||
input: JoinCreateGeneralInput;
|
||||
acceptedAt: Date;
|
||||
turnScheduleAt?: Date;
|
||||
operationalAcceptedAt: Date;
|
||||
}): Promise<{ ok: true; generalId: number }> => {
|
||||
const { db, world, worldState, input, acceptedAt, operationalAcceptedAt } = options;
|
||||
const turnScheduleAt = options.turnScheduleAt ?? acceptedAt;
|
||||
await lockJoinMutation(db, input.userId);
|
||||
await assertGeneralIdSnapshotMatches(db, world);
|
||||
|
||||
@@ -707,7 +711,7 @@ export const createGeneralFromJoin = async (options: {
|
||||
const turnTime = resolveJoinTurnTime(
|
||||
rng,
|
||||
worldState,
|
||||
acceptedAt,
|
||||
turnScheduleAt,
|
||||
world.getState().lastTurnTime,
|
||||
input.inheritTurntimeZone
|
||||
);
|
||||
|
||||
@@ -651,11 +651,18 @@ const resolveTurnTimeBase = (worldState: WorldStateRow, now: Date): Date => {
|
||||
return now;
|
||||
};
|
||||
|
||||
const buildInitialTurnTime = (rng: RandUtil, worldState: WorldStateRow, now: Date): Date => {
|
||||
export const buildInitialTurnTime = (
|
||||
rng: Pick<RandUtil, 'nextRangeInt'>,
|
||||
worldState: WorldStateRow,
|
||||
now: Date,
|
||||
notBefore: Date = now
|
||||
): Date => {
|
||||
const termSeconds = resolveTurnTermMinutes(worldState) * 60;
|
||||
const seconds = rng.nextRangeInt(0, termSeconds - 1);
|
||||
const microseconds = rng.nextRangeInt(0, 999_999);
|
||||
return new Date(resolveTurnTimeBase(worldState, now).getTime() + seconds * 1000 + microseconds / 1000);
|
||||
const base = resolveTurnTimeBase(worldState, now);
|
||||
const safeBase = base.getTime() < notBefore.getTime() ? notBefore : base;
|
||||
return new Date(safeBase.getTime() + seconds * 1000 + microseconds / 1000);
|
||||
};
|
||||
|
||||
const appendSelectionLogs = async (options: {
|
||||
@@ -702,6 +709,7 @@ export const createGeneralFromSelectionPool = async (options: {
|
||||
uniqueName: string;
|
||||
personality: string;
|
||||
now?: Date;
|
||||
turnScheduleAt?: Date;
|
||||
operationalAcceptedAt: Date;
|
||||
seedOwnerIdentity?: string | number;
|
||||
ownerPicture?: string;
|
||||
@@ -761,7 +769,7 @@ export const createGeneralFromSelectionPool = async (options: {
|
||||
);
|
||||
}
|
||||
const city = rng.choice(cities);
|
||||
const turnTime = buildInitialTurnTime(rng, worldState, now);
|
||||
const turnTime = buildInitialTurnTime(rng, worldState, now, options.turnScheduleAt ?? now);
|
||||
const age = 20;
|
||||
const specialityAges = resolveSpecialityAges(worldState, age);
|
||||
const nextChangeAt = new Date(
|
||||
|
||||
@@ -340,6 +340,7 @@ async function handleJoinCreateGeneral(
|
||||
}
|
||||
const operationalAcceptedAt = await resolveCommandAcceptedAt(db, command);
|
||||
const acceptedAt = ctx.world.getGameNow(operationalAcceptedAt);
|
||||
const turnScheduleAt = ctx.world.getRunnableGameNow(operationalAcceptedAt);
|
||||
try {
|
||||
return {
|
||||
type: 'joinCreateGeneral',
|
||||
@@ -377,6 +378,7 @@ async function handleJoinCreateGeneral(
|
||||
...(command.inheritBonusStat !== undefined ? { inheritBonusStat: command.inheritBonusStat } : {}),
|
||||
},
|
||||
acceptedAt,
|
||||
turnScheduleAt,
|
||||
operationalAcceptedAt,
|
||||
})),
|
||||
};
|
||||
@@ -455,6 +457,7 @@ async function handleSelectPoolCreate(
|
||||
: command.acceptedGameAt !== undefined
|
||||
? new Date(command.acceptedGameAt)
|
||||
: ctx.world.getGameNow(operationalAcceptedAt);
|
||||
const turnScheduleAt = ctx.world.getRunnableGameNow(operationalAcceptedAt);
|
||||
try {
|
||||
return {
|
||||
type: 'selectPoolCreate',
|
||||
@@ -471,6 +474,7 @@ async function handleSelectPoolCreate(
|
||||
...(command.ownerImageServer !== undefined ? { ownerImageServer: command.ownerImageServer } : {}),
|
||||
...(command.ownerIconRevision ? { ownerIconRevision: command.ownerIconRevision } : {}),
|
||||
now: acceptedAt,
|
||||
turnScheduleAt,
|
||||
operationalAcceptedAt,
|
||||
})),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user