diff options
Diffstat (limited to 'featureManager.js')
-rw-r--r-- | featureManager.js | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/featureManager.js b/featureManager.js new file mode 100644 index 0000000..92b9cd8 --- /dev/null +++ b/featureManager.js @@ -0,0 +1,384 @@ +/// <reference types="../../CTAutocomplete" /> +/// <reference lib="es2015" /> +import LocationSetting from "../features/settings/settingThings/location"; +import logger from "../logger"; +const File = Java.type("java.io.File") +import metadata from "../metadata.js" +import { registerForge as registerForgeBase, unregisterForge as unregisterForgeBase} from "./forgeEvents.js" + +class FeatureManager { + constructor(){ + + this.enabled = true //make triggers work with this context + + this.features = {}; + this.events = {} + this.eventObjects = {} + this.soopyEventHandlers = {} + + this.parent = undefined + + this.commandFuncs = {} + + this.lastEventId = 0 + + this.customEvents = {} + this.lastChatEventId = 0 + + this.forgeEvents = {} + this.lastForgeEventId = 0 + + this.lastSoopyEventId = 0 + + this.featureSettingsDataLastUpdated = false + + this.featureMetas = {} + + this.featureSettingsData = {} + + new Thread(()=>{ + this.loadFeatureMetas() + + this.loadFeatureSettings() + + Object.keys(this.featureMetas).forEach((feature)=>{ + if(this.featureSettingsData[feature] && this.featureSettingsData[feature].enabled){ + this.loadFeature(feature) + } + }) + }).start() + + this.registerStep(false, 30, ()=>{ + if(this.featureSettingsDataLastUpdated){ + new Thread(()=>{ + this.saveFeatureSettings() + }).start() + } + }, this) + + this.registerEvent("worldUnload", this.saveFeatureSettings, this) + this.registerEvent("gameUnload", this.saveFeatureSettings, this) + + this.registerCommand("soopyunloadfeature", (args)=>{ + new Thread(()=>{ + this.unloadFeature(args) + }).start() + }, this) + this.registerCommand("soopyloadfeature", (args)=>{ + new Thread(()=>{ + this.loadFeature(args) + }).start() + }, this) + this.registerCommand("soopyreloadfeature", (args)=>{ + new Thread(()=>{ + this.unloadFeature(args) + + this.loadFeature(args) + }).start() + }, this) + } + + loadFeatureSettings(){ + logger.logMessage("Loading settings", 4) + + let data = FileLib.read("soopyAddonsData", "soopyaddonsbetafeaturesdata.json") + + if(!data){ + this.loadDefaultFeatureSettings(); + return; + } + + data = JSON.parse(data) + + this.featureSettingsData = data + + this.ensureNewSettingsExist() + } + + saveFeatureSettings(){ + if(!this.featureSettingsDataLastUpdated) return + + FileLib.write("soopyAddonsData", "soopyaddonsbetafeaturesdata.json", JSON.stringify(this.featureSettingsData)) + + this.featureSettingsDataLastUpdated = false + + logger.logMessage("Saved settings", 4) + } + + loadDefaultFeatureSettings(){ + Object.keys(this.featureMetas).forEach((feature)=>{ + this.featureSettingsData[feature] = { + enabled: this.featureMetas[feature].defaultEnabled, + subSettings: {} + } + }) + + this.featureSettingsDataLastUpdated= true + + logger.logMessage("Loaded default settings", 4) + } + + ensureNewSettingsExist(){ + Object.keys(this.featureMetas).forEach((feature)=>{ + if(!this.featureSettingsData[feature]){ + this.featureSettingsData[feature] = { + enabled: this.featureMetas[feature].defaultEnabled, + subSettings: {} + } + this.featureSettingsDataLastUpdated= true + logger.logMessage("Loaded default settings for " + feature, 4) + } + }) + } + + startCatchingEvent(event){ + if(this.eventObjects[event]) return + + //SBA compatability or something (removed) + // if(event === "renderOverlay"){ + // let lastPartialTick = undefined + // this.eventObjects[event] = register(event, (...args)=>{ + // let pTicks = Tessellator.getPartialTicks() + // if(pTicks !== lastPartialTick){ + // lastPartialTick = pTicks + // this.triggerEvent(event, args) + // } + // }) + // }else{ + this.eventObjects[event] = register(event, (...args)=>{ + this.triggerEvent(event, args) + }) + //} + + logger.logMessage("Registered " + event + " event", 4) + } + + triggerEvent(event, args){ + if(this.events[event]) + try{ + for(Event of Object.values(this.events[event])){ + if(Event.context.enabled) Event.func.call(Event.context, ...args) + } + }catch(e){ + logger.logMessage("Error in " + event + " event: " + JSON.stringify(e, undefined, 2), 2) + } + } + triggerSoopy(event, args){ + if(this.soopyEventHandlers[event]) + try{ + for(Event of Object.values(this.soopyEventHandlers[event])){ + if(Event.context.enabled) Event.func.call(Event.context, ...args) + } + }catch(e){ + logger.logMessage("Error in soopy " + event + " event: " + JSON.stringify(e, undefined, 2), 2) + } + } + + stopCatchingEvent(event){ + if(!this.eventObjects[event]) return + + this.eventObjects[event].unregister() + delete this.eventObjects[event] + delete this.events[event] + logger.logMessage("Unregistered " + event + " event", 4) + } + + registerEvent(event, func, context){ + if(!this.events[event]){ + this.events[event] = [] + this.startCatchingEvent(event) + } + + let theEvent = { + func: func, + context: context, + id: this.lastEventId++, + event: event + } + this.events[event].push(theEvent) + + return theEvent + } + registerSoopy(event, func, context){ + if(!this.soopyEventHandlers[event]){ + this.soopyEventHandlers[event] = [] + } + + let theEvent = { + func: func, + context: context, + id: this.lastSoopyEventId++, + event: event + } + this.soopyEventHandlers[event].push(theEvent) + + return theEvent + } + + registerChat(criteria, func, context){ + + let event = this.registerCustom("chat", func, context) + + event.trigger.setChatCriteria(criteria) + + return event + } + registerCommand(commandName, func, context){ + + let event = this.registerCustom("command", func, context) + + event.trigger.setName(commandName) + + return event + } + registerStep(isFps, interval, func, context){ + + let event = this.registerCustom("step", func, context) + + event.trigger[isFps?"setFps":"setDelay"](interval) //TODO: make this group events similar to registerEvent() + + return event + } + + registerCustom(type, func, context){ + + let id = this.lastChatEventId++ + + this.customEvents[id] = { + func: func, + context: context, + trigger: register(type, (...args)=>{ + try{ + if(context.enabled) func.call(context, ...(args || [])) + }catch(e){ + logger.logMessage("Error in " + type + " event: " + JSON.stringify(e, undefined, 2), 2) + } + }), + id: id + } + + return this.customEvents[id] + } + + registerForge(event, func, context){ + let id = this.lastForgeEventId++ + + this.forgeEvents[id] = { + func: func, + context: context, + trigger: registerForgeBase(event, (...args)=>{ + try{ + if(context.enabled) func.call(context, ...args) + }catch(e){ + logger.logMessage("Error in " + event.class.toString() + " (forge) event: " + JSON.stringify(e, undefined, 2), 2) + } + }), + id: id + } + + return this.forgeEvents[id] + } + + unregisterForge(event){ + unregisterForgeBase(this.forgeEvents[event.id].trigger) + delete this.forgeEvents[event.id] + } + + unregisterCustom(event){ + event.trigger.unregister() + + delete this.customEvents[event.id] + } + + unregisterEvent(event){ + if(!this.events[event.event]) return + + this.events[event.event] = this.events[event.event].filter((e)=>{ + return e.id !== event.id + }) + + if(this.events[event.event].length === 0){ + this.stopCatchingEvent(event.event) + delete this.events[event.event] + } + } + + unregisterSoopy(event){ + if(!this.soopyEventHandlers[event.event]) return + + this.soopyEventHandlers[event.event] = this.soopyEventHandlers[event.event].filter((e)=>{ + return e.id !== event.id + }) + + if(this.soopyEventHandlers[event.event].length === 0){ + delete this.events[event.event] + } + } + + loadFeatureMetas(){ + featuresDir = new File("./config/ChatTriggers/modules/" + metadata.name + "/features") + + featuresDir.list().forEach((pathName)=>{ + if(pathName.includes(".")) return; + + try{ + let data = JSON.parse(FileLib.read( metadata.name + "/features/" + pathName,"metadata.json")) + if(data === null){ + return; + } + data.id = pathName + this.featureMetas[pathName] = data + }catch(_){} + }) + } + + loadFeature(feature){ //run in seperate thread so onenable can do network requests + if(this.features[feature]) return + + let LoadedFeature = require("../features/" + feature + "/index.js") + + this.features[feature] = LoadedFeature + + LoadedFeature.class.setId(feature) + + LoadedFeature.class._onEnable(this) + + logger.logMessage("Loaded feature " + feature, 3) + + return this + } + + unloadFeature(feature){ //run in seperate thread so ondisable can do network requests + if(!this.features[feature]) return + + this.features[feature].class._onDisable() + + delete this.features[feature] + + logger.logMessage("Unloaded feature " + feature, 3) + + return this + } + + isFeatureLoaded(feature){ + return !!this.features[feature] + } + + getLoadedFeatures(){ + return Object.keys(this.features) + } + + createCustomEvent(eventId){ + logger.logMessage("Registered custom " + eventId + " event", 4) + + return { + trigger: (...args)=>{ + this.triggerSoopy(eventId, args) + } + } + } +} + +const featureManager = new FeatureManager(); + +export default featureManager;
\ No newline at end of file |