193 lines
5.7 KiB
TypeScript
193 lines
5.7 KiB
TypeScript
import { eq } from "drizzle-orm";
|
|
import { gameSettings } from "@db/schema";
|
|
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
|
import type {
|
|
LevelingConfig,
|
|
EconomyConfig,
|
|
InventoryConfig,
|
|
LootdropConfig,
|
|
TriviaConfig,
|
|
ModerationConfig,
|
|
} from "@db/schema/game-settings";
|
|
|
|
export type GameSettingsData = {
|
|
leveling: LevelingConfig;
|
|
economy: EconomyConfig;
|
|
inventory: InventoryConfig;
|
|
lootdrop: LootdropConfig;
|
|
trivia: TriviaConfig;
|
|
moderation: ModerationConfig;
|
|
commands: Record<string, boolean>;
|
|
system: Record<string, unknown>;
|
|
};
|
|
|
|
let cachedSettings: GameSettingsData | null = null;
|
|
let cacheTimestamp = 0;
|
|
const CACHE_TTL_MS = 30000;
|
|
|
|
export const gameSettingsService = {
|
|
getSettings: async (useCache = true): Promise<GameSettingsData | null> => {
|
|
if (useCache && cachedSettings && Date.now() - cacheTimestamp < CACHE_TTL_MS) {
|
|
return cachedSettings;
|
|
}
|
|
|
|
const settings = await DrizzleClient.query.gameSettings.findFirst({
|
|
where: eq(gameSettings.id, "default"),
|
|
});
|
|
|
|
if (!settings) return null;
|
|
|
|
cachedSettings = {
|
|
leveling: settings.leveling,
|
|
economy: settings.economy,
|
|
inventory: settings.inventory,
|
|
lootdrop: settings.lootdrop,
|
|
trivia: settings.trivia,
|
|
moderation: settings.moderation,
|
|
commands: settings.commands ?? {},
|
|
system: settings.system ?? {},
|
|
};
|
|
cacheTimestamp = Date.now();
|
|
|
|
return cachedSettings;
|
|
},
|
|
|
|
upsertSettings: async (data: Partial<GameSettingsData>) => {
|
|
const existing = await gameSettingsService.getSettings(false);
|
|
|
|
const values: typeof gameSettings.$inferInsert = {
|
|
id: "default",
|
|
leveling: data.leveling ?? existing?.leveling ?? gameSettingsService.getDefaultLeveling(),
|
|
economy: data.economy ?? existing?.economy ?? gameSettingsService.getDefaultEconomy(),
|
|
inventory: data.inventory ?? existing?.inventory ?? gameSettingsService.getDefaultInventory(),
|
|
lootdrop: data.lootdrop ?? existing?.lootdrop ?? gameSettingsService.getDefaultLootdrop(),
|
|
trivia: data.trivia ?? existing?.trivia ?? gameSettingsService.getDefaultTrivia(),
|
|
moderation: data.moderation ?? existing?.moderation ?? gameSettingsService.getDefaultModeration(),
|
|
commands: data.commands ?? existing?.commands ?? {},
|
|
system: data.system ?? existing?.system ?? {},
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
const [result] = await DrizzleClient.insert(gameSettings)
|
|
.values(values)
|
|
.onConflictDoUpdate({
|
|
target: gameSettings.id,
|
|
set: values,
|
|
})
|
|
.returning();
|
|
|
|
gameSettingsService.invalidateCache();
|
|
|
|
return result;
|
|
},
|
|
|
|
updateSection: async <K extends keyof GameSettingsData>(
|
|
section: K,
|
|
value: GameSettingsData[K]
|
|
) => {
|
|
const existing = await gameSettingsService.getSettings(false);
|
|
|
|
if (!existing) {
|
|
throw new Error("Game settings not found. Initialize settings first.");
|
|
}
|
|
|
|
const updates: Partial<GameSettingsData> = { [section]: value };
|
|
await gameSettingsService.upsertSettings(updates);
|
|
|
|
gameSettingsService.invalidateCache();
|
|
},
|
|
|
|
toggleCommand: async (commandName: string, enabled: boolean) => {
|
|
const settings = await gameSettingsService.getSettings(false);
|
|
|
|
if (!settings) {
|
|
throw new Error("Game settings not found. Initialize settings first.");
|
|
}
|
|
|
|
const commands = {
|
|
...settings.commands,
|
|
[commandName]: enabled,
|
|
};
|
|
|
|
await gameSettingsService.updateSection("commands", commands);
|
|
},
|
|
|
|
invalidateCache: () => {
|
|
cachedSettings = null;
|
|
cacheTimestamp = 0;
|
|
},
|
|
|
|
getDefaultLeveling: (): LevelingConfig => ({
|
|
base: 100,
|
|
exponent: 1.5,
|
|
chat: {
|
|
cooldownMs: 60000,
|
|
minXp: 5,
|
|
maxXp: 15,
|
|
},
|
|
}),
|
|
|
|
getDefaultEconomy: (): EconomyConfig => ({
|
|
daily: {
|
|
amount: "100",
|
|
streakBonus: "10",
|
|
weeklyBonus: "50",
|
|
cooldownMs: 86400000,
|
|
},
|
|
transfers: {
|
|
allowSelfTransfer: false,
|
|
minAmount: "1",
|
|
},
|
|
exam: {
|
|
multMin: 1.0,
|
|
multMax: 2.0,
|
|
},
|
|
}),
|
|
|
|
getDefaultInventory: (): InventoryConfig => ({
|
|
maxStackSize: "99",
|
|
maxSlots: 20,
|
|
}),
|
|
|
|
getDefaultLootdrop: (): LootdropConfig => ({
|
|
activityWindowMs: 300000,
|
|
minMessages: 5,
|
|
spawnChance: 0.1,
|
|
cooldownMs: 60000,
|
|
reward: {
|
|
min: 10,
|
|
max: 50,
|
|
currency: "AU",
|
|
},
|
|
}),
|
|
|
|
getDefaultTrivia: (): TriviaConfig => ({
|
|
entryFee: "50",
|
|
rewardMultiplier: 1.8,
|
|
timeoutSeconds: 30,
|
|
cooldownMs: 60000,
|
|
categories: [],
|
|
difficulty: "random",
|
|
}),
|
|
|
|
getDefaultModeration: (): ModerationConfig => ({
|
|
prune: {
|
|
maxAmount: 100,
|
|
confirmThreshold: 50,
|
|
batchSize: 100,
|
|
batchDelayMs: 1000,
|
|
},
|
|
}),
|
|
|
|
getDefaults: (): GameSettingsData => ({
|
|
leveling: gameSettingsService.getDefaultLeveling(),
|
|
economy: gameSettingsService.getDefaultEconomy(),
|
|
inventory: gameSettingsService.getDefaultInventory(),
|
|
lootdrop: gameSettingsService.getDefaultLootdrop(),
|
|
trivia: gameSettingsService.getDefaultTrivia(),
|
|
moderation: gameSettingsService.getDefaultModeration(),
|
|
commands: {},
|
|
system: {},
|
|
}),
|
|
};
|