refacto: Changing actions reset windows + display
This commit is contained in:
@@ -8,9 +8,12 @@ const CONFIG_FILE_PATH =
|
||||
process.env.CONFIG_FILE_PATH ?? path.join(__dirname, "..", "config", "game.settings.json");
|
||||
|
||||
/** @type {{ dailyActionQuota: number, teamActionQuota: number, databaseWipeoutIntervalSeconds: number, configReloadIntervalSeconds: number, resourceWorth: object, militaryPower: object }} */
|
||||
const VALID_RESET_HOURS = new Set([1, 2, 3, 4, 6, 8, 12, 24]);
|
||||
|
||||
let cached = {
|
||||
dailyActionQuota: 100,
|
||||
teamActionQuota: 100,
|
||||
actionsResetIntervalHours: 12,
|
||||
databaseWipeoutIntervalSeconds: 21600,
|
||||
configReloadIntervalSeconds: 30,
|
||||
elementWorth: {},
|
||||
@@ -44,6 +47,10 @@ export function loadConfigFile() {
|
||||
if (typeof j.teamActionQuota === "number" && j.teamActionQuota >= 1) {
|
||||
cached.teamActionQuota = Math.floor(j.teamActionQuota);
|
||||
}
|
||||
if (typeof j.actionsResetIntervalHours === "number") {
|
||||
const v = Math.floor(j.actionsResetIntervalHours);
|
||||
if (VALID_RESET_HOURS.has(v)) cached.actionsResetIntervalHours = v;
|
||||
}
|
||||
if (typeof j.databaseWipeoutIntervalSeconds === "number" && j.databaseWipeoutIntervalSeconds >= 60) {
|
||||
cached.databaseWipeoutIntervalSeconds = j.databaseWipeoutIntervalSeconds;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { pool } from "./pools.js";
|
||||
import { loadConfigFile, getConfig } from "../configLoader.js";
|
||||
import { computeWorldSeedState } from "../worldSeed.js";
|
||||
import { nextNoonUtc, resetAllUserActions, getUsersByIds } from "./usersDb.js";
|
||||
import { nextResetUtc, resetAllUserActions, getUsersByIds } from "./usersDb.js";
|
||||
|
||||
let lastSeedSlot = null;
|
||||
|
||||
@@ -187,7 +187,7 @@ export async function ensureSeedEpoch() {
|
||||
await pool.query("DELETE FROM team_cell_visibility WHERE world_seed != $1", [worldSeed]);
|
||||
// Reset both team and user quotas to server defaults (no bonuses) for the new period
|
||||
const cfg = getConfig();
|
||||
const nextNoon = nextNoonUtc().toISOString();
|
||||
const nextNoon = nextResetUtc(cfg.actionsResetIntervalHours ?? 12).toISOString();
|
||||
await pool.query(
|
||||
`INSERT INTO team_action_quota (team, actions_remaining, quota_reset_at)
|
||||
VALUES ('blue', $1, $2), ('red', $1, $2)
|
||||
|
||||
+20
-4
@@ -29,12 +29,28 @@ export async function initUserActionQuotaSchema() {
|
||||
|
||||
/** Returns the next noon (12:00:00) UTC after the current moment. */
|
||||
export function nextNoonUtc() {
|
||||
return nextResetUtc(12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next reset timestamp UTC based on a repeating interval.
|
||||
* @param {number} intervalHours - must be a divisor of 24 (1,2,3,4,6,8,12,24)
|
||||
*/
|
||||
export function nextResetUtc(intervalHours) {
|
||||
const now = new Date();
|
||||
const noon = new Date(Date.UTC(
|
||||
now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 12, 0, 0, 0
|
||||
const utcHours = now.getUTCHours();
|
||||
const slotsPassed = Math.floor(utcHours / intervalHours);
|
||||
const nextSlotHour = (slotsPassed + 1) * intervalHours;
|
||||
if (nextSlotHour < 24) {
|
||||
return new Date(Date.UTC(
|
||||
now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),
|
||||
nextSlotHour, 0, 0, 0
|
||||
));
|
||||
}
|
||||
return new Date(Date.UTC(
|
||||
now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1,
|
||||
0, 0, 0, 0
|
||||
));
|
||||
if (noon <= now) noon.setUTCDate(noon.getUTCDate() + 1);
|
||||
return noon;
|
||||
}
|
||||
|
||||
// ── Queries ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -14,6 +14,7 @@ function makeConfigSignature(cfg) {
|
||||
return JSON.stringify({
|
||||
dailyActionQuota: cfg.dailyActionQuota,
|
||||
teamActionQuota: cfg.teamActionQuota,
|
||||
actionsResetIntervalHours: cfg.actionsResetIntervalHours,
|
||||
databaseWipeoutIntervalSeconds: cfg.databaseWipeoutIntervalSeconds,
|
||||
configReloadIntervalSeconds: cfg.configReloadIntervalSeconds,
|
||||
elementWorth: cfg.elementWorth ?? {},
|
||||
@@ -41,6 +42,7 @@ function scheduleConfigPoll() {
|
||||
config: {
|
||||
dailyActionQuota: cfg.dailyActionQuota,
|
||||
teamActionQuota: cfg.teamActionQuota,
|
||||
actionsResetIntervalHours: cfg.actionsResetIntervalHours,
|
||||
databaseWipeoutIntervalSeconds: cfg.databaseWipeoutIntervalSeconds,
|
||||
configReloadIntervalSeconds: cfg.configReloadIntervalSeconds,
|
||||
elementWorth: cfg.elementWorth ?? {},
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
getTeamVisibleCells,
|
||||
} from "../db/gameDb.js";
|
||||
import {
|
||||
nextNoonUtc,
|
||||
nextResetUtc,
|
||||
getUserActionsRow,
|
||||
resetUserActions,
|
||||
decrementUserActions,
|
||||
@@ -100,6 +100,7 @@ router.get("/config", async (req, res) => {
|
||||
seedPeriodStartsAtUtc: ws.seedPeriodStartsAtUtc,
|
||||
actionsRemaining,
|
||||
teamActionsRemaining,
|
||||
actionsResetIntervalHours: cfg.actionsResetIntervalHours ?? 12,
|
||||
resourceWorth: cfg.resourceWorth ?? { common: {}, rare: {} },
|
||||
elementWorth: cfg.elementWorth ?? {},
|
||||
militaryPower: cfg.militaryPower ?? {},
|
||||
@@ -170,7 +171,7 @@ router.post("/cell/reveal", authMiddleware, async (req, res) => {
|
||||
const now = new Date();
|
||||
const quotaRow = await getUserActionsRow(userId);
|
||||
if (!quotaRow || new Date(quotaRow.quota_reset_at) <= now) {
|
||||
await resetUserActions(userId, effectiveQuota - 1, nextNoonUtc().toISOString());
|
||||
await resetUserActions(userId, effectiveQuota - 1, nextResetUtc(cfg.actionsResetIntervalHours ?? 12).toISOString());
|
||||
} else {
|
||||
const updated = await decrementUserActions(userId);
|
||||
if (!updated) {
|
||||
@@ -247,7 +248,7 @@ router.post("/cell/capture", authMiddleware, async (req, res) => {
|
||||
if (totalActions < cost) {
|
||||
return res.status(429).json({ error: "team_quota_exhausted", cost, teamActionsRemaining: totalActions });
|
||||
}
|
||||
await resetTeamActions(team, totalActions - cost, nextNoonUtc().toISOString());
|
||||
await resetTeamActions(team, totalActions - cost, nextResetUtc(cfg.actionsResetIntervalHours ?? 12).toISOString());
|
||||
} else {
|
||||
if (teamRow.actions_remaining < cost) {
|
||||
return res.status(429).json({ error: "team_quota_exhausted", cost, teamActionsRemaining: teamRow.actions_remaining });
|
||||
|
||||
Reference in New Issue
Block a user