134 lines
4.4 KiB
TypeScript
134 lines
4.4 KiB
TypeScript
import { IPlugin } from "@/src/types/pluginTypes";
|
|
import { logger } from "@/src/utils/logger";
|
|
|
|
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
|
|
import { config } from "@/src/services/configService";
|
|
|
|
/* Add this to your config.json worldState section to enable world state sync:
|
|
"sync":{
|
|
"enabled": true,
|
|
"url": "https://content.warframe.com/dynamic/worldState.php",
|
|
"fields": { // adjust these fields to your needs
|
|
"Events": "merge",
|
|
"InGameMarket": "replace",
|
|
"SyndicateMissions": "replace",
|
|
"ActiveMissions": "replace",
|
|
"VoidTraders": "replace",
|
|
"PrimeVaultTraders": "replace",
|
|
"DailyDeals": "replace",
|
|
"Goals": "replace"
|
|
},
|
|
"interval": 3000
|
|
}
|
|
*/
|
|
|
|
type AnyObj = { [key: string]: object | Array<object> | string | number | boolean };
|
|
const staticWorldStateBackup: AnyObj = structuredClone(staticWorldState);
|
|
let syncWorldStateTimer: NodeJS.Timeout | null = null;
|
|
|
|
interface myConfig {
|
|
worldState?: {
|
|
sync?: {
|
|
enabled: boolean;
|
|
url: string;
|
|
fields: { [key: string]: string };
|
|
interval?: number;
|
|
};
|
|
};
|
|
}
|
|
|
|
export const syncWorldState = async (): Promise<void> => {
|
|
if (syncWorldStateTimer) {
|
|
clearTimeout(syncWorldStateTimer);
|
|
syncWorldStateTimer = null;
|
|
}
|
|
const config_ = config as myConfig;
|
|
if (!config_.worldState?.sync) {
|
|
logger.info("World state sync is disabled, skipping");
|
|
return;
|
|
}
|
|
const { enabled, url, fields, interval } = config_.worldState.sync;
|
|
if (!enabled || !url || !fields) {
|
|
logger.info("World state sync is not enabled or misconfigured, skipping");
|
|
return;
|
|
}
|
|
const res = await fetch(url, { method: "GET" });
|
|
if (!res.ok) {
|
|
logger.error("Failed to fetch remote world state, will retry in 5 min", {
|
|
status: res.status,
|
|
statusText: res.statusText
|
|
});
|
|
syncWorldStateTimer = setTimeout(
|
|
() => {
|
|
void syncWorldState();
|
|
},
|
|
5 * 60 * 1000
|
|
);
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
if (!data || typeof data !== "object") {
|
|
logger.error("Invalid world state sync response", { data });
|
|
return;
|
|
}
|
|
const staticWorldState_ = staticWorldState as AnyObj;
|
|
const data_ = data as AnyObj;
|
|
|
|
for (const [name, action_] of Object.entries(fields)) {
|
|
if (!(name in data)) {
|
|
logger.warn(`Field ${name} not found in world state sync response`, { data });
|
|
continue;
|
|
}
|
|
const action = action_ as string;
|
|
if (action === "replace") {
|
|
staticWorldState_[name] = data_[name];
|
|
continue;
|
|
}
|
|
if (action === "merge") {
|
|
switch (name) {
|
|
case "Events":
|
|
{
|
|
const remoteValue = data_[name] as Array<object>;
|
|
const localValue = staticWorldStateBackup[name] as Array<object>;
|
|
if (Array.isArray(remoteValue) && Array.isArray(localValue)) {
|
|
staticWorldState_[name] = localValue.concat(remoteValue);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
logger.warn(`Not supported merge action for field ${name} in world state sync`);
|
|
}
|
|
continue;
|
|
}
|
|
logger.warn(`Unknown action ${action} for field ${name} in world state sync`);
|
|
continue;
|
|
}
|
|
if (interval && interval > 0) {
|
|
logger.info(`Next world state sync in ${interval} seconds`);
|
|
syncWorldStateTimer = setTimeout(() => {
|
|
void syncWorldState();
|
|
}, interval * 1000);
|
|
} else {
|
|
logger.info("No next world state sync scheduled");
|
|
}
|
|
};
|
|
|
|
export default class WorldStateSync implements IPlugin {
|
|
public name = "WorldStateSync";
|
|
public version = "1.0.0";
|
|
public description = "WorldStateSync plugin for Warframe Emulator";
|
|
|
|
async initialize(): Promise<void> {
|
|
logger.info(`[${this.name}] Plugin initialized successfully!`);
|
|
await syncWorldState();
|
|
}
|
|
|
|
async cleanup(): Promise<void> {
|
|
logger.info(`[${this.name}] Plugin cleanup completed`);
|
|
if (syncWorldStateTimer) {
|
|
clearTimeout(syncWorldStateTimer);
|
|
syncWorldStateTimer = null;
|
|
}
|
|
}
|
|
}
|