fix: Fixing the MP power bonus + seed maintenance
This commit is contained in:
+63
-16
@@ -7,21 +7,49 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
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]);
|
||||
const EPOCH_FILE_PATH =
|
||||
process.env.EPOCH_FILE_PATH ?? path.join(path.dirname(CONFIG_FILE_PATH), ".timing_epoch");
|
||||
|
||||
let cached = {
|
||||
dailyActionQuota: 100,
|
||||
teamActionQuota: 100,
|
||||
actionsResetIntervalHours: 12,
|
||||
databaseWipeoutIntervalSeconds: 21600,
|
||||
actionsResetIntervalSeconds: 3600,
|
||||
databaseWipeoutIntervalCycles: 6,
|
||||
configReloadIntervalSeconds: 30,
|
||||
elementWorth: {},
|
||||
resourceWorth: { common: {}, rare: {} },
|
||||
militaryPower: {},
|
||||
};
|
||||
|
||||
let lastMtimeMs = 0;
|
||||
/** Raw JSON content from the last successful read (for change detection). */
|
||||
let lastRawContent = "";
|
||||
|
||||
/** Unix seconds marking the origin of all timing slot calculations. */
|
||||
let timingEpochSec = 0;
|
||||
|
||||
/** Signature of timing-relevant values from the last successful load. */
|
||||
let lastTimingSig = "";
|
||||
|
||||
function timingSignature() {
|
||||
return `${cached.actionsResetIntervalSeconds}:${cached.databaseWipeoutIntervalCycles}`;
|
||||
}
|
||||
|
||||
function loadTimingEpoch() {
|
||||
try {
|
||||
const raw = fs.readFileSync(EPOCH_FILE_PATH, "utf8").trim();
|
||||
const v = Number(raw);
|
||||
if (Number.isFinite(v) && v > 0) return v;
|
||||
} catch { /* ignore */ }
|
||||
return 0;
|
||||
}
|
||||
|
||||
function saveTimingEpoch(sec) {
|
||||
try {
|
||||
fs.writeFileSync(EPOCH_FILE_PATH, String(sec), "utf8");
|
||||
} catch (e) {
|
||||
console.error("[config] Could not persist timing epoch:", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function parseBool(v) {
|
||||
if (typeof v === "boolean") return v;
|
||||
@@ -35,11 +63,13 @@ function parseBool(v) {
|
||||
|
||||
export function loadConfigFile() {
|
||||
try {
|
||||
const st = fs.statSync(CONFIG_FILE_PATH);
|
||||
if (st.mtimeMs === lastMtimeMs) {
|
||||
// Always read the file — mtime is unreliable on Docker bind mounts (Windows).
|
||||
// The file is tiny and polled every ~30 s, so the cost is negligible.
|
||||
const raw = fs.readFileSync(CONFIG_FILE_PATH, "utf8");
|
||||
if (raw === lastRawContent) {
|
||||
return cached;
|
||||
}
|
||||
const raw = fs.readFileSync(CONFIG_FILE_PATH, "utf8");
|
||||
lastRawContent = raw;
|
||||
const j = JSON.parse(raw);
|
||||
if (typeof j.dailyActionQuota === "number" && j.dailyActionQuota >= 1) {
|
||||
cached.dailyActionQuota = Math.floor(j.dailyActionQuota);
|
||||
@@ -47,12 +77,11 @@ 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.actionsResetIntervalSeconds === "number" && j.actionsResetIntervalSeconds >= 1) {
|
||||
cached.actionsResetIntervalSeconds = Math.floor(j.actionsResetIntervalSeconds);
|
||||
}
|
||||
if (typeof j.databaseWipeoutIntervalSeconds === "number" && j.databaseWipeoutIntervalSeconds >= 60) {
|
||||
cached.databaseWipeoutIntervalSeconds = j.databaseWipeoutIntervalSeconds;
|
||||
if (typeof j.databaseWipeoutIntervalCycles === "number" && j.databaseWipeoutIntervalCycles >= 1) {
|
||||
cached.databaseWipeoutIntervalCycles = Math.floor(j.databaseWipeoutIntervalCycles);
|
||||
}
|
||||
if (typeof j.configReloadIntervalSeconds === "number" && j.configReloadIntervalSeconds >= 5) {
|
||||
cached.configReloadIntervalSeconds = j.configReloadIntervalSeconds;
|
||||
@@ -64,10 +93,25 @@ export function loadConfigFile() {
|
||||
cached.resourceWorth = j.resourceWorth;
|
||||
} if (j.militaryPower && typeof j.militaryPower === 'object') {
|
||||
cached.militaryPower = j.militaryPower;
|
||||
} lastMtimeMs = st.mtimeMs;
|
||||
}
|
||||
// Detect timing changes and reset the epoch when they happen
|
||||
const newSig = timingSignature();
|
||||
if (!timingEpochSec) {
|
||||
// First load: try to restore from disk
|
||||
timingEpochSec = loadTimingEpoch();
|
||||
}
|
||||
if (!timingEpochSec || (lastTimingSig && newSig !== lastTimingSig)) {
|
||||
// No persisted epoch, or timing values changed → new epoch
|
||||
timingEpochSec = Math.floor(Date.now() / 1000);
|
||||
saveTimingEpoch(timingEpochSec);
|
||||
if (lastTimingSig) {
|
||||
console.log(`[config] Timing values changed (${lastTimingSig} → ${newSig}), epoch reset to ${timingEpochSec}`);
|
||||
}
|
||||
}
|
||||
lastTimingSig = newSig;
|
||||
} catch (e) {
|
||||
if (e.code === "ENOENT") {
|
||||
lastMtimeMs = 0;
|
||||
lastRawContent = "";
|
||||
} else {
|
||||
console.error("[config]", e.message);
|
||||
}
|
||||
@@ -76,7 +120,10 @@ export function loadConfigFile() {
|
||||
}
|
||||
|
||||
export function getConfig() {
|
||||
return { ...cached };
|
||||
const c = { ...cached };
|
||||
c.databaseWipeoutIntervalSeconds = c.actionsResetIntervalSeconds * c.databaseWipeoutIntervalCycles;
|
||||
c.timingEpochSec = timingEpochSec;
|
||||
return c;
|
||||
}
|
||||
|
||||
export function getConfigFilePath() {
|
||||
|
||||
Reference in New Issue
Block a user