Enhance world simulation and API functionality; implement clock management improvements, ensure proper handling of world states during updates, and refine data persistence methods to prevent resurrecting deleted worlds.
This commit is contained in:
@@ -24,6 +24,12 @@ describe('parseGameTime', () => {
|
||||
expect(parseGameTime('')).toBeNull();
|
||||
expect(parseGameTime('not-a-date')).toBeNull();
|
||||
});
|
||||
|
||||
it('rejects out-of-range components instead of rolling them over', () => {
|
||||
expect(parseGameTime('2012-04-12T06:00:60')).toBeNull();
|
||||
expect(parseGameTime('2012-04-12T06:60:00')).toBeNull();
|
||||
expect(parseGameTime('2012-02-30T06:00:00')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatGameTime', () => {
|
||||
@@ -65,6 +71,27 @@ describe('interpolateGameTime', () => {
|
||||
expect(date).not.toBeNull();
|
||||
expect(formatGameTime(date!)).toBe('12 April 2012 · 06:10');
|
||||
});
|
||||
|
||||
it('clamps timeScale the way the server does', () => {
|
||||
const tooFast = interpolateGameTime(
|
||||
{ gameTime: '2012-04-12T06:00:00', timeScale: 99, paused: false },
|
||||
1000,
|
||||
);
|
||||
expect(formatGameTime(tooFast!)).toBe('12 April 2012 · 06:20');
|
||||
|
||||
const tooSlow = interpolateGameTime(
|
||||
{ gameTime: '2012-04-12T06:00:00', timeScale: 0, paused: false },
|
||||
1000,
|
||||
);
|
||||
expect(formatGameTime(tooSlow!)).toBe('12 April 2012 · 06:05');
|
||||
});
|
||||
});
|
||||
|
||||
describe('startGameTimeFromInput', () => {
|
||||
it('rejects out-of-range components', () => {
|
||||
expect(startGameTimeFromInput('2012-04-12T06:60')).toBeNull();
|
||||
expect(startGameTimeFromInput('2012-04-12T06:00:60')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('startGameTimeFromInput', () => {
|
||||
|
||||
@@ -3,6 +3,10 @@ import type { WorldClock } from '../api/types';
|
||||
/** Matches server GameTime: five game minutes per real second at x1. */
|
||||
export const GAME_MINUTES_PER_REAL_SECOND = 5;
|
||||
|
||||
/** Mirrors GameTime.MinTimeScale / MaxTimeScale, which the server clamps to. */
|
||||
export const MIN_TIME_SCALE = 1;
|
||||
export const MAX_TIME_SCALE = 4;
|
||||
|
||||
const MONTHS = [
|
||||
'January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November', 'December',
|
||||
@@ -30,6 +34,7 @@ export function parseGameTime(raw: string): Date | null {
|
||||
|| date.getDate() !== day
|
||||
|| date.getHours() !== hour
|
||||
|| date.getMinutes() !== minute
|
||||
|| date.getSeconds() !== second
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -64,7 +69,10 @@ export function interpolateGameTime(
|
||||
if (!base) return null;
|
||||
if (clock.paused || elapsedRealMs <= 0) return base;
|
||||
|
||||
const scale = Number.isFinite(clock.timeScale) ? clock.timeScale : 1;
|
||||
// Clamp like the server does, so a contract drift cannot make the client draw a time nobody is simulating.
|
||||
const scale = Number.isFinite(clock.timeScale)
|
||||
? Math.min(Math.max(clock.timeScale, MIN_TIME_SCALE), MAX_TIME_SCALE)
|
||||
: MIN_TIME_SCALE;
|
||||
const gameMs = (elapsedRealMs / 1000) * GAME_MINUTES_PER_REAL_SECOND * scale * 60_000;
|
||||
return new Date(base.getTime() + gameMs);
|
||||
}
|
||||
@@ -97,6 +105,7 @@ export function startGameTimeFromInput(raw: string): string | null {
|
||||
|| date.getDate() !== day
|
||||
|| date.getHours() !== hour
|
||||
|| date.getMinutes() !== minute
|
||||
|| date.getSeconds() !== second
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user