diff --git a/build.gradle.kts b/build.gradle.kts index 1920f5a6..d6b422a0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,6 +25,10 @@ val shadowImpl: Configuration by configurations.creating { configurations.implementation.get().extendsFrom(this) } +loom { + accessWidenerPath = rootProject.file("src/main/resources/cobalt.accesswidener") +} + dependencies { minecraft(libs.minecraft) implementation(libs.bundles.fabric) diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 6e566264..bea0121d 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -57,7 +57,7 @@ complexity: CyclomaticComplexMethod: active: true - allowedComplexity: 6 + allowedComplexity: 10 NestedBlockDepth: active: true diff --git a/src/main/java/org/cobalt/mixin/client/AbstractClientPlayerAccessor.java b/src/main/java/org/cobalt/mixin/client/AbstractClientPlayerAccessor.java deleted file mode 100644 index bcafb250..00000000 --- a/src/main/java/org/cobalt/mixin/client/AbstractClientPlayerAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.cobalt.mixin.client; - -import net.minecraft.client.multiplayer.PlayerInfo; -import net.minecraft.client.player.AbstractClientPlayer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(AbstractClientPlayer.class) -public interface AbstractClientPlayerAccessor { - - @Accessor("playerInfo") - PlayerInfo getClientPlayerInfo(); - -} diff --git a/src/main/java/org/cobalt/mixin/client/MinecraftAccessor.java b/src/main/java/org/cobalt/mixin/client/MinecraftAccessor.java deleted file mode 100644 index 65b3600b..00000000 --- a/src/main/java/org/cobalt/mixin/client/MinecraftAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.cobalt.mixin.client; - -import net.minecraft.client.Minecraft; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(Minecraft.class) -public interface MinecraftAccessor { - - @Invoker("startAttack") - boolean leftClick(); - - @Invoker("startUseItem") - void rightClick(); - -} diff --git a/src/main/java/org/cobalt/mixin/client/MouseHandlerMixin.java b/src/main/java/org/cobalt/mixin/client/MouseHandlerMixin.java index b7109a0a..25309c64 100644 --- a/src/main/java/org/cobalt/mixin/client/MouseHandlerMixin.java +++ b/src/main/java/org/cobalt/mixin/client/MouseHandlerMixin.java @@ -4,6 +4,7 @@ import net.minecraft.client.input.MouseButtonInfo; import org.cobalt.event.EventBus; import org.cobalt.event.impl.MouseEvent; +import org.cobalt.util.MouseMode; import org.cobalt.util.MouseUtils; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -65,14 +66,14 @@ private void onMouseButton(long handle, MouseButtonInfo rawButtonInfo, int actio @Inject(method = "turnPlayer", at = @At("HEAD"), cancellable = true) private void onUpdateMouse(CallbackInfo callbackInfo) { - if (MouseUtils.shouldBlockRotation()) { + if (MouseUtils.getMouseMode() == MouseMode.LOCK_MOUSE) { callbackInfo.cancel(); } } @Inject(method = "isMouseGrabbed", at = @At("HEAD"), cancellable = true) private void onIsCursorLocked(CallbackInfoReturnable callbackInfoReturnable) { - if (MouseUtils.isForceUngrabbed()) { + if (MouseUtils.getMouseMode() == MouseMode.UNGRAB_MOUSE) { if (this.mouseGrabbed) { this.releaseMouse(); } @@ -83,7 +84,7 @@ private void onIsCursorLocked(CallbackInfoReturnable callbackInfoReturn @Inject(method = "grabMouse", at = @At("HEAD"), cancellable = true) private void onLockCursor(CallbackInfo callbackInfo) { - if (MouseUtils.isForceUngrabbed()) { + if (MouseUtils.getMouseMode() == MouseMode.UNGRAB_MOUSE) { callbackInfo.cancel(); } } diff --git a/src/main/java/org/cobalt/mixin/gui/SplashManagerMixin.java b/src/main/java/org/cobalt/mixin/gui/SplashManagerMixin.java new file mode 100644 index 00000000..bf064586 --- /dev/null +++ b/src/main/java/org/cobalt/mixin/gui/SplashManagerMixin.java @@ -0,0 +1,41 @@ +package org.cobalt.mixin.gui; + +import net.minecraft.client.gui.components.SplashRenderer; +import net.minecraft.client.resources.SplashManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import org.cobalt.Cobalt; +import org.cobalt.ui.theme.ThemeManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +@Mixin(SplashManager.class) +public class SplashManagerMixin { + + @Inject( + method = "getSplash", + at = @At("HEAD"), + cancellable = true + ) + private void modifySplash(CallbackInfoReturnable cir) { + Component splash = cobalt$createSplash(); + SplashRenderer splashRenderer = new SplashRenderer(splash); + + cir.setReturnValue(splashRenderer); + } + + @Unique + private Component cobalt$createSplash() { + int color = ThemeManager.getActiveTheme().getAccentPrimary(); + + return Component.literal(Cobalt.MOD_NAME + " on top!") + .setStyle(Style.EMPTY.withColor(TextColor.fromRgb(color))); + } + +} diff --git a/src/main/java/org/cobalt/mixin/gui/SplashRendererMixin.java b/src/main/java/org/cobalt/mixin/gui/SplashRendererMixin.java deleted file mode 100644 index 210ffec8..00000000 --- a/src/main/java/org/cobalt/mixin/gui/SplashRendererMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.cobalt.mixin.gui; - -import net.minecraft.client.gui.components.SplashRenderer; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; -import net.minecraft.network.chat.TextColor; -import org.cobalt.Cobalt; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyArgs; -import org.spongepowered.asm.mixin.injection.invoke.arg.Args; - -@Mixin(SplashRenderer.class) -public class SplashRendererMixin { - - @Final - @Unique - public Component cobalt$splash = Component.literal(Cobalt.MOD_NAME + " on top!") - .setStyle(Style.EMPTY.withColor(TextColor.fromRgb(0x4F8CFF))); - - @ModifyArgs( - method = "extractRenderState", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/gui/ActiveTextCollector;accept(Lnet/minecraft/client/gui/TextAlignment;IILnet/minecraft/client/gui/ActiveTextCollector$Parameters;Lnet/minecraft/network/chat/Component;)V" - ) - ) - private void modifySplash(Args args) { - args.set(4, cobalt$splash); - } - -} diff --git a/src/main/java/org/cobalt/mixin/render/FrustumInvoker.java b/src/main/java/org/cobalt/mixin/render/FrustumInvoker.java deleted file mode 100644 index 1b74d5d2..00000000 --- a/src/main/java/org/cobalt/mixin/render/FrustumInvoker.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.cobalt.mixin.render; - -import net.minecraft.client.renderer.culling.Frustum; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(Frustum.class) -public interface FrustumInvoker { - - @Invoker - int invokeCubeInFrustum(double minX, double minY, double minZ, double maxX, double maxY, double maxZ); - -} diff --git a/src/main/kotlin/org/cobalt/Cobalt.kt b/src/main/kotlin/org/cobalt/Cobalt.kt index 62ac8e66..951554f3 100644 --- a/src/main/kotlin/org/cobalt/Cobalt.kt +++ b/src/main/kotlin/org/cobalt/Cobalt.kt @@ -11,6 +11,7 @@ import org.cobalt.command.impl.MainCommand import org.cobalt.event.EventBus import org.cobalt.event.impl.WorldRenderEvent import org.cobalt.module.ModuleManager +import org.cobalt.script.ScriptManager import org.slf4j.LoggerFactory object Cobalt : ClientModInitializer { @@ -33,6 +34,7 @@ object Cobalt : ClientModInitializer { override fun onInitializeClient() { logger.info("Initializing $MOD_NAME ${SharedConstants.getCurrentVersion().name()} (v$MOD_VERSION)") + ScriptManager.registerScripts() ModuleManager.registerModules() CommandManager.register(MainCommand) diff --git a/src/main/kotlin/org/cobalt/command/CommandManager.kt b/src/main/kotlin/org/cobalt/command/CommandManager.kt index bd4bffa7..3f3f0e9a 100644 --- a/src/main/kotlin/org/cobalt/command/CommandManager.kt +++ b/src/main/kotlin/org/cobalt/command/CommandManager.kt @@ -43,6 +43,7 @@ object CommandManager { try { dispatcher.execute(commandLine, player.connection.suggestionsProvider) + minecraft.commandHistory().addCommand(content) } catch (exception: CommandSyntaxException) { ChatUtils.sendSystemMessage("${ChatFormatting.RED}${exception.message}") } diff --git a/src/main/kotlin/org/cobalt/command/impl/MainCommand.kt b/src/main/kotlin/org/cobalt/command/impl/MainCommand.kt index a9f91c3c..9be876ff 100644 --- a/src/main/kotlin/org/cobalt/command/impl/MainCommand.kt +++ b/src/main/kotlin/org/cobalt/command/impl/MainCommand.kt @@ -1,11 +1,14 @@ package org.cobalt.command.impl +import kotlin.time.Duration.Companion.seconds import org.cobalt.Cobalt.minecraft import org.cobalt.command.Command import org.cobalt.command.annotation.DefaultHandler import org.cobalt.command.annotation.SubCommand +import org.cobalt.ui.notification.NotificationManager import org.cobalt.ui.screen.ConfigScreen import org.cobalt.ui.screen.HudEditorScreen +import org.cobalt.util.MouseUtils import org.cobalt.util.helper.TickScheduler internal object MainCommand : Command(name = "cobalt", aliases = listOf("cb")) { @@ -26,4 +29,9 @@ internal object MainCommand : Command(name = "cobalt", aliases = listOf("cb")) { } } + @SubCommand + fun notification(title: String, description: String, duration: Int) { + NotificationManager.queue(title, description, duration.seconds) + } + } diff --git a/src/main/kotlin/org/cobalt/dsl/Utils.kt b/src/main/kotlin/org/cobalt/dsl/Utils.kt index e2d5555e..89f92a6e 100644 --- a/src/main/kotlin/org/cobalt/dsl/Utils.kt +++ b/src/main/kotlin/org/cobalt/dsl/Utils.kt @@ -1,7 +1,5 @@ package org.cobalt.dsl -import org.cobalt.Cobalt.minecraft - inline val Int.red get() = this shr 16 and 0xFF @@ -13,9 +11,3 @@ inline val Int.blue inline val Int.alpha get() = this shr 24 and 0xFF - -inline val mouseX: Float - get() = minecraft.mouseHandler.xpos().toFloat() - -inline val mouseY: Float - get() = minecraft.mouseHandler.ypos().toFloat() diff --git a/src/main/kotlin/org/cobalt/event/impl/SkiaDrawEvent.kt b/src/main/kotlin/org/cobalt/event/impl/SkiaDrawEvent.kt index 02c6e4e2..6fd1af0d 100644 --- a/src/main/kotlin/org/cobalt/event/impl/SkiaDrawEvent.kt +++ b/src/main/kotlin/org/cobalt/event/impl/SkiaDrawEvent.kt @@ -1,12 +1,12 @@ package org.cobalt.event.impl +import io.github.humbleui.skija.BackendRenderTarget import io.github.humbleui.skija.Canvas import io.github.humbleui.skija.DirectContext import org.cobalt.event.Event -import org.cobalt.util.skia.WrappedBackendRenderTarget class SkiaDrawEvent( val context: DirectContext, - val renderTarget: WrappedBackendRenderTarget, + val renderTarget: BackendRenderTarget, val canvas: Canvas, ) : Event() diff --git a/src/main/kotlin/org/cobalt/module/Module.kt b/src/main/kotlin/org/cobalt/module/Module.kt index 1036c52c..f9f90703 100644 --- a/src/main/kotlin/org/cobalt/module/Module.kt +++ b/src/main/kotlin/org/cobalt/module/Module.kt @@ -1,86 +1,96 @@ package org.cobalt.module -import net.minecraft.ChatFormatting -import org.cobalt.util.ChatUtils +import org.cobalt.ui.theme.Theme +import org.cobalt.ui.theme.ThemeManager +import org.cobalt.util.Dimensions +import org.cobalt.util.Vec2f +import org.cobalt.util.WindowUtils.windowHeight +import org.cobalt.util.WindowUtils.windowWidth abstract class Module( val name: String, val category: ModuleCategory, ) { - private var enabled: Boolean = false + var enabled: Boolean = false open fun onRegistration() {} - fun setEnabled(enabled: Boolean) { - this.enabled = enabled - } - - fun isEnabled(): Boolean = enabled - } -abstract class Script( +abstract class RenderableModule( name: String, category: ModuleCategory, + var anchor: Anchor = Anchor.TOP_LEFT, + var offsetX: Float = 5.0f, + var offsetY: Float = 5.0f, + var scale: Float = 1.0f, ) : Module(name, category) { - private var running: Boolean = false - - abstract fun onEnable() - abstract fun onDisable() - - fun startScript() { - onEnable() - ChatUtils.sendSystemMessage("$name ${ChatFormatting.GREEN}Started") - running = true - } - - fun stopScript() { - onDisable() - ChatUtils.sendSystemMessage("$name ${ChatFormatting.RED}Stopped") - running = false - } - - fun toggleScript() { - if (running) { - stopScript() - } else { - startScript() + val theme: Theme + get() = ThemeManager.getActiveTheme() + + val screenPosition: Vec2f + get() = anchor.computePosition( + offsetX, + offsetY, + getWidth() * scale, + getHeight() * scale, + windowWidth, + windowHeight + ) + + val dimensions: Dimensions + get() = Dimensions(getWidth(), getHeight()) + + val xPos: Float + get() = screenPosition.x + + val yPos: Float + get() = screenPosition.y + + abstract fun getWidth(): Float + abstract fun getHeight(): Float + abstract fun renderComponent() + + enum class Anchor { + + TOP_LEFT, + TOP_CENTER, + TOP_RIGHT, + CENTER_LEFT, + CENTER, + CENTER_RIGHT, + BOTTOM_LEFT, + BOTTOM_CENTER, + BOTTOM_RIGHT; + + fun computePosition( + offsetX: Float, + offsetY: Float, + moduleWidth: Float, + moduleHeight: Float, + screenWidth: Float, + screenHeight: Float, + ): Vec2f { + val x = when (this) { + TOP_LEFT, CENTER_LEFT, BOTTOM_LEFT -> offsetX + TOP_CENTER, CENTER, BOTTOM_CENTER -> screenWidth / 2f - moduleWidth / 2f + offsetX + TOP_RIGHT, CENTER_RIGHT, BOTTOM_RIGHT -> screenWidth - moduleWidth - offsetX + } + + val y = when (this) { + TOP_LEFT, TOP_CENTER, TOP_RIGHT -> offsetY + CENTER_LEFT, CENTER, CENTER_RIGHT -> screenHeight / 2f - moduleHeight / 2f + offsetY + BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT -> screenHeight - moduleHeight - offsetY + } + + return Vec2f( + x.coerceIn(0f, (screenWidth - moduleWidth).coerceAtLeast(0f)), + y.coerceIn(0f, (screenHeight - moduleHeight).coerceAtLeast(0f)) + ) } - } - - fun isRunning(): Boolean = running -} - -interface Renderable { - - val renderProps: RenderProperties - - var xPos: Float - get() = renderProps.xPos; - set(value) { renderProps.xPos = value } - - var yPos: Float - get() = renderProps.yPos; - set(value) { renderProps.yPos = value } - - var scale: Float - get() = renderProps.scale; - set(value) { renderProps.scale = value } - - fun getWidth(): Float - fun getHeight(): Float - fun renderComponent() + } } - -private const val DEFAULT_OFFSET = 5.0f -private const val DEFAULT_SCALE = 1.0f - -data class RenderProperties( - var xPos: Float = DEFAULT_OFFSET, - var yPos: Float = DEFAULT_OFFSET, - var scale: Float = DEFAULT_SCALE, -) diff --git a/src/main/kotlin/org/cobalt/module/ModuleManager.kt b/src/main/kotlin/org/cobalt/module/ModuleManager.kt index 9ad2536d..31f38b9f 100644 --- a/src/main/kotlin/org/cobalt/module/ModuleManager.kt +++ b/src/main/kotlin/org/cobalt/module/ModuleManager.kt @@ -5,13 +5,13 @@ import org.cobalt.event.EventBus import org.cobalt.event.annotation.SubscribeEvent import org.cobalt.event.impl.SkiaDrawEvent import org.cobalt.module.impl.render.PerformanceHUD +import org.cobalt.ui.screen.HudEditorScreen import org.cobalt.util.Vec2f -import org.cobalt.util.WindowUtils import org.cobalt.util.skia.SkiaTransforms object ModuleManager { - private val modules = mutableSetOf() + val modules = mutableSetOf() init { EventBus.register(this) @@ -45,39 +45,33 @@ object ModuleManager { } } - fun getModules(): Set { - return modules - } - @SubscribeEvent fun drawRenderableModules(@Suppress("UnusedParameter") event: SkiaDrawEvent) { - if ( - minecraft.level == null || - minecraft.player == null || - minecraft.options.hideGui || - minecraft.debugOverlay.showDebugScreen() - ) { + if (minecraft.level == null || minecraft.player == null) { + return + } + + if (minecraft.options.hideGui || minecraft.debugOverlay.showDebugScreen()) { return } - val windowScale = WindowUtils.getWindowScale() + if (minecraft.screen is HudEditorScreen) { + return + } - modules - .filter { module -> module.isEnabled() && module is Renderable } + modules.filterIsInstance() + .filter { module -> module.enabled } .forEach { module -> - val renderable = module as Renderable - SkiaTransforms.save() - val originX = renderable.xPos - val originY = renderable.yPos - val moduleScale = renderable.scale * windowScale + val (x, y) = module.screenPosition + val scale = module.scale - SkiaTransforms.translate(Vec2f(originX, originY)) - SkiaTransforms.scale(Vec2f(moduleScale, moduleScale)) - SkiaTransforms.translate(Vec2f(-originX, -originY)) + SkiaTransforms.translate(Vec2f(x, y)) + SkiaTransforms.scale(Vec2f(scale, scale)) + SkiaTransforms.translate(Vec2f(-x, -y)) - renderable.renderComponent() + module.renderComponent() SkiaTransforms.restore() } diff --git a/src/main/kotlin/org/cobalt/module/impl/render/PerformanceHUD.kt b/src/main/kotlin/org/cobalt/module/impl/render/PerformanceHUD.kt index 744888b4..d05e6b17 100644 --- a/src/main/kotlin/org/cobalt/module/impl/render/PerformanceHUD.kt +++ b/src/main/kotlin/org/cobalt/module/impl/render/PerformanceHUD.kt @@ -2,11 +2,8 @@ package org.cobalt.module.impl.render import kotlin.math.roundToInt import org.cobalt.Cobalt.minecraft -import org.cobalt.module.Module import org.cobalt.module.ModuleCategory -import org.cobalt.module.RenderProperties -import org.cobalt.module.Renderable -import org.cobalt.ui.ColorPalette +import org.cobalt.module.RenderableModule import org.cobalt.util.Dimensions import org.cobalt.util.ServerUtils import org.cobalt.util.Vec2f @@ -14,22 +11,10 @@ import org.cobalt.util.skia.SkiaShapes import org.cobalt.util.skia.SkiaText import org.cobalt.util.skia.TextStyle -internal object PerformanceHUD : Module( +internal object PerformanceHUD : RenderableModule( name = "Performance HUD", category = ModuleCategory.RENDER, -), Renderable { - - override var renderProps = RenderProperties() - - private const val PADDING = 25f - private const val CORNER_RADIUS = 5f - private const val OUTLINE_THICKNESS = 2f - private const val FONT_SIZE = 16f - private const val TEXT_SPACING = 5f - private const val DIVIDER_HALF_HEIGHT = 10f - private const val PANEL_HEIGHT = 50f - private const val MID_FACTOR = 0.5f - private const val DIVIDER_GAP = PADDING / 2 + TEXT_SPACING +) { override fun getWidth(): Float { var width = PADDING * 2 @@ -59,13 +44,11 @@ internal object PerformanceHUD : Module( } private fun drawBackground(width: Float, height: Float) { - SkiaShapes.drawRoundedRect(Vec2f(xPos, yPos), Dimensions(width, height), CORNER_RADIUS, ColorPalette.PANEL) - SkiaShapes.drawRoundedOutline( + SkiaShapes.drawRoundedRect( Vec2f(xPos, yPos), Dimensions(width, height), CORNER_RADIUS, - ColorPalette.BORDER, - OUTLINE_THICKNESS + theme.backgroundPrimary ) } @@ -86,16 +69,17 @@ internal object PerformanceHUD : Module( private fun drawDivider(startX: Float, height: Float): Float { var x = startX + DIVIDER_GAP - val midY = yPos + height * MID_FACTOR + SkiaShapes.drawLine( Vec2f(x, midY - DIVIDER_HALF_HEIGHT), Vec2f(x, midY + DIVIDER_HALF_HEIGHT), - ColorPalette.BORDER, + theme.border, OUTLINE_THICKNESS ) x += DIVIDER_GAP + return x } @@ -106,7 +90,7 @@ internal object PerformanceHUD : Module( SkiaText.primaryFont, stat.value, Vec2f(x, textY), - TextStyle(FONT_SIZE, ColorPalette.TEXT_PRIMARY) + TextStyle(FONT_SIZE, theme.textPrimary) ) x += SkiaText.getTextWidth(SkiaText.primaryFont, stat.value, FONT_SIZE) + TEXT_SPACING @@ -115,7 +99,7 @@ internal object PerformanceHUD : Module( SkiaText.primaryFont, stat.unit, Vec2f(x, textY), - TextStyle(FONT_SIZE, ColorPalette.TEXT_DISABLED) + TextStyle(FONT_SIZE, theme.textDisabled) ) x += SkiaText.getTextWidth(SkiaText.primaryFont, stat.unit, FONT_SIZE) @@ -133,6 +117,16 @@ internal object PerformanceHUD : Module( private fun getTPS(): String = ServerUtils.averageTps.roundToInt().toString() private fun getPing(): String = ServerUtils.currentPing.toString() + private const val PADDING = 25f + private const val CORNER_RADIUS = 5f + private const val OUTLINE_THICKNESS = 2f + private const val FONT_SIZE = 16f + private const val TEXT_SPACING = 5f + private const val DIVIDER_HALF_HEIGHT = 10f + private const val PANEL_HEIGHT = 50f + private const val MID_FACTOR = 0.5f + private const val DIVIDER_GAP = PADDING / 2 + TEXT_SPACING + private data class Stat(val value: String, val unit: String) } diff --git a/src/main/kotlin/org/cobalt/script/Script.kt b/src/main/kotlin/org/cobalt/script/Script.kt new file mode 100644 index 00000000..74bb8750 --- /dev/null +++ b/src/main/kotlin/org/cobalt/script/Script.kt @@ -0,0 +1,37 @@ +package org.cobalt.script + +import net.minecraft.ChatFormatting +import org.cobalt.util.ChatUtils + +abstract class Script( + val name: String, + val category: ScriptCategory, +) { + + var running: Boolean = false + private set + + abstract fun onEnable() + abstract fun onDisable() + + fun startScript() { + onEnable() + ChatUtils.sendSystemMessage("$name ${ChatFormatting.GREEN}Started") + running = true + } + + fun stopScript() { + onDisable() + ChatUtils.sendSystemMessage("$name ${ChatFormatting.RED}Stopped") + running = false + } + + fun toggleScript() { + if (running) { + stopScript() + } else { + startScript() + } + } + +} diff --git a/src/main/kotlin/org/cobalt/script/ScriptCategory.kt b/src/main/kotlin/org/cobalt/script/ScriptCategory.kt new file mode 100644 index 00000000..1e66ba04 --- /dev/null +++ b/src/main/kotlin/org/cobalt/script/ScriptCategory.kt @@ -0,0 +1,26 @@ +package org.cobalt.script + +class ScriptCategory private constructor( + val displayName: String, +) { + + companion object { + + private val entries = mutableMapOf() + + @JvmField + val SKILLS = register(displayName = "Skills") + + fun register(displayName: String): ScriptCategory { + return entries.getOrPut(displayName.lowercase()) { + ScriptCategory(displayName) + } + } + + fun getCategories(): Collection { + return entries.values + } + + } + +} diff --git a/src/main/kotlin/org/cobalt/script/ScriptManager.kt b/src/main/kotlin/org/cobalt/script/ScriptManager.kt new file mode 100644 index 00000000..5f91784c --- /dev/null +++ b/src/main/kotlin/org/cobalt/script/ScriptManager.kt @@ -0,0 +1,40 @@ +package org.cobalt.script + +import org.cobalt.event.EventBus +import org.cobalt.module.impl.render.PerformanceHUD + +object ScriptManager { + + val scripts = mutableSetOf