From ceac1fda7a1fe6150271105231527e7acd0492e5 Mon Sep 17 00:00:00 2001 From: videogame hacker Date: Thu, 3 Feb 2022 19:29:14 +0000 Subject: [PATCH] Create features system with Flight, No Fall Damage --- build.gradle.kts | 31 +++- gradle.properties | 1 + settings.gradle.kts | 3 +- .../mixins/MixinClientPlayNetworkHandler.java | 22 +++ .../mixins/MixinExtClientPlayerEntity.java | 38 +++++ .../mixins/MixinExtPlayerMoveC2SPacket.java | 13 ++ ...ixinExtUpdatePlayerAbilitiesC2SPacket.java | 13 ++ .../hibiscus/mixins/MixinMinecraftClient.java | 45 +++++ .../hackery/unknit/MixinMinecraftMain.java | 33 ++-- .../kotlin/codes/som/hibiscus/HibiscusMod.kt | 12 +- .../codes/som/hibiscus/MinecraftAccessors.kt | 4 + .../som/hibiscus/api/event/Cancellable.kt | 10 ++ .../som/hibiscus/api/event/TypedListener.kt | 13 ++ .../codes/som/hibiscus/api/feature/Feature.kt | 37 +++++ .../hibiscus/api/feature/FeatureCategory.kt | 6 + .../api/feature/values/BooleanValue.kt | 11 ++ .../hibiscus/api/feature/values/FloatValue.kt | 23 +++ .../api/feature/values/IntegerValue.kt | 23 +++ .../api/feature/values/KeyboardValue.kt | 18 ++ .../api/feature/values/RegisteredValue.kt | 25 +++ .../api/feature/values/StringValue.kt | 21 +++ .../api/feature/values/ValueRegistry.kt | 29 ++++ .../som/hibiscus/events/NetworkEvents.kt | 15 ++ .../{PlayerTickEvent.kt => PlayerEvents.kt} | 0 .../codes/som/hibiscus/events/RenderEvents.kt | 5 + .../som/hibiscus/features/FeatureList.kt | 10 ++ .../som/hibiscus/features/FeaturesRegistry.kt | 7 + .../som/hibiscus/features/movement/Flight.kt | 79 +++++++++ .../hibiscus/features/player/NoFallDamage.kt | 19 +++ .../kotlin/codes/som/hibiscus/gui/ImGuiKt.kt | 37 +++++ .../codes/som/hibiscus/gui/ImGuiRenderer.kt | 47 ++++++ .../codes/som/hibiscus/gui/ImGuiScreen.kt | 37 +---- .../som/hibiscus/gui/ModuleControlsUI.kt | 58 +++++++ .../som/hibiscus/util/ext/RequireExtension.kt | 14 ++ .../codes/som/hibiscus/util/input/Keys.kt | 155 ++++++++++++++++++ .../util/netmoving/NetworkMovingEvent.kt | 64 ++++++++ src/main/resources/hibiscus.mixins.json | 9 +- 37 files changed, 930 insertions(+), 57 deletions(-) create mode 100644 src/main/java/codes/som/hibiscus/mixins/MixinClientPlayNetworkHandler.java create mode 100644 src/main/java/codes/som/hibiscus/mixins/MixinExtClientPlayerEntity.java create mode 100644 src/main/java/codes/som/hibiscus/mixins/MixinExtPlayerMoveC2SPacket.java create mode 100644 src/main/java/codes/som/hibiscus/mixins/MixinExtUpdatePlayerAbilitiesC2SPacket.java create mode 100644 src/main/java/codes/som/hibiscus/mixins/MixinMinecraftClient.java create mode 100644 src/main/kotlin/codes/som/hibiscus/api/event/Cancellable.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/event/TypedListener.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/Feature.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/FeatureCategory.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/BooleanValue.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/FloatValue.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/IntegerValue.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/KeyboardValue.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/RegisteredValue.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/StringValue.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/api/feature/values/ValueRegistry.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/events/NetworkEvents.kt rename src/main/kotlin/codes/som/hibiscus/events/{PlayerTickEvent.kt => PlayerEvents.kt} (100%) create mode 100644 src/main/kotlin/codes/som/hibiscus/events/RenderEvents.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/features/FeatureList.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/features/movement/Flight.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/features/player/NoFallDamage.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/gui/ImGuiKt.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/gui/ImGuiRenderer.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/gui/ModuleControlsUI.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/util/ext/RequireExtension.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/util/input/Keys.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/util/netmoving/NetworkMovingEvent.kt diff --git a/build.gradle.kts b/build.gradle.kts index 5e98bf7..8c23d80 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,11 @@ +import org.gradle.kotlin.dsl.accessors.runtime.extensionOf +import org.quiltmc.quiltmappings.loom.QuiltMappingsOnLoomPlugin + plugins { id("fabric-loom") val kotlinVersion: String by System.getProperties() kotlin("jvm").version(kotlinVersion) + id("org.quiltmc.quilt-mappings-on-loom").version("3.1.1") } base { @@ -21,8 +25,25 @@ repositories {} dependencies { val minecraftVersion: String by project minecraft("com.mojang:minecraft:$minecraftVersion") - val yarnMappings: String by project - mappings("net.fabricmc:yarn:$yarnMappings:v2") + + val USE_QUILT_MAPPINGS = false + if (USE_QUILT_MAPPINGS) { + // Seems to crash on startup right now + + val quiltMappings: String by project + mappings(loom.layered { + officialMojangMappings { + nameSyntheticMembers = false + } + + val qm = extensionOf(project, "quiltMappings") as QuiltMappingsOnLoomPlugin.QuiltMappingsOnLoomExtension + addLayer(qm.mappings("org.quiltmc:quilt-mappings:${quiltMappings}:v2")) + }) + } else { + val yarnMappings: String by project + mappings("net.fabricmc:yarn:$yarnMappings:v2") + } + val loaderVersion: String by project modImplementation("net.fabricmc:fabric-loader:$loaderVersion") val fabricVersion: String by project @@ -49,7 +70,11 @@ tasks { } withType { - kotlinOptions { jvmTarget = javaVersion.toString() } + kotlinOptions { + jvmTarget = javaVersion.toString() + freeCompilerArgs = freeCompilerArgs + listOf("-Xopt-in=kotlin.RequiresOptIn") + } + sourceCompatibility = javaVersion.toString() targetCompatibility = javaVersion.toString() } diff --git a/gradle.properties b/gradle.properties index b032ddd..71a534f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,6 +4,7 @@ org.gradle.warning.mode=all # Check these on https://fabricmc.net/develop/ minecraftVersion=1.18.1 yarnMappings=1.18.1+build.22 +quiltMappings=1.18.1+build.6 loaderVersion=0.12.12 # Fabric API fabricVersion=0.46.1+1.18 diff --git a/settings.gradle.kts b/settings.gradle.kts index 7cab0d8..5d35d71 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,7 @@ pluginManagement { repositories { maven("https://maven.fabricmc.net") { name = "Fabric" } + maven("https://maven.quiltmc.org/repository/release") { name = "Quilt" } mavenCentral() gradlePluginPortal() } @@ -10,4 +11,4 @@ pluginManagement { val kotlinVersion: String by System.getProperties() kotlin("jvm").version(kotlinVersion) } -} \ No newline at end of file +} diff --git a/src/main/java/codes/som/hibiscus/mixins/MixinClientPlayNetworkHandler.java b/src/main/java/codes/som/hibiscus/mixins/MixinClientPlayNetworkHandler.java new file mode 100644 index 0000000..1196d1d --- /dev/null +++ b/src/main/java/codes/som/hibiscus/mixins/MixinClientPlayNetworkHandler.java @@ -0,0 +1,22 @@ +package codes.som.hibiscus.mixins; + +import codes.som.hibiscus.HibiscusMod; +import codes.som.hibiscus.events.SendPacketEvent; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.Packet; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ClientPlayNetworkHandler.class) +public abstract class MixinClientPlayNetworkHandler { + @Redirect(method = "sendPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;send(Lnet/minecraft/network/Packet;)V")) + public void onSendPacket(ClientConnection clientConnection, Packet packet) { + var event = new SendPacketEvent(packet); + HibiscusMod.bus().fire(event); + if (!event.isCancelled()) { + clientConnection.send(event.getPacket()); + } + } +} diff --git a/src/main/java/codes/som/hibiscus/mixins/MixinExtClientPlayerEntity.java b/src/main/java/codes/som/hibiscus/mixins/MixinExtClientPlayerEntity.java new file mode 100644 index 0000000..a6dff50 --- /dev/null +++ b/src/main/java/codes/som/hibiscus/mixins/MixinExtClientPlayerEntity.java @@ -0,0 +1,38 @@ +package codes.som.hibiscus.mixins; + +import net.minecraft.client.network.ClientPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ClientPlayerEntity.class) +public interface MixinExtClientPlayerEntity { + @Accessor + double getLastX(); + + @Accessor + void setLastX(double lastX); + + @Accessor + double getLastBaseY(); + + @Accessor + void setLastBaseY(double lastBaseY); + + @Accessor + double getLastZ(); + + @Accessor + void setLastZ(double lastZ); + + @Accessor + float getLastYaw(); + + @Accessor + void setLastYaw(float lastYaw); + + @Accessor + float getLastPitch(); + + @Accessor + void setLastPitch(float lastPitch); +} diff --git a/src/main/java/codes/som/hibiscus/mixins/MixinExtPlayerMoveC2SPacket.java b/src/main/java/codes/som/hibiscus/mixins/MixinExtPlayerMoveC2SPacket.java new file mode 100644 index 0000000..cff1d2c --- /dev/null +++ b/src/main/java/codes/som/hibiscus/mixins/MixinExtPlayerMoveC2SPacket.java @@ -0,0 +1,13 @@ +package codes.som.hibiscus.mixins; + +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(PlayerMoveC2SPacket.class) +public interface MixinExtPlayerMoveC2SPacket { + @Accessor + @Mutable + void setOnGround(boolean onGround); +} diff --git a/src/main/java/codes/som/hibiscus/mixins/MixinExtUpdatePlayerAbilitiesC2SPacket.java b/src/main/java/codes/som/hibiscus/mixins/MixinExtUpdatePlayerAbilitiesC2SPacket.java new file mode 100644 index 0000000..32eaee8 --- /dev/null +++ b/src/main/java/codes/som/hibiscus/mixins/MixinExtUpdatePlayerAbilitiesC2SPacket.java @@ -0,0 +1,13 @@ +package codes.som.hibiscus.mixins; + +import net.minecraft.network.packet.c2s.play.UpdatePlayerAbilitiesC2SPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(UpdatePlayerAbilitiesC2SPacket.class) +public interface MixinExtUpdatePlayerAbilitiesC2SPacket { + @Accessor + @Mutable + void setFlying(boolean flying); +} diff --git a/src/main/java/codes/som/hibiscus/mixins/MixinMinecraftClient.java b/src/main/java/codes/som/hibiscus/mixins/MixinMinecraftClient.java new file mode 100644 index 0000000..5879629 --- /dev/null +++ b/src/main/java/codes/som/hibiscus/mixins/MixinMinecraftClient.java @@ -0,0 +1,45 @@ +package codes.som.hibiscus.mixins; + +import codes.som.hibiscus.HibiscusMod; +import codes.som.hibiscus.events.RenderOverlayEvent; +import codes.som.hibiscus.gui.ImGuiRenderer; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.RunArgs; +import net.minecraft.client.render.RenderTickCounter; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftClient.class) +public abstract class MixinMinecraftClient { + @Shadow + private volatile boolean paused; + + @Shadow + private float pausedTickDelta; + + @Shadow + @Final + private RenderTickCounter renderTickCounter; + + @Inject(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/SplashOverlay;init(Lnet/minecraft/client/MinecraftClient;)V", shift = At.Shift.BEFORE)) + private void onFinishingStartup(RunArgs args, CallbackInfo ci) { + ImGuiRenderer.INSTANCE.setup(); + } + + @Inject(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;skipGameRender:Z", shift = At.Shift.BEFORE)) + private void onPreRenderEverything(boolean tick, CallbackInfo ci) { + float delta = this.paused ? this.pausedTickDelta : this.renderTickCounter.tickDelta; + ImGuiRenderer.INSTANCE.beginFrame(delta); + } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gl/Framebuffer;endWrite()V", shift = At.Shift.BEFORE)) + private void onPostRenderEverything(boolean tick, CallbackInfo ci) { + float delta = this.paused ? this.pausedTickDelta : this.renderTickCounter.tickDelta; + HibiscusMod.bus().fire(new RenderOverlayEvent(delta)); + ImGuiRenderer.INSTANCE.finishFrame(delta); + } +} diff --git a/src/main/java/site/hackery/unknit/MixinMinecraftMain.java b/src/main/java/site/hackery/unknit/MixinMinecraftMain.java index bbc3d9c..0f97d73 100644 --- a/src/main/java/site/hackery/unknit/MixinMinecraftMain.java +++ b/src/main/java/site/hackery/unknit/MixinMinecraftMain.java @@ -1,19 +1,26 @@ package site.hackery.unknit; -import com.mojang.authlib.*; -import com.mojang.authlib.exceptions.*; -import com.mojang.authlib.yggdrasil.*; -import com.mojang.util.*; -import net.minecraft.client.main.*; -import net.minecraft.client.util.*; -import org.spongepowered.asm.mixin.*; -import org.spongepowered.asm.mixin.injection.*; +import com.mojang.authlib.Agent; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.exceptions.AuthenticationException; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; +import com.mojang.util.UUIDTypeAdapter; +import net.minecraft.client.main.Main; +import net.minecraft.client.util.Session; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; -import java.io.*; -import java.net.*; -import java.nio.file.*; -import java.util.*; +import java.io.IOException; +import java.net.Proxy; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; @Mixin(Main.class) public abstract class MixinMinecraftMain { @@ -24,7 +31,7 @@ public abstract class MixinMinecraftMain { } } - @ModifyVariable(method = "main", at = @At("HEAD"), argsOnly = true) + @ModifyVariable(method = "main", at = @At("HEAD"), argsOnly = true, remap = false) private static String[] setArgs(String[] args) { List arguments = new ArrayList<>(Arrays.asList(args)); replace(arguments, "--version", "1.18.1"); diff --git a/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt b/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt index 5addaf6..db8af51 100644 --- a/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt +++ b/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt @@ -2,7 +2,9 @@ package codes.som.hibiscus import codes.som.hibiscus.api.event.EventBus import codes.som.hibiscus.events.KeyEvent +import codes.som.hibiscus.features.FeaturesRegistry import codes.som.hibiscus.gui.ImGuiScreen +import codes.som.hibiscus.util.netmoving.NetworkMovingDispatcher import net.fabricmc.api.ModInitializer import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_SHIFT @@ -15,9 +17,15 @@ object HibiscusMod : ModInitializer { @get:JvmName("bus") val bus = EventBus() + val features = FeaturesRegistry() + override fun onInitialize() { - bus.register { key: KeyEvent -> - if (key.key != GLFW_KEY_RIGHT_SHIFT || key.action != GLFW.GLFW_PRESS) + bus.register(NetworkMovingDispatcher()) + bus.register { event: KeyEvent -> + if (event.key != GLFW_KEY_RIGHT_SHIFT || event.action != GLFW.GLFW_PRESS) + return@register + + if (mc.currentScreen != null) return@register mc.setScreen(ImGuiScreen) diff --git a/src/main/kotlin/codes/som/hibiscus/MinecraftAccessors.kt b/src/main/kotlin/codes/som/hibiscus/MinecraftAccessors.kt index 384baa1..d12f0c3 100644 --- a/src/main/kotlin/codes/som/hibiscus/MinecraftAccessors.kt +++ b/src/main/kotlin/codes/som/hibiscus/MinecraftAccessors.kt @@ -1,5 +1,9 @@ package codes.som.hibiscus import net.minecraft.client.MinecraftClient +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.client.world.ClientWorld val mc: MinecraftClient inline get() = MinecraftClient.getInstance() +val player: ClientPlayerEntity inline get() = mc.player!! +val world: ClientWorld inline get() = mc.world!! diff --git a/src/main/kotlin/codes/som/hibiscus/api/event/Cancellable.kt b/src/main/kotlin/codes/som/hibiscus/api/event/Cancellable.kt new file mode 100644 index 0000000..3784896 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/event/Cancellable.kt @@ -0,0 +1,10 @@ +package codes.som.hibiscus.api.event + +abstract class Cancellable { + @get:JvmName("isCancelled") + var cancelled: Boolean = false + + fun cancel() { + cancelled = true + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/event/TypedListener.kt b/src/main/kotlin/codes/som/hibiscus/api/event/TypedListener.kt new file mode 100644 index 0000000..3470ed7 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/event/TypedListener.kt @@ -0,0 +1,13 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package codes.som.hibiscus.api.event + +abstract class TypedListener(val eventType: Class) : Listener + +inline fun EventBus.registerTyped(typedListener: TypedListener) { + register(typedListener.eventType, typedListener) +} + +inline fun EventBus.unregisterTyped(typedListener: TypedListener) { + unregister(typedListener.eventType, typedListener) +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/Feature.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/Feature.kt new file mode 100644 index 0000000..029067d --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/Feature.kt @@ -0,0 +1,37 @@ +package codes.som.hibiscus.api.feature + +import codes.som.hibiscus.HibiscusMod +import codes.som.hibiscus.api.event.* +import codes.som.hibiscus.api.feature.values.ValueRegistry + +abstract class Feature(val name: String, val category: FeatureCategory) { + private val listeners = mutableListOf>() + + protected inline fun on(listener: Listener) = + on(object : TypedListener(T::class.java), Listener by listener {}) + + protected fun on(listener: TypedListener) = + listeners.add(listener) + + val values = ValueRegistry() + + var enabled: Boolean = false + set(value) { + val hasChanged = value != field + if (hasChanged) { + field = value + if (value) { + onEnable() + listeners.forEach { HibiscusMod.bus.registerTyped(it) } + } else { + listeners.forEach { HibiscusMod.bus.unregisterTyped(it) } + onDisable() + } + } + } + + open fun onEnable() {} + open fun onDisable() {} + + // TODO: Module commands +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/FeatureCategory.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/FeatureCategory.kt new file mode 100644 index 0000000..ab9360d --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/FeatureCategory.kt @@ -0,0 +1,6 @@ +package codes.som.hibiscus.api.feature + +enum class FeatureCategory(val humanName: String) { + PLAYER("Player"), + MOVEMENT("Movement"), +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/BooleanValue.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/BooleanValue.kt new file mode 100644 index 0000000..dc822dd --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/BooleanValue.kt @@ -0,0 +1,11 @@ +package codes.som.hibiscus.api.feature.values + +import codes.som.hibiscus.gui.ImGuiKt + +class BooleanValue(name: String, value: Boolean) : RegisteredValue(name, value) { + override fun convertValueFromString(representation: String) = representation.toBoolean() + + override fun drawUIControl() { + ImGuiKt.checkbox(name, ::value) + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/FloatValue.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/FloatValue.kt new file mode 100644 index 0000000..8341d34 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/FloatValue.kt @@ -0,0 +1,23 @@ +package codes.som.hibiscus.api.feature.values + +import codes.som.hibiscus.gui.ImGuiKt + +class FloatValue( + name: String, value: Float, + val min: Float = Float.MIN_VALUE, val max: Float = Float.MAX_VALUE +) : RegisteredValue(name, value) { + override fun valueChangeHook(orig: Float, new: Float) = + new.coerceIn(min, max) + + override fun convertValueFromString(representation: String): Float { + return representation.toFloat() + } + + override fun drawUIControl() { + if (min == Float.MIN_VALUE || max == Float.MAX_VALUE) { + ImGuiKt.dragFloat(name, ::value, 1f, min, max) + } else { + ImGuiKt.sliderFloat(name, ::value, min, max) + } + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/IntegerValue.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/IntegerValue.kt new file mode 100644 index 0000000..1840bfa --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/IntegerValue.kt @@ -0,0 +1,23 @@ +package codes.som.hibiscus.api.feature.values + +import codes.som.hibiscus.gui.ImGuiKt + +class IntegerValue( + name: String, value: Int, + val min: Int = Int.MIN_VALUE, val max: Int = Int.MAX_VALUE +) : RegisteredValue(name, value) { + override fun valueChangeHook(orig: Int, new: Int) = + new.coerceIn(min, max) + + override fun convertValueFromString(representation: String): Int { + return representation.toInt() + } + + override fun drawUIControl() { + if (min == Int.MIN_VALUE || max == Int.MAX_VALUE) { + ImGuiKt.dragInt(name, ::value, 1f, min.toFloat(), max.toFloat()) + } else { + ImGuiKt.sliderInt(name, ::value, min, max) + } + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/KeyboardValue.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/KeyboardValue.kt new file mode 100644 index 0000000..988b946 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/KeyboardValue.kt @@ -0,0 +1,18 @@ +package codes.som.hibiscus.api.feature.values + +import codes.som.hibiscus.util.input.Keys +import org.lwjgl.glfw.GLFW + +class KeyboardValue(name: String, value: Int = GLFW.GLFW_KEY_UNKNOWN) : RegisteredValue(name, value) { + override fun convertValueFromString(representation: String): Int { + return Keys.KEY_MAP[representation.toUpperCase()] ?: -1 + } + + override fun getValueAsString(): String { + return Keys.KEY_MAP.inverse()[value] ?: "UNKNOWN" + } + + override fun drawUIControl() { + // TODO + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/RegisteredValue.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/RegisteredValue.kt new file mode 100644 index 0000000..38505b6 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/RegisteredValue.kt @@ -0,0 +1,25 @@ +package codes.som.hibiscus.api.feature.values + +import kotlin.reflect.KProperty + +abstract class RegisteredValue(val name: String, value: T) { + var value: T = value + set(value) { + field = valueChangeHook(field, value) + } + + open fun valueChangeHook(orig: T, new: T): T = new + + open fun getValueAsString(): String = value.toString() + abstract fun convertValueFromString(representation: String): T + fun setValueFromString(representation: String) { + value = convertValueFromString(representation) + } + + abstract fun drawUIControl() + + operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { + this.value = value + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/StringValue.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/StringValue.kt new file mode 100644 index 0000000..a977ca1 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/StringValue.kt @@ -0,0 +1,21 @@ +package codes.som.hibiscus.api.feature.values + +import imgui.ImGui +import imgui.type.ImString + +class StringValue(name: String, value: String) : RegisteredValue(name, value) { + override fun convertValueFromString(representation: String) = representation + + private val uiState = ImString(256) + private var lastValue = value + + override fun drawUIControl() { + if (value != lastValue) { + uiState.set(value) + } + + ImGui.inputText(name, uiState) + value = uiState.get() + lastValue = value + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/api/feature/values/ValueRegistry.kt b/src/main/kotlin/codes/som/hibiscus/api/feature/values/ValueRegistry.kt new file mode 100644 index 0000000..6d5c85e --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/api/feature/values/ValueRegistry.kt @@ -0,0 +1,29 @@ +package codes.som.hibiscus.api.feature.values + +import org.lwjgl.glfw.GLFW + +class ValueRegistry { + private val registeredValues = mutableListOf>() + + fun register(value: RegisteredValue<*>) { + registeredValues.add(value) + } + + fun exist() = registeredValues.isNotEmpty() + operator fun iterator() = registeredValues.iterator() + + fun string(name: String, default: String) = + StringValue(name, default).also(this::register) + + fun bool(name: String, default: Boolean) = + BooleanValue(name, default).also(this::register) + + fun int(name: String, default: Int, min: Int = Int.MIN_VALUE, max: Int = Int.MAX_VALUE) = + IntegerValue(name, default, min, max).also(this::register) + + fun key(name: String, default: Int = GLFW.GLFW_KEY_UNKNOWN) = + KeyboardValue(name, default).also(this::register) + + fun float(name: String, default: Float, min: Float = Float.MIN_VALUE, max: Float = Float.MAX_VALUE) = + FloatValue(name, default, min, max).also(this::register) +} diff --git a/src/main/kotlin/codes/som/hibiscus/events/NetworkEvents.kt b/src/main/kotlin/codes/som/hibiscus/events/NetworkEvents.kt new file mode 100644 index 0000000..b547a59 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/events/NetworkEvents.kt @@ -0,0 +1,15 @@ +package codes.som.hibiscus.events + +import codes.som.hibiscus.api.event.Cancellable +import codes.som.hibiscus.api.event.Event +import net.minecraft.network.Packet + +data class SendPacketEvent(var packet: Packet<*>) : Cancellable(), Event +class NetworkMovingEvent( + var x: Double, + var y: Double, + var z: Double, + var yaw: Float, + var pitch: Float, + var onGround: Boolean +) : Cancellable(), Event diff --git a/src/main/kotlin/codes/som/hibiscus/events/PlayerTickEvent.kt b/src/main/kotlin/codes/som/hibiscus/events/PlayerEvents.kt similarity index 100% rename from src/main/kotlin/codes/som/hibiscus/events/PlayerTickEvent.kt rename to src/main/kotlin/codes/som/hibiscus/events/PlayerEvents.kt diff --git a/src/main/kotlin/codes/som/hibiscus/events/RenderEvents.kt b/src/main/kotlin/codes/som/hibiscus/events/RenderEvents.kt new file mode 100644 index 0000000..5e7c752 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/events/RenderEvents.kt @@ -0,0 +1,5 @@ +package codes.som.hibiscus.events + +import codes.som.hibiscus.api.event.Event + +class RenderOverlayEvent(val delta: Float) : Event diff --git a/src/main/kotlin/codes/som/hibiscus/features/FeatureList.kt b/src/main/kotlin/codes/som/hibiscus/features/FeatureList.kt new file mode 100644 index 0000000..e2855a6 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/features/FeatureList.kt @@ -0,0 +1,10 @@ +package codes.som.hibiscus.features + +import codes.som.hibiscus.api.feature.Feature +import codes.som.hibiscus.features.movement.Flight +import codes.som.hibiscus.features.player.NoFallDamage + +val ALL_FEATURES: Array<() -> Feature> = arrayOf( + ::NoFallDamage, + ::Flight, +) diff --git a/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt b/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt new file mode 100644 index 0000000..bb4da60 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt @@ -0,0 +1,7 @@ +package codes.som.hibiscus.features + +class FeaturesRegistry { + private val features = ALL_FEATURES.map { it() } + + fun getAllFeatures() = features.asSequence() +} diff --git a/src/main/kotlin/codes/som/hibiscus/features/movement/Flight.kt b/src/main/kotlin/codes/som/hibiscus/features/movement/Flight.kt new file mode 100644 index 0000000..e5986da --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/features/movement/Flight.kt @@ -0,0 +1,79 @@ +package codes.som.hibiscus.features.movement + +import codes.som.hibiscus.api.feature.Feature +import codes.som.hibiscus.api.feature.FeatureCategory +import codes.som.hibiscus.events.NetworkMovingEvent +import codes.som.hibiscus.events.PlayerTickEvent +import codes.som.hibiscus.events.SendPacketEvent +import codes.som.hibiscus.mc +import codes.som.hibiscus.mixins.MixinExtUpdatePlayerAbilitiesC2SPacket +import codes.som.hibiscus.player +import codes.som.hibiscus.util.ext.requireExtension +import codes.som.hibiscus.world +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket +import net.minecraft.network.packet.c2s.play.UpdatePlayerAbilitiesC2SPacket +import net.minecraft.util.shape.VoxelShape + +class Flight : Feature("Flight", FeatureCategory.MOVEMENT) { + private var flyKickCounter = 0 + private var lockY = 0.0 + + init { + on { _: PlayerTickEvent -> + player.abilities.flying = true + } + + val interceptServerboundAbilityPackets by values.bool("Intercept Serverbound Ability Packets", true) + val vanillaKickBypass by values.bool("Vanilla Kick Bypass", false) + + on { event: SendPacketEvent -> + val (packet) = event + + if (!interceptServerboundAbilityPackets) + return@on + + if (packet is UpdatePlayerAbilitiesC2SPacket) { + requireExtension(packet) + packet.setFlying(player.abilities.allowFlying) + } + + if (packet is ClientCommandC2SPacket) { + if (packet.mode == ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY) { + event.cancel() + } + } + } + + on { event: NetworkMovingEvent -> + if (!vanillaKickBypass) + return@on + + flyKickCounter++ + + if (flyKickCounter >= 16) { + if (flyKickCounter == 16) + lockY = event.y - 0.03126 + + if (world.getBlockCollisions( + null, + player.boundingBox.offset(0.0, lockY - player.y, 0.0).expand(0.0625).stretch(0.0, -0.55, 0.0) + ).all(VoxelShape::isEmpty) + ) { + event.y = lockY + } + } + + if (flyKickCounter >= 24) + flyKickCounter = 0 + } + } + + override fun onEnable() { + if (mc.player != null) + lockY = player.y - 0.03126 + } + + override fun onDisable() { + player.abilities.flying = false + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/features/player/NoFallDamage.kt b/src/main/kotlin/codes/som/hibiscus/features/player/NoFallDamage.kt new file mode 100644 index 0000000..d21611c --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/features/player/NoFallDamage.kt @@ -0,0 +1,19 @@ +package codes.som.hibiscus.features.player + +import codes.som.hibiscus.api.feature.Feature +import codes.som.hibiscus.api.feature.FeatureCategory +import codes.som.hibiscus.events.SendPacketEvent +import codes.som.hibiscus.mixins.MixinExtPlayerMoveC2SPacket +import codes.som.hibiscus.util.ext.requireExtension +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket + +class NoFallDamage : Feature("No Fall Damage", FeatureCategory.PLAYER) { + init { + on { (packet): SendPacketEvent -> + if (packet is PlayerMoveC2SPacket) { + requireExtension(packet) + packet.setOnGround(true) + } + } + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/gui/ImGuiKt.kt b/src/main/kotlin/codes/som/hibiscus/gui/ImGuiKt.kt new file mode 100644 index 0000000..d35ee0c --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/gui/ImGuiKt.kt @@ -0,0 +1,37 @@ +package codes.som.hibiscus.gui + +import imgui.ImGui +import imgui.type.ImBoolean +import kotlin.reflect.KMutableProperty + +object ImGuiKt { + fun checkbox(label: String, prop: KMutableProperty) { + val imB = ImBoolean(prop.call()) + ImGui.checkbox(label, imB) + prop.setter.call(imB.get()) + } + + fun dragFloat(label: String, prop: KMutableProperty, speed: Float, min: Float, max: Float) { + val arr = floatArrayOf(prop.call()) + ImGui.dragFloat(label, arr, speed, min, max) + prop.setter.call(arr[0]) + } + + fun sliderFloat(label: String, prop: KMutableProperty, min: Float, max: Float) { + val arr = floatArrayOf(prop.call()) + ImGui.sliderFloat(label, arr, min, max) + prop.setter.call(arr[0]) + } + + fun dragInt(label: String, prop: KMutableProperty, speed: Float, min: Float, max: Float) { + val arr = intArrayOf(prop.call()) + ImGui.dragInt(label, arr, speed, min, max) + prop.setter.call(arr[0]) + } + + fun sliderInt(label: String, prop: KMutableProperty, min: Int, max: Int) { + val arr = intArrayOf(prop.call()) + ImGui.sliderInt(label, arr, min, max) + prop.setter.call(arr[0]) + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/gui/ImGuiRenderer.kt b/src/main/kotlin/codes/som/hibiscus/gui/ImGuiRenderer.kt new file mode 100644 index 0000000..ec01458 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/gui/ImGuiRenderer.kt @@ -0,0 +1,47 @@ +package codes.som.hibiscus.gui + +import codes.som.hibiscus.mc +import imgui.ImGui +import imgui.flag.ImGuiConfigFlags +import imgui.gl3.ImGuiImplGl3 +import imgui.glfw.ImGuiImplGlfw +import org.lwjgl.glfw.GLFW + +object ImGuiRenderer { + private val imGuiGlfw = ImGuiImplGlfw() + private val imGuiGl3 = ImGuiImplGl3() + + fun setup() { + ImGui.createContext() + + with(ImGui.getIO()) { + iniFilename = null // We don't want to save .ini file + addConfigFlags(ImGuiConfigFlags.NavEnableKeyboard) // Enable Keyboard Controls + addConfigFlags(ImGuiConfigFlags.DockingEnable) // Enable Docking + addConfigFlags(ImGuiConfigFlags.ViewportsEnable) // Enable Multi-Viewport / Platform Windows + configViewportsNoTaskBarIcon = true + } + + applyHibiscusImGuiTheme() + + imGuiGlfw.init(mc.window.handle, true) + imGuiGl3.init() + } + + fun beginFrame(delta: Float) { + imGuiGlfw.newFrame() + ImGui.newFrame() + } + + fun finishFrame(delta: Float) { + ImGui.render() + imGuiGl3.renderDrawData(ImGui.getDrawData()) + + if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) { + val backupWindowPtr = GLFW.glfwGetCurrentContext() + ImGui.updatePlatformWindows() + ImGui.renderPlatformWindowsDefault() + GLFW.glfwMakeContextCurrent(backupWindowPtr) + } + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/gui/ImGuiScreen.kt b/src/main/kotlin/codes/som/hibiscus/gui/ImGuiScreen.kt index 8a41f51..ae60661 100644 --- a/src/main/kotlin/codes/som/hibiscus/gui/ImGuiScreen.kt +++ b/src/main/kotlin/codes/som/hibiscus/gui/ImGuiScreen.kt @@ -1,47 +1,14 @@ package codes.som.hibiscus.gui -import codes.som.hibiscus.mc -import imgui.ImGui -import imgui.flag.ImGuiConfigFlags -import imgui.gl3.ImGuiImplGl3 -import imgui.glfw.ImGuiImplGlfw import net.minecraft.client.gui.screen.Screen import net.minecraft.client.util.math.MatrixStack import net.minecraft.text.Text -import org.lwjgl.glfw.GLFW - - -object ImGuiScreen : Screen(Text.of("hacker_menu")) { - private val imGuiGlfw = ImGuiImplGlfw() - private val imGuiGl3 = ImGuiImplGl3() - - init { - ImGui.createContext() - applyHibiscusImGuiTheme() - - imGuiGlfw.init(mc.window.handle, true) - imGuiGl3.init() - } +object ImGuiScreen : Screen(Text.of("hacker menu")) { override fun render(matrices: MatrixStack?, mouseX: Int, mouseY: Int, delta: Float) { super.render(matrices, mouseX, mouseY, delta) - imGuiGlfw.newFrame() - ImGui.newFrame() - - ImGui.begin("hello") - ImGui.text("you just got hacked by didi @ digitalgangster") - ImGui.end() - - ImGui.render() - imGuiGl3.renderDrawData(ImGui.getDrawData()) - - if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) { - val backupWindowPtr = GLFW.glfwGetCurrentContext() - ImGui.updatePlatformWindows() - ImGui.renderPlatformWindowsDefault() - GLFW.glfwMakeContextCurrent(backupWindowPtr) - } + ModuleControlsUI.render(delta) } override fun shouldPause() = false diff --git a/src/main/kotlin/codes/som/hibiscus/gui/ModuleControlsUI.kt b/src/main/kotlin/codes/som/hibiscus/gui/ModuleControlsUI.kt new file mode 100644 index 0000000..aab5a9c --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/gui/ModuleControlsUI.kt @@ -0,0 +1,58 @@ +package codes.som.hibiscus.gui + +import codes.som.hibiscus.HibiscusMod +import codes.som.hibiscus.api.feature.Feature +import codes.som.hibiscus.api.feature.FeatureCategory +import imgui.ImGui +import imgui.flag.ImGuiCond.FirstUseEver +import imgui.flag.ImGuiWindowFlags +import imgui.flag.ImGuiWindowFlags.AlwaysVerticalScrollbar + +object ModuleControlsUI { + private val moduleValueWindows = mutableMapOf() + + private fun categoryPanel(category: FeatureCategory, initialX: Float, initialY: Float) { + ImGui.setNextWindowPos(initialX, initialY, FirstUseEver) + ImGui.setNextWindowCollapsed(true, FirstUseEver) + + ImGui.begin(category.humanName, AlwaysVerticalScrollbar) + + for (feature in HibiscusMod.features.getAllFeatures().filter { it.category == category }) { + featureControls(feature) + } + + ImGui.end() + } + + private fun featureControls(feature: Feature) { + ImGuiKt.checkbox(feature.name, feature::enabled) + + if (feature.values.exist()) { + val showValueWindow = moduleValueWindows.getOrPut(feature) { booleanArrayOf(false) } + + ImGui.sameLine(ImGui.getWindowContentRegionMaxX() - ImGui.getWindowContentRegionMinX() - 10) + if (ImGui.radioButton("##${feature.name} values", showValueWindow[0])) { + showValueWindow[0] = !showValueWindow[0] + } + + if (showValueWindow[0]) { + if (ImGui.begin("${feature.name}##Feature Controls", ImGuiWindowFlags.NoCollapse)) { + for (value in feature.values) + value.drawUIControl() + } + ImGui.end() + } + } + } + + + fun render(delta: Float) { + for ((index, category) in FeatureCategory.values().withIndex()) { + categoryPanel( + category, + ImGui.getMainViewport().posX + 10f, + ImGui.getMainViewport().posY + 10f + index * 20f + ) + } + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/util/ext/RequireExtension.kt b/src/main/kotlin/codes/som/hibiscus/util/ext/RequireExtension.kt new file mode 100644 index 0000000..dce299a --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/util/ext/RequireExtension.kt @@ -0,0 +1,14 @@ +package codes.som.hibiscus.util.ext + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +inline fun requireExtension(obj: Any) { + contract { + returns() implies (obj is T) + } + + if (obj !is T) + error("Missing mixin extension ${T::class.java.name} for ${obj.javaClass.name}") +} diff --git a/src/main/kotlin/codes/som/hibiscus/util/input/Keys.kt b/src/main/kotlin/codes/som/hibiscus/util/input/Keys.kt new file mode 100644 index 0000000..b5fb704 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/util/input/Keys.kt @@ -0,0 +1,155 @@ +package codes.som.hibiscus.util.input + + +import codes.som.hibiscus.mc +import com.google.common.collect.BiMap +import com.google.common.collect.ImmutableBiMap +import com.google.common.collect.ImmutableSortedSet +import net.minecraft.client.util.InputUtil +import org.lwjgl.glfw.GLFW + +object Keys { + val KEY_MAP: BiMap = ImmutableBiMap.builder() + .put("SPACE", GLFW.GLFW_KEY_SPACE) + .put("APOSTROPHE", GLFW.GLFW_KEY_APOSTROPHE) + .put("COMMA", GLFW.GLFW_KEY_COMMA) + .put("MINUS", GLFW.GLFW_KEY_MINUS) + .put("PERIOD", GLFW.GLFW_KEY_PERIOD) + .put("SLASH", GLFW.GLFW_KEY_SLASH) + .put("0", GLFW.GLFW_KEY_0) + .put("1", GLFW.GLFW_KEY_1) + .put("2", GLFW.GLFW_KEY_2) + .put("3", GLFW.GLFW_KEY_3) + .put("4", GLFW.GLFW_KEY_4) + .put("5", GLFW.GLFW_KEY_5) + .put("6", GLFW.GLFW_KEY_6) + .put("7", GLFW.GLFW_KEY_7) + .put("8", GLFW.GLFW_KEY_8) + .put("9", GLFW.GLFW_KEY_9) + .put("SEMICOLON", GLFW.GLFW_KEY_SEMICOLON) + .put("EQUAL", GLFW.GLFW_KEY_EQUAL) + .put("A", GLFW.GLFW_KEY_A) + .put("B", GLFW.GLFW_KEY_B) + .put("C", GLFW.GLFW_KEY_C) + .put("D", GLFW.GLFW_KEY_D) + .put("E", GLFW.GLFW_KEY_E) + .put("F", GLFW.GLFW_KEY_F) + .put("G", GLFW.GLFW_KEY_G) + .put("H", GLFW.GLFW_KEY_H) + .put("I", GLFW.GLFW_KEY_I) + .put("J", GLFW.GLFW_KEY_J) + .put("K", GLFW.GLFW_KEY_K) + .put("L", GLFW.GLFW_KEY_L) + .put("M", GLFW.GLFW_KEY_M) + .put("N", GLFW.GLFW_KEY_N) + .put("O", GLFW.GLFW_KEY_O) + .put("P", GLFW.GLFW_KEY_P) + .put("Q", GLFW.GLFW_KEY_Q) + .put("R", GLFW.GLFW_KEY_R) + .put("S", GLFW.GLFW_KEY_S) + .put("T", GLFW.GLFW_KEY_T) + .put("U", GLFW.GLFW_KEY_U) + .put("V", GLFW.GLFW_KEY_V) + .put("W", GLFW.GLFW_KEY_W) + .put("X", GLFW.GLFW_KEY_X) + .put("Y", GLFW.GLFW_KEY_Y) + .put("Z", GLFW.GLFW_KEY_Z) + .put("LEFT_BRACKET", GLFW.GLFW_KEY_LEFT_BRACKET) + .put("BACKSLASH", GLFW.GLFW_KEY_BACKSLASH) + .put("RIGHT_BRACKET", GLFW.GLFW_KEY_RIGHT_BRACKET) + .put("GRAVE_ACCENT", GLFW.GLFW_KEY_GRAVE_ACCENT) + .put("WORLD_1", GLFW.GLFW_KEY_WORLD_1) + .put("WORLD_2", GLFW.GLFW_KEY_WORLD_2) + .put("ESCAPE", GLFW.GLFW_KEY_ESCAPE) + .put("ENTER", GLFW.GLFW_KEY_ENTER) + .put("TAB", GLFW.GLFW_KEY_TAB) + .put("BACKSPACE", GLFW.GLFW_KEY_BACKSPACE) + .put("INSERT", GLFW.GLFW_KEY_INSERT) + .put("DELETE", GLFW.GLFW_KEY_DELETE) + .put("RIGHT", GLFW.GLFW_KEY_RIGHT) + .put("LEFT", GLFW.GLFW_KEY_LEFT) + .put("DOWN", GLFW.GLFW_KEY_DOWN) + .put("UP", GLFW.GLFW_KEY_UP) + .put("PAGE_UP", GLFW.GLFW_KEY_PAGE_UP) + .put("PAGE_DOWN", GLFW.GLFW_KEY_PAGE_DOWN) + .put("HOME", GLFW.GLFW_KEY_HOME) + .put("END", GLFW.GLFW_KEY_END) + .put("CAPS_LOCK", GLFW.GLFW_KEY_CAPS_LOCK) + .put("SCROLL_LOCK", GLFW.GLFW_KEY_SCROLL_LOCK) + .put("NUM_LOCK", GLFW.GLFW_KEY_NUM_LOCK) + .put("PRINT_SCREEN", GLFW.GLFW_KEY_PRINT_SCREEN) + .put("PAUSE", GLFW.GLFW_KEY_PAUSE) + .put("F1", GLFW.GLFW_KEY_F1) + .put("F2", GLFW.GLFW_KEY_F2) + .put("F3", GLFW.GLFW_KEY_F3) + .put("F4", GLFW.GLFW_KEY_F4) + .put("F5", GLFW.GLFW_KEY_F5) + .put("F6", GLFW.GLFW_KEY_F6) + .put("F7", GLFW.GLFW_KEY_F7) + .put("F8", GLFW.GLFW_KEY_F8) + .put("F9", GLFW.GLFW_KEY_F9) + .put("F10", GLFW.GLFW_KEY_F10) + .put("F11", GLFW.GLFW_KEY_F11) + .put("F12", GLFW.GLFW_KEY_F12) + .put("F13", GLFW.GLFW_KEY_F13) + .put("F14", GLFW.GLFW_KEY_F14) + .put("F15", GLFW.GLFW_KEY_F15) + .put("F16", GLFW.GLFW_KEY_F16) + .put("F17", GLFW.GLFW_KEY_F17) + .put("F18", GLFW.GLFW_KEY_F18) + .put("F19", GLFW.GLFW_KEY_F19) + .put("F20", GLFW.GLFW_KEY_F20) + .put("F21", GLFW.GLFW_KEY_F21) + .put("F22", GLFW.GLFW_KEY_F22) + .put("F23", GLFW.GLFW_KEY_F23) + .put("F24", GLFW.GLFW_KEY_F24) + .put("F25", GLFW.GLFW_KEY_F25) + .put("KP_0", GLFW.GLFW_KEY_KP_0) + .put("KP_1", GLFW.GLFW_KEY_KP_1) + .put("KP_2", GLFW.GLFW_KEY_KP_2) + .put("KP_3", GLFW.GLFW_KEY_KP_3) + .put("KP_4", GLFW.GLFW_KEY_KP_4) + .put("KP_5", GLFW.GLFW_KEY_KP_5) + .put("KP_6", GLFW.GLFW_KEY_KP_6) + .put("KP_7", GLFW.GLFW_KEY_KP_7) + .put("KP_8", GLFW.GLFW_KEY_KP_8) + .put("KP_9", GLFW.GLFW_KEY_KP_9) + .put("KP_DECIMAL", GLFW.GLFW_KEY_KP_DECIMAL) + .put("KP_DIVIDE", GLFW.GLFW_KEY_KP_DIVIDE) + .put("KP_MULTIPLY", GLFW.GLFW_KEY_KP_MULTIPLY) + .put("KP_SUBTRACT", GLFW.GLFW_KEY_KP_SUBTRACT) + .put("KP_ADD", GLFW.GLFW_KEY_KP_ADD) + .put("KP_ENTER", GLFW.GLFW_KEY_KP_ENTER) + .put("KP_EQUAL", GLFW.GLFW_KEY_KP_EQUAL) + .put("LEFT_SHIFT", GLFW.GLFW_KEY_LEFT_SHIFT) + .put("LEFT_CONTROL", GLFW.GLFW_KEY_LEFT_CONTROL) + .put("LEFT_ALT", GLFW.GLFW_KEY_LEFT_ALT) + .put("LEFT_SUPER", GLFW.GLFW_KEY_LEFT_SUPER) + .put("RIGHT_SHIFT", GLFW.GLFW_KEY_RIGHT_SHIFT) + .put("RIGHT_CONTROL", GLFW.GLFW_KEY_RIGHT_CONTROL) + .put("RIGHT_ALT", GLFW.GLFW_KEY_RIGHT_ALT) + .put("RIGHT_SUPER", GLFW.GLFW_KEY_RIGHT_SUPER) + .put("MENU", GLFW.GLFW_KEY_MENU) + .put("NONE", GLFW.GLFW_KEY_UNKNOWN) + .build() + + val KEY_PAD: Set = ImmutableSortedSet.of( + GLFW.GLFW_KEY_KP_0, + GLFW.GLFW_KEY_KP_1, + GLFW.GLFW_KEY_KP_2, + GLFW.GLFW_KEY_KP_3, + GLFW.GLFW_KEY_KP_4, + GLFW.GLFW_KEY_KP_5, + GLFW.GLFW_KEY_KP_6, + GLFW.GLFW_KEY_KP_7, + GLFW.GLFW_KEY_KP_8, + GLFW.GLFW_KEY_KP_9 + ) + + fun pressed(key: Int): Boolean { + if (key == GLFW.GLFW_KEY_UNKNOWN) + return false + + return InputUtil.isKeyPressed(mc.window.handle, key) + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/util/netmoving/NetworkMovingEvent.kt b/src/main/kotlin/codes/som/hibiscus/util/netmoving/NetworkMovingEvent.kt new file mode 100644 index 0000000..ee3ae3c --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/util/netmoving/NetworkMovingEvent.kt @@ -0,0 +1,64 @@ +package codes.som.hibiscus.util.netmoving + +import codes.som.hibiscus.HibiscusMod +import codes.som.hibiscus.api.event.TypedListener +import codes.som.hibiscus.events.NetworkMovingEvent +import codes.som.hibiscus.events.SendPacketEvent +import codes.som.hibiscus.mc +import codes.som.hibiscus.mixins.MixinExtClientPlayerEntity +import codes.som.hibiscus.util.ext.requireExtension +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket + +class NetworkMovingDispatcher : TypedListener(SendPacketEvent::class.java) { + override fun on(event: SendPacketEvent) { + val packet = event.packet + if (packet is PlayerMoveC2SPacket) { + val player = mc.player!! + requireExtension(player) + + val movingEvent = NetworkMovingEvent( + packet.getX(player.x), packet.getY(player.y), packet.getZ(player.z), + packet.getYaw(player.yaw), packet.getPitch(player.pitch), packet.isOnGround + ) + + HibiscusMod.bus.fire(movingEvent) + + if (movingEvent.cancelled) + event.cancel() + + val moving = + movingEvent.x != player.lastX || movingEvent.y != player.lastBaseY || movingEvent.z != player.lastZ + val rotating = movingEvent.yaw != player.lastYaw || movingEvent.pitch != player.lastPitch + + player.lastX = movingEvent.x + player.lastBaseY = movingEvent.y + player.lastZ = movingEvent.z + + player.lastYaw = movingEvent.yaw + player.lastPitch = movingEvent.pitch + + event.packet = when { + moving && rotating -> PlayerMoveC2SPacket.Full( + movingEvent.x, + movingEvent.y, + movingEvent.z, + movingEvent.yaw, + movingEvent.pitch, + movingEvent.onGround + ) + moving -> PlayerMoveC2SPacket.PositionAndOnGround( + movingEvent.x, + movingEvent.y, + movingEvent.z, + movingEvent.onGround + ) + rotating -> PlayerMoveC2SPacket.LookAndOnGround( + movingEvent.yaw, + movingEvent.pitch, + movingEvent.onGround + ) + else -> PlayerMoveC2SPacket.OnGroundOnly(movingEvent.onGround) + } + } + } +} diff --git a/src/main/resources/hibiscus.mixins.json b/src/main/resources/hibiscus.mixins.json index 489a715..6607a70 100644 --- a/src/main/resources/hibiscus.mixins.json +++ b/src/main/resources/hibiscus.mixins.json @@ -6,9 +6,12 @@ "defaultRequire": 1 }, "mixins": [ - ], - "client": [ "MixinClientPlayerEntity", - "MixinKeyboard" + "MixinClientPlayNetworkHandler", + "MixinExtClientPlayerEntity", + "MixinExtPlayerMoveC2SPacket", + "MixinExtUpdatePlayerAbilitiesC2SPacket", + "MixinKeyboard", + "MixinMinecraftClient" ] }