init commit
This commit is contained in:
commit
03d75f84dc
133
index.ts
Normal file
133
index.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
plugin.json
Normal file
15
plugin.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "WorldStateSync",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "WorldStateSync plugin for Warframe Emulator",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "Your Name",
|
||||||
|
"license": "GNU",
|
||||||
|
"config": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"tags": [
|
||||||
|
"custom"
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user