feat: add RuntimeConstants service with get/update/reset

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-10 02:17:50 +00:00
parent f8cb83481e
commit 0d93574e76
2 changed files with 94 additions and 0 deletions
@@ -0,0 +1,42 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { createRuntimeConstants } from '../runtimeConstants.js';
describe('RuntimeConstants', () => {
let rc: ReturnType<typeof createRuntimeConstants>;
beforeEach(() => {
rc = createRuntimeConstants();
});
it('initializes with default values from shared constants', () => {
const constants = rc.getAll();
expect(constants.TICK_RATE).toBe(10);
expect(constants.HUNGER_DECAY_PER_TICK).toBe(0.05);
expect(constants.AWARENESS_RADIUS).toBe(5);
});
it('updates a single constant', () => {
rc.update('TICK_RATE', 20);
expect(rc.getAll().TICK_RATE).toBe(20);
});
it('rejects unknown keys gracefully', () => {
const result = rc.update('NOT_A_KEY' as any, 5);
expect(result).toBe(false);
});
it('resets all to defaults', () => {
rc.update('TICK_RATE', 20);
rc.update('HUNGER_DECAY_PER_TICK', 1.0);
rc.resetDefaults();
const constants = rc.getAll();
expect(constants.TICK_RATE).toBe(10);
expect(constants.HUNGER_DECAY_PER_TICK).toBe(0.05);
});
it('get() returns individual constant value', () => {
expect(rc.get('MOVE_SPEED')).toBe(0.75);
rc.update('MOVE_SPEED', 1.5);
expect(rc.get('MOVE_SPEED')).toBe(1.5);
});
});
+52
View File
@@ -0,0 +1,52 @@
import type { TunableConstants, TunableKey } from '@dflike/shared';
import {
TICK_RATE, BROADCAST_EVERY_N_TICKS,
HUNGER_DECAY_PER_TICK, ENERGY_DECAY_PER_TICK, HUNGER_THRESHOLD, ENERGY_THRESHOLD, NEED_RECOVERY_RATE,
SLEEP_ENERGY_RECOVERY_PER_TICK, SLEEP_HUNGER_DECAY_MULTIPLIER, SLEEP_WAKE_THRESHOLD, SLEEP_VOLUNTARY_ENERGY_THRESHOLD,
PRODUCTIVITY_DECAY_PER_TICK, PRODUCTIVITY_THRESHOLD, PRODUCTIVITY_RECOVERY_RATE,
DAY_NIGHT_RATIO, DAY_HOURS, SUNSET_DURATION_HOURS, SUNRISE_DURATION_HOURS, NIGHT_DARKNESS,
AWARENESS_RADIUS, FACING_DURATION, PAUSING_DURATION, EMOTING_DURATION,
SOCIAL_GLOBAL_COOLDOWN, SOCIAL_PAIR_COOLDOWN, PROPOSAL_EMOTING_DURATION,
MAX_NPC_COUNT, MOVE_SPEED,
} from '@dflike/shared';
const DEFAULTS: TunableConstants = {
TICK_RATE, BROADCAST_EVERY_N_TICKS,
HUNGER_DECAY_PER_TICK, ENERGY_DECAY_PER_TICK, HUNGER_THRESHOLD, ENERGY_THRESHOLD, NEED_RECOVERY_RATE,
SLEEP_ENERGY_RECOVERY_PER_TICK, SLEEP_HUNGER_DECAY_MULTIPLIER, SLEEP_WAKE_THRESHOLD, SLEEP_VOLUNTARY_ENERGY_THRESHOLD,
PRODUCTIVITY_DECAY_PER_TICK, PRODUCTIVITY_THRESHOLD, PRODUCTIVITY_RECOVERY_RATE,
DAY_NIGHT_RATIO, DAY_HOURS, SUNSET_DURATION_HOURS, SUNRISE_DURATION_HOURS, NIGHT_DARKNESS,
AWARENESS_RADIUS, FACING_DURATION, PAUSING_DURATION, EMOTING_DURATION,
SOCIAL_GLOBAL_COOLDOWN, SOCIAL_PAIR_COOLDOWN, PROPOSAL_EMOTING_DURATION,
MAX_NPC_COUNT, MOVE_SPEED,
};
export function createRuntimeConstants() {
const current: TunableConstants = { ...DEFAULTS };
return {
get<K extends TunableKey>(key: K): TunableConstants[K] {
return current[key];
},
getAll(): TunableConstants {
return { ...current };
},
update(key: TunableKey, value: number): boolean {
if (!(key in DEFAULTS)) return false;
current[key] = value;
return true;
},
resetDefaults(): void {
Object.assign(current, DEFAULTS);
},
getDefaults(): TunableConstants {
return { ...DEFAULTS };
},
};
}
export type RuntimeConstants = ReturnType<typeof createRuntimeConstants>;