diff options
Diffstat (limited to 'featureClass')
-rw-r--r-- | featureClass/class.js | 293 | ||||
-rw-r--r-- | featureClass/featureManager.js | 877 | ||||
-rw-r--r-- | featureClass/forgeEvents.js | 99 |
3 files changed, 0 insertions, 1269 deletions
diff --git a/featureClass/class.js b/featureClass/class.js deleted file mode 100644 index f2d5549..0000000 --- a/featureClass/class.js +++ /dev/null @@ -1,293 +0,0 @@ -/// <reference types="../../CTAutocomplete" /> -/// <reference lib="es2015" /> -import { delay } from "../utils/delayUtils" - -class Feature { - constructor() { - this.FeatureManager = undefined - this.events = {} - this.customEvents = {} - this.forgeEvents = {} - this.soopyEvents = {} - this.dynamicEvents = new Set() - - this.id = undefined - - this.enabled = false - } - - setId(id) { - this.id = id - } - getId() { - return this.id - } - - _onDisable() { - Object.values(this.events).forEach(e => this.FeatureManager.unregisterEvent(e)) //calling parent unregister to avoid the set in unregister event - Object.values(this.customEvents).forEach(e => this.FeatureManager.unregisterCustom(e)) //calling parent unregister to avoid the set in unregister event - Object.values(this.forgeEvents).forEach(e => this.FeatureManager.unregisterForge(e)) //calling parent unregister to avoid the set in unregister event - Object.values(this.soopyEvents).forEach(e => this.FeatureManager.unregisterSoopy(e)) //calling parent unregister to avoid the set in unregister event - - this.onDisable() - - this.events = {} - this.customEvents = {} - this.enabled = false - - this.dynamicEvents.clear() - - this.stepEvent.unregister() - } - - _onEnable(parent) { - this.FeatureManager = parent - - this.enabled = true - - this.stepEvent = this.registerStep(false, 5, () => { - this.dynamicEvents.forEach(e => e.update()) - }) - - this.onEnable() - } - - onDisable() { } - onEnable() { } - - registerEvent(event, func) { - let theEvent = this.FeatureManager.registerEvent(event, func, this) - - this.events[theEvent.id] = theEvent - - return new CtEvent(theEvent, undefined, [event, func], this) - } - - unregisterEvent(event) { - this.FeatureManager.unregisterEvent(event) - - delete this.events[event.id] - } - registerSoopy(event, func) { - let theEvent = this.FeatureManager.registerSoopy(event, func, this) - - this.soopyEvents[theEvent.id] = theEvent - - return new SoopyEvent(theEvent, undefined, [event, func], this) - } - - unregisterSoopy(event) { - this.FeatureManager.unregisterSoopy(event) - - delete this.soopyEvents[event.id] - } - - registerForge(event, func, priority) { - let theEvent - try { - theEvent = this.FeatureManager.registerForge(event, func, priority, this) - } catch (e) { - ChatLib.chat(this.FeatureManager.messagePrefix + "An error occured while registering the event " + event.class.toString().split(".").pop() + ", this may cause " + this.constructor.name + " to not work properly.") - } - if (theEvent) this.forgeEvents[theEvent.id] = theEvent - - return new ForgeEvent(theEvent, theEvent.trigger, [event, func, priority], this) - } - - unregisterForge(event) { - if (!event) return - - this.FeatureManager.unregisterForge(event) - - delete this.forgeEvents[event.id] - } - - registerChat(criteria, func) { - let theEvent = this.FeatureManager.registerChat(criteria, func, this) - - this.customEvents[theEvent.id] = theEvent - - return new CustomEvent(theEvent, theEvent.trigger, [criteria, func], this) - } - registerSoundPlay(criteria, func) { - let theEvent = this.FeatureManager.registerSoundPlay(criteria, func, this) - - this.customEvents[theEvent.id] = theEvent - - return new CustomEvent(theEvent, theEvent.trigger, [criteria, func], this) - } - registerActionBar(criteria, func) { - let theEvent = this.FeatureManager.registerActionBar(criteria, func, this) - - this.customEvents[theEvent.id] = theEvent - - return new CustomEvent(theEvent, theEvent.trigger, [criteria, func], this) - } - registerStep(isFps, interval, func) { - let theEvent = this.FeatureManager.registerStep(isFps, interval, func, this) - - this.customEvents[theEvent.id] = theEvent - - return new CustomEvent(theEvent, theEvent.trigger, [isFps, interval, func], this) - } - - registerCustom(event, func) { - let theEvent = this.FeatureManager.registerCustom(event, func, this) - - this.customEvents[theEvent.id] = theEvent - - return new CustomEvent(theEvent, theEvent.trigger, [event, func], this) - } - - registerCommand(name, func, completions) { - this.FeatureManager.commandFuncs[name] = func - - this.FeatureManager.registerCommand(name, (...args) => { - if (this.FeatureManager.commandFuncs[name]) { - this.FeatureManager.commandFuncs[name].call(this, ...(args || [])) - } else { - ChatLib.chat(this.FeatureManager.messagePrefix + "This command is not available atm") - } - }, this, completions) - - return new CommandEvent(name, undefined, [name, func], this) - } - unregisterCommand(name) { - delete this.FeatureManager.commandFuncs[name] - } - - unregisterCustom(event) { - this.FeatureManager.unregisterCustom(event) - - delete this.customEvents[event.id] - } - - createCustomEvent(eventId) { - return this.FeatureManager.createCustomEvent(eventId) - } -} - -export default Feature - -class Event { - constructor(data, trigger, registerArgs = [], parent) { - this.data = data - this.trigger = trigger - this.registerArgs = registerArgs - this.parent = parent - - this.enabled = true - - this.when = undefined - } - - update() { - let shouldBeEnabled = !!this.when() - if (this.enabled === shouldBeEnabled) return - - if (this.enabled) { - this.unregister() - } else { - this.register() - } - } - - /** - * Runs the function given as the argument every 5seconds - * And will make sure that the event is only registered when the condition is true - */ - registeredWhen(fun) { - this.when = fun - - if (!fun()) { - this.unregister() - } - - this.parent.dynamicEvents.add(this) - - return this - } - - register() { - if (this.enabled) return - - this.enabled = true - - delay(0, () => { - this.actuallyRegister() - }) - } - - unregister() { - if (!this.enabled) return - - this.enabled = false - delay(0, () => { - this.actuallyUnregister() - }) - } - - actuallyRegister() { } - - actuallyUnregister() { } -} - -class CtEvent extends Event { - actuallyRegister() { - let newEvent = this.parent.registerEvent(...this.registerArgs) - this.data = newEvent.data - this.trigger = newEvent.trigger - } - - actuallyUnregister() { - this.parent.unregisterEvent(this.data) - } -} -class SoopyEvent extends Event { - actuallyRegister() { - let newEvent = this.parent.registerSoopy(...this.registerArgs) - this.data = newEvent.data - this.trigger = newEvent.trigger - } - - actuallyUnregister() { - this.parent.unregisterSoopy(this.data) - } -} - -class CommandEvent extends Event { - actuallyRegister() { - let newEvent = this.parent.registerCommand(...this.registerArgs) - this.data = newEvent.data - this.trigger = newEvent.trigger - } - - actuallyUnregister() { - this.parent.unregisterCommand(this.data) - } -} - -class ForgeEvent extends Event { - actuallyRegister() { - let newEvent = this.parent.registerForge(...this.registerArgs) - this.data = newEvent.data - this.trigger = newEvent.trigger - } - - actuallyUnregister() { - this.parent.unregisterForge(this.data) - } -} - -class CustomEvent extends Event { - constructor(...args) { - super(...args) - } - actuallyRegister() { - this.trigger.register() - } - - actuallyUnregister() { - this.trigger.unregister() - } -} diff --git a/featureClass/featureManager.js b/featureClass/featureManager.js deleted file mode 100644 index a4cb53f..0000000 --- a/featureClass/featureManager.js +++ /dev/null @@ -1,877 +0,0 @@ -/// <reference types="../../CTAutocomplete" /> -/// <reference lib="es2015" /> -const Instant = Java.type("java.time.Instant"); -import logger from "../logger"; -const File = Java.type("java.io.File") -import metadata from "../metadata.js" -import soopyV2Server from "../socketConnection"; -import { fetch } from "../utils/networkUtils"; -import NonPooledThread from "../utils/nonPooledThread"; -import { setRendering } from "../utils/renderJavaUtils"; -import { registerForge as registerForgeBase, unregisterForge as unregisterForgeBase } from "./forgeEvents.js" - -const JSLoader = Java.type("com.chattriggers.ctjs.engine.langs.js.JSLoader") -const UrlModuleSourceProvider = Java.type("org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider") -const UrlModuleSourceProviderInstance = new UrlModuleSourceProvider(null, null) -const StrongCachingModuleScriptProviderClass = Java.type("org.mozilla.javascript.commonjs.module.provider.StrongCachingModuleScriptProvider") -let StrongCachingModuleScriptProvider = new StrongCachingModuleScriptProviderClass(UrlModuleSourceProviderInstance) -let CTRequire = new JSLoader.CTRequire(StrongCachingModuleScriptProvider) - -const System = Java.type("java.lang.System") - -let loadedModules = new Set() -let shouldRequireForceNoCache = true - -function RequireNoCache(place) { - if (!shouldRequireForceNoCache) { - if (!logger.isDev) return require(place) - if (!loadedModules.has(place)) { - loadedModules.add(place) - return require(place) //performance optimisation - } - } - - StrongCachingModuleScriptProvider = new StrongCachingModuleScriptProviderClass(UrlModuleSourceProviderInstance) - CTRequire = new JSLoader.CTRequire(StrongCachingModuleScriptProvider) - return CTRequire(place) -} - -class FeatureManager { - constructor() { - - this.isDev = logger.isDev - - this.messagePrefix = "&6[SOOPY V2]&7 " - this.enabled = true //make triggers work with this context - - this.features = {}; - this.events = {} - this.eventObjects = {} - this.soopyEventHandlers = {} - - this.parent = undefined - - this.finishedLoading = false - - this.commandFuncs = {} - - this.lastEventId = 0 - - this.customEvents = {} - this.lastChatEventId = 0 - - this.forgeEvents = {} - this.lastForgeEventId = 0 - - this.lastSoopyEventId = 0 - - this.featureSettingsDataLastUpdated = false - - //PERFORMANCE RECORDING - this.recordingPerformanceUsage = false - this.performanceUsage = {} //{<moduleName>: {<event>: {time: 0, count: 0}}} - this.flameGraphData = [] - - this.longEventTime = 20 - - this.perfTrackingFeatures = false - this.stack = [] - - - this.featureMetas = {} - - this.featureSettingsData = {} - - let fetchD = fetch("http://soopy.dev/api/soopyv2/ping").async(d => { - if (fetchD.responseCode() >= 400 || fetchD.responseCode() === -1) { - ChatLib.chat(this.messagePrefix + "&cError: Could not connect to Soopy's server. This may cause issues with some features but will (hopefully) be back soon.") - } - - new NonPooledThread(() => { - this.loadSoopy() - }).start() - }, true) - - 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.unloadAllFeatures() - - this.enabled = false - }, this) - - if (this.isDev) { - this.registerStep(true, 2, () => { - if (this.reloadModuleTime !== 0 && Date.now() - this.reloadModuleTime > 0) { - new Thread(() => { - this.reloadModuleTime = 0 - this.reloadingModules.forEach(m => { - this.unloadFeature(m) - }) - this.reloadingModules.forEach(m => { - this.loadFeature(m) - }) - this.reloadingModules.clear() - }).start() - } - }, this) - - this.watches = {} - this.addedWatches = new Set() - this.watchService = Java.type("java.nio.file.FileSystems").getDefault().newWatchService(); - this.reloadingModules = new Set() - this.reloadModuleTime = 0 - new NonPooledThread(() => { - while (this.enabled) { - key = this.watchService.take(); - let moduleToReload = this.watches[key] - if (this.features[moduleToReload] && !this.reloadingModules.has(moduleToReload)) { //if enabled && not alr in queue - this.reloadingModules.add(moduleToReload) - this.reloadModuleTime = Date.now() + 5000 - } - key.pollEvents()/*.forEach(event=>{ - logger.logMessage(event.context().toString(), 1) - })*/ - key.reset(); - } - }).start() - } - - this.registerCommand("soopyunloadfeature", (args) => { - new Thread(() => { - this.unloadFeature(args) - }).start() - }, this) - this.registerCommand("soopyloadfeature", (args) => { - new Thread(() => { - this.loadFeature(args) - }).start() - }, this) - this.registerCommand("soopyunload", () => { - new Thread(() => { - this.unloadSoopy() - }).start() - }, this) - this.registerCommand("soopyload", () => { - new NonPooledThread(() => { - this.loadSoopy() - }).start() - }, this) - this.registerCommand("soopyreload", () => { - new NonPooledThread(() => { - this.unloadSoopy() - this.loadSoopy() - }).start() - }, this) - this.registerCommand("soopyreloadfeature", (args) => { - new Thread(() => { - this.unloadFeature(args) - - this.loadFeature(args) - }).start() - }, this) - this.registerCommand("soopysetlongeventtime", (args) => { - this.longEventTime = parseInt(args) - }, this) - this.registerCommand("soopylaginformation", (args) => { - this.loadPerformanceData() - }, this) - this.registerCommand("soopylaginformationfast", (args) => { - this.loadPerformanceDataFast() - }, this) - } - - getId() { - return "FeatureManager" - } - loadPerformanceDataFast() { - new Thread(() => { - this.loadEventLag(true) - }).start() - } - - loadPerformanceData() { - new NonPooledThread(() => { - ChatLib.chat(this.messagePrefix + "Recording performance impact, this will take around 60 seconds to complete!") - shouldRequireForceNoCache = true - let eventLagData = this.loadEventLag() - ChatLib.chat(this.messagePrefix + "ETA: 40s") - this.perfTrackingFeatures = true - this.unloadSoopy() - this.loadSoopy() - Thread.sleep(1000) - let eventLagDataFull = this.loadEventLag() - this.perfTrackingFeatures = false - this.unloadSoopy() - this.loadSoopy() - Thread.sleep(1000) - ChatLib.chat(this.messagePrefix + "ETA: 25s") - let forgeLagData = this.loadForgeRenderLag() - ChatLib.chat(this.messagePrefix + "ETA: 15s") - let soopyLagData = this.loadSoopyLag() - - let lagData = { - eventLagDataFull, - eventLagData, - forgeLagData, - soopyLagData - } - - shouldRequireForceNoCache = false - let url = this.reportLagData(lagData) - ChatLib.chat(this.messagePrefix + "Done!") - new TextComponent(this.messagePrefix + "See the report at " + url).setClick("open_url", url).setHover("show_text", "Click to open the report.").chat() - - - this.performanceUsage = {} - this.flameGraphData = [] - }).start() - } - - reportLagData(data) { - return fetch("http://soopy.dev/soopy/submitlag", { postData: data }).text() - } - - loadSoopyLag() { - // ChatLib.chat(this.messagePrefix + "Recording All Soopy Lag...") - let framesWith = 0 - let framesWithOut = 0 - let event = this.registerEvent("renderWorld", () => { - framesWith++ - }, this) - - Thread.sleep(5000) - this.unregisterEvent(event) - - this.unloadSoopy() - Thread.sleep(1000) - event = this.registerEvent("renderWorld", () => { - framesWithOut++ - }, this) - - Thread.sleep(5000) - this.unregisterEvent(event) - - // ChatLib.chat(this.messagePrefix + "Soopy Lag:") - // ChatLib.chat("&eFps without Soopy: &7" + (framesWithOut / 5)) - // ChatLib.chat("&eFps with Soopy: &7" + (framesWith / 5)) - - this.loadSoopy() - - return { - fpsWith: (framesWith / 5), - fpsWithout: (framesWithOut / 5) - } - } - - loadForgeRenderLag() { - // ChatLib.chat(this.messagePrefix + "Recording Forge-Rendering Lag...") - let framesWith = 0 - let framesWithOut = 0 - let renderingForge = true - let event = this.registerEvent("renderWorld", () => { - if (renderingForge) { - framesWith++ - } else { - framesWithOut++ - } - }, this) - - for (let i = 0; i < 10; i++) { - Thread.sleep(1000) - renderingForge = !renderingForge - setRendering(renderingForge) - } - this.unregisterEvent(event) - - // ChatLib.chat(this.messagePrefix + "Forge Lag:") - // ChatLib.chat("&eFps without forge: &7" + (framesWithOut / 5)) - // ChatLib.chat("&eFps with forge: &7" + (framesWith / 5)) - return { - fpsWith: (framesWith / 5), - fpsWithout: (framesWithOut / 5) - } - } - - loadEventLag(sendMessage = false) { - this.recordingPerformanceUsage = true - this.performanceUsage = {} - this.flameGraphData = [] - if (sendMessage) ChatLib.chat(this.messagePrefix + "Recording Event Lag...") - - Thread.sleep(10000) - - let totalMsGlobal = 0 - this.recordingPerformanceUsage = false - if (sendMessage) { - ChatLib.chat(this.messagePrefix + "Event Lag:") - Object.keys(this.performanceUsage).sort((a, b) => { - let totalMsA = 0 - Object.keys(this.performanceUsage[a]).forEach((event) => { - totalMsA += this.performanceUsage[a][event].time - }) - let totalMsB = 0 - Object.keys(this.performanceUsage[b]).forEach((event) => { - totalMsB += this.performanceUsage[b][event].time - }) - - return totalMsA - totalMsB - }).forEach((moduleName) => { - let totalMs = 0 - let totalCalls = 0 - Object.keys(this.performanceUsage[moduleName]).forEach((event) => { - totalMs += this.performanceUsage[moduleName][event].time - totalCalls += this.performanceUsage[moduleName][event].count - }) - - totalMsGlobal += totalMs - - ChatLib.chat("&eModule: &7" + moduleName) - ChatLib.chat("&eTotal: &7" + totalMs.toFixed(2) + "ms (" + totalCalls + " calls)") - Object.keys(this.performanceUsage[moduleName]).sort((a, b) => { return this.performanceUsage[moduleName][a].time - this.performanceUsage[moduleName][b].time }).forEach((event) => { - ChatLib.chat(" &eEvent:&7 " + event + " - " + this.performanceUsage[moduleName][event].time.toFixed(2) + "ms (" + this.performanceUsage[moduleName][event].count + " calls) [" + ((this.performanceUsage[moduleName][event].time / this.performanceUsage[moduleName][event].count).toFixed(2)) + "ms avg]") - }) - }) - - ChatLib.chat("&eTotal: &7" + totalMsGlobal.toFixed(2) + "ms") - } - return { performanceUsage: this.performanceUsage, flameGraphData: this.flameGraphData } - } - - loadFeatureSettings() { - logger.logMessage("Loading settings", 4) - - let data = FileLib.read("soopyAddonsData", "soopyaddonsbetafeaturesdata.json") - - if (!data) { - this.loadDefaultFeatureSettings(); - return; - } - - try { - data = JSON.parse(data) - } catch (e) { - ChatLib.chat(this.messagePrefix + "&cYour settings file corrupted and could not be read! Resetting to defaults.") - 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) => { - // let start = Date.now() - this.triggerEvent(event, args) - // this.eventTimingData[event] = (this.eventTimingData[event] || 0)+(Date.now()-start) - }) - //} - - 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) { - if (this.recordingPerformanceUsage) this.startRecordingPerformance(Event.context.getId(), event) - let start = Date.now() - Event.func.call(Event.context, ...args) - let time = Date.now() - start - if (time > this.longEventTime) { - logger.logMessage("Long event triggered [" + time + "ms] (" + Event.context.getId() + "/" + event + ")", 3) - } - if (this.recordingPerformanceUsage) this.stopRecordingPerformance(Event.context.getId(), event) - } - } - } catch (e) { - logger.logMessage("Error in " + event + " event: " + JSON.stringify(e, undefined, 2), 2) - logger.logMessage(e.stack, 1) - - soopyV2Server.reportError(e, "Error in " + event + " event.") - } - } - } - triggerSoopy(event, args) { - if (this.soopyEventHandlers[event]) { - try { - for (Event of Object.values(this.soopyEventHandlers[event])) { - if (Event.context.enabled) { - if (this.recordingPerformanceUsage) this.startRecordingPerformance(Event.context.getId(), event) - let start = Date.now() - Event.func.call(Event.context, ...args) - let time = Date.now() - start - if (time > this.longEventTime) { - logger.logMessage("Long event triggered [" + time + "ms] (" + Event.context.getId() + "/" + event + ")", 3) - } - if (this.recordingPerformanceUsage) this.stopRecordingPerformance(Event.context.getId(), event) - } - } - } catch (e) { - logger.logMessage("Error in soopy " + event + " event: " + JSON.stringify(e, undefined, 2), 2) - logger.logMessage(e.stack, 1) - soopyV2Server.reportError(e, "Error in soopy " + event + " event.") - } - } - } - - 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 - } - - registerSoundPlay(criteria, func, context) { - let event = this.registerCustom("soundPlay", func, context) - - event.trigger.setCriteria(criteria) - - return event - } - - registerActionBar(criteria, func, context) { - - let event = this.registerCustom("actionBar", func, context) - - event.trigger.setChatCriteria(criteria) - - return event - } - registerCommand(commandName, func, context, completions) { - - let event = this.registerCustom("command", func, context) - - event.trigger.setName(commandName, true) - - if (completions) event.trigger.setTabCompletions(completions).setName(commandName, true) - - return event - } - registerStep(isFps, interval, func, context) { - let event = this.registerCustom("step", func, context) - - event.trigger[isFps ? "setFps" : "setDelay"](interval) - - return event - } - - registerCustom(type, func, context) { - let id = this.lastChatEventId++ - - if (!func) throw new Error("Function must not be null") - - this.customEvents[id] = { - func: func, - context: context, - trigger: register(type, (...args) => { - try { - if (context.enabled) { - if (this.recordingPerformanceUsage) this.startRecordingPerformance(context.getId(), type) - let start = Date.now() - func.call(context, ...(args || [])) - let time = Date.now() - start - if (time > this.longEventTime) { - logger.logMessage("Long event triggered [" + time + "ms] (" + context.getId() + "/" + type + ")", 3) - } - if (this.recordingPerformanceUsage) this.stopRecordingPerformance(context.getId(), type) - } - } catch (e) { - logger.logMessage("Error in " + type + " event: " + JSON.stringify(e, undefined, 2), 2) - logger.logMessage(e.stack, 1) - - soopyV2Server.reportError(e, "Error in " + type + " event.") - } - }), - id: id - } - - return this.customEvents[id] - } - - registerForge(event, func, priority, context) { - let id = this.lastForgeEventId++ - - this.forgeEvents[id] = { - func: func, - context: context, - trigger: registerForgeBase(event, priority, (...args) => { - try { - if (context.enabled) { - if (this.recordingPerformanceUsage) this.startRecordingPerformance(context.getId(), event.class.name) - let start = Date.now() - func.call(context, ...(args || [])) - let time = Date.now() - start - if (time > this.longEventTime) { - logger.logMessage("Long (forge) event triggered (" + context.getId() + "/" + event.class.toString() + ")", 3) - } - if (this.recordingPerformanceUsage) this.stopRecordingPerformance(context.getId(), event.class.name) - } - } catch (e) { - logger.logMessage("Error in " + event.class.toString() + " (forge) event: " + JSON.stringify(e, undefined, 2), 2) - logger.logMessage(e.stack, 1) - - soopyV2Server.reportError(e, "Error in " + event.class.toString() + " (forge) event.") - } - }), - id: id - } - - return this.forgeEvents[id] - } - - unregisterForge(event) { - if (!this.forgeEvents[event.id]) return - 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() { - let 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 (e) { - logger.logMessage("Error loading feature metadata for " + pathName, 1) - logger.logMessage(JSON.stringify(e, undefined, 2), 1) - } - }) - } - - addPerformanceTracking(feature) { - let featureId = feature.getId() - if (!this.perfTrackingFeatures) return - - Object.getOwnPropertyNames(Object.getPrototypeOf(feature)).forEach(key => { - if (typeof (feature[key]) === "function") { - let fun = feature[key].bind(feature) - feature[key] = (...args) => { - if (!this.recordingPerformanceUsage || Thread.currentThread().getId() !== 1 || !this.perfTrackingFeatures) { - let err = undefined - try { - args ? fun(...args) : fun() - } catch (e) { - err = e - } - if (err) throw err - return - } - - let pushedId = false - let start = this.getExactTime() - - if (this.stack.length === 0) { - this.stack.push([featureId, 0]) - // this.flameGraphData.push({ isEnter: true, thing: featureId, time: start }) - pushedId = true - } - this.stack.push([featureId + "." + key, 0]) - - // this.flameGraphData.push({ isEnter: true, thing: featureId + "." + key, time: start }) - let err = undefined - try { - args ? fun(...args) : fun() - } catch (e) { - err = e - } - let nowTime = this.getExactTime() - let time = (nowTime - start) - this.stack[this.stack.length - 1][1] - - this.stack[this.stack.length - 2][1] += nowTime - start - - if (!this.performanceUsage[featureId]) this.performanceUsage[featureId] = {} - if (!this.performanceUsage[featureId].functions) this.performanceUsage[featureId].functions = {} - if (!this.performanceUsage[featureId].functions[key]) this.performanceUsage[featureId].functions[key] = { time: 0, count: 0 } - this.performanceUsage[featureId].functions[key].count++ - this.performanceUsage[featureId].functions[key].time += nowTime - start - - this.flameGraphData.push(this.stack.map(a => a[0]).join(";") + " " + (time)) - this.stack.pop()[1] - if (pushedId) { - let time = (nowTime - start) - this.stack[this.stack.length - 1][1] - this.flameGraphData.push(this.stack.map(a => a[0]).join(";") + " " + (time)) - this.stack.pop() - } - - if (err) throw err - } - } - }) - } - - unloadSoopy() { - this.saveFeatureSettings() - this.unloadAllFeatures() - } - - loadSoopy() { - ChatLib.chat(this.messagePrefix + "Loading SoopyV2...") - let startLoading = Date.now() - this.loadFeatureMetas() - - this.loadFeatureSettings() - - let loadedFeatures = new Map() - - Object.keys(this.featureMetas).forEach((feature) => { - if (this.featureSettingsData[feature] && this.featureSettingsData[feature].enabled) { - loadedFeatures.set(feature, false) - new Thread(() => { - this.loadFeature(feature) - loadedFeatures.set(feature, true) - }).start() - } - }) - - while ([...loadedFeatures.values()].some(a => !a)) { - Thread.sleep(100) - } - - this.finishedLoading = true - ChatLib.chat(this.messagePrefix + "SoopyV2 Loaded!") - logger.logMessage("SoopyV2 took " + ((Date.now() - startLoading) / 1000).toFixed(2) + "s to load", 3) - } - - loadFeature(feature) { //run in seperate thread so onenable can do network requests - if (this.features[feature]) return - - try { - - let LoadedFeature = RequireNoCache("../features/" + feature + "/index.js") - // let LoadedFeature = RequireNoCache(new File("config/ChatTriggers/modules/" + metadata.name + "/features/" + feature + "/index.js")) - - this.features[feature] = LoadedFeature - - LoadedFeature.class.setId(feature) - - this.addPerformanceTracking(LoadedFeature.class) - - LoadedFeature.class._onEnable(this) - - logger.logMessage("Loaded feature " + feature, 3) - - if (this.isDev && !this.addedWatches.has(feature)) { - this.addedWatches.add(feature) - let path = Java.type("java.nio.file.Paths").get("./config/ChatTriggers/modules/SoopyV2/features/" + feature + "/"); - this.watches[path.register(this.watchService, Java.type("java.nio.file.StandardWatchEventKinds").ENTRY_MODIFY)] = feature - } - } catch (e) { - logger.logMessage("Error loading feature " + feature, 1) - logger.logMessage(JSON.stringify(e, undefined, 2), 1) - logger.logMessage(e.stack, 1) - ChatLib.chat(this.messagePrefix + "Error loading feature " + feature) - - soopyV2Server.reportError(e, "Error loading feature " + feature) - } - - return this - } - - unloadFeature(feature) { - if (!this.features[feature]) return - - this.features[feature].class._onDisable() - - delete this.features[feature] - - logger.logMessage("Unloaded feature " + feature, 3) - - return this - } - - unloadAllFeatures() { - Object.keys(this.features).forEach((feature) => { - this.unloadFeature(feature) - }) - } - - 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) - } - } - } - - getExactTime() { - return System.nanoTime() / 1000000 - } - startRecordingPerformance(feature, event) { - if (!this.recordingPerformanceUsage) return - - if (!this.performanceUsage[feature]) this.performanceUsage[feature] = {} - if (!this.performanceUsage[feature][event]) this.performanceUsage[feature][event] = { time: 0, count: 0 } - - let time = this.getExactTime() - - this.performanceUsage[feature][event].startTime = time - } - stopRecordingPerformance(feature, event) { - if (!this.recordingPerformanceUsage) return - - let time = this.getExactTime() - - this.performanceUsage[feature][event].time += (time - this.performanceUsage[feature][event].startTime) - this.performanceUsage[feature][event].count++ - } -} - -if (!global.soopyv2featuremanagerthing) { - global.soopyv2featuremanagerthing = new FeatureManager() - register("gameUnload", () => { - global.soopyv2featuremanagerthing = undefined - }) -} -export default global.soopyv2featuremanagerthing diff --git a/featureClass/forgeEvents.js b/featureClass/forgeEvents.js deleted file mode 100644 index fb723b1..0000000 --- a/featureClass/forgeEvents.js +++ /dev/null @@ -1,99 +0,0 @@ -importClass(net.minecraftforge.common.MinecraftForge) //i would have used the ct module but it is broken (line 78) (this is fixed verison) -importPackage(net.minecraftforge.fml.common.eventhandler) -importPackage(org.objectweb.asm) -importClass(java.lang.ClassLoader) -importClass(org.apache.commons.lang3.RandomStringUtils) -importClass(java.util.function.Consumer) -importClass(net.minecraftforge.fml.common.eventhandler.EventPriority) - -const L = s => `L${s};` -const LoadedInsts = [] - -function defineClassBytes(name, bytes) {//should support multymc? ty dawjaw https://canary.discord.com/channels/119493402902528000/688773480954855537/979959207124168744 - const classLoader = Packages.com.chattriggers.ctjs.CTJS.class.getClassLoader() - - let defClass; - ClassLoader.class.getDeclaredMethods().forEach(m => { - if (m.toString() === "protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int) throws java.lang.ClassFormatError") { - defClass = m; - } - }) - - defClass.setAccessible(true) - - const n = new java.lang.String(name) - const o = new java.lang.Integer(0) - const s = new java.lang.Integer(bytes.length) - return defClass.invoke(classLoader, n, bytes, o, s) -} - -const registerForge = (e, priority = EventPriority.NORMAL, cb) => { - const cw = new ClassWriter(0) - - const event = Type.getType(e.class).internalName - const name = RandomStringUtils.randomAlphabetic(7) - - const consumer = Type.getType(Consumer.class).internalName - const mcForge = Type.getType(MinecraftForge.class).internalName - const eventBus = Type.getType(EventBus.class).internalName - const subscribeEvent = Type.getType(SubscribeEvent.class).internalName - const obj = Type.getType(java.lang.Object.class).internalName - - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, obj, null) - //cw.visitInnerClass("net/minecraftforge/event/entity/player/PlayerEvent$BreakSpeed","net/minecraftforge/event/entity/player/PlayerEvent","BreakSpeed",ACC_PUBLIC+ACC_STATIC); - { - cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, "callback", L(consumer), L(consumer + "<" + L(event) + ">"), null).visitEnd() - } - { - const con = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "(" + L(consumer) + ")V", "(" + L(consumer + "<" + L(event) + ">") + ")V", null) - con.visitCode() - con.visitVarInsn(Opcodes.ALOAD, 0) - con.visitMethodInsn(Opcodes.INVOKESPECIAL, obj, "<init>", "()V", false) - - con.visitVarInsn(Opcodes.ALOAD, 0) - con.visitVarInsn(Opcodes.ALOAD, 1) - con.visitFieldInsn(Opcodes.PUTFIELD, name, "callback", L(consumer)) - con.visitFieldInsn(Opcodes.GETSTATIC, mcForge, "EVENT_BUS", L(eventBus)) - con.visitVarInsn(Opcodes.ALOAD, 0) - con.visitMethodInsn(Opcodes.INVOKEVIRTUAL, eventBus, "register", "(" + L(obj) + ")V", false) - con.visitInsn(Opcodes.RETURN) - con.visitMaxs(2, 2) - con.visitEnd() - } - { - const mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "on", "(" + L(event) + ")V", null, null) - { - const av = mv.visitAnnotation(L(subscribeEvent), true) - av.visitEnum("priority", "Lnet/minecraftforge/fml/common/eventhandler/EventPriority;", priority.name()); - av.visitEnd() - } - mv.visitCode() - mv.visitVarInsn(Opcodes.ALOAD, 0) - mv.visitFieldInsn(Opcodes.GETFIELD, name, "callback", L(consumer)) - mv.visitVarInsn(Opcodes.ALOAD, 1) - mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, consumer, "accept", "(" + L(obj) + ")V", true) - mv.visitInsn(Opcodes.RETURN) - mv.visitMaxs(2, 2) - mv.visitEnd() - } - cw.visitEnd() - - const inst = defineClassBytes(name, cw.toByteArray()) - .getDeclaredConstructor(Consumer.class) - .newInstance(new java.util.function.Consumer({ - accept: function (t) { cb(t) } - })) - LoadedInsts.push(inst) - return inst; -} - -const unregisterForge = inst => { - MinecraftForge.EVENT_BUS.unregister(inst) -} - -register("gameUnload", () => { - LoadedInsts.forEach(unregisterForge) - LoadedInsts.length = 0 -}) - -export { registerForge, unregisterForge }
\ No newline at end of file |