feat: add RuntimeConstants service with get/update/reset
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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>;
|
||||
Reference in New Issue
Block a user