aboutsummaryrefslogtreecommitdiff
path: root/featureManager.js
diff options
context:
space:
mode:
Diffstat (limited to 'featureManager.js')
-rw-r--r--featureManager.js384
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