Add SQLite-based data storage system & account manager

You can access the account manager by pressing right-shift from the
title screen
main
Charlotte Som 2022-03-07 23:34:22 +00:00
parent a1cff649dd
commit f96a4fc83d
31 changed files with 387 additions and 82 deletions

View File

@ -19,7 +19,9 @@ version = modVersion
val mavenGroup: String by project val mavenGroup: String by project
group = mavenGroup group = mavenGroup
repositories {} repositories {
mavenCentral()
}
dependencies { dependencies {
val minecraftVersion: String by project val minecraftVersion: String by project
@ -52,7 +54,12 @@ dependencies {
implementation(files("vendor/libs/lwjgl-util.jar")) implementation(files("vendor/libs/lwjgl-util.jar"))
implementation(files("vendor/libs/minecraft_authenticator-2.0.1.jar")) implementation(files("vendor/libs/minecraft_authenticator-2.0.1.jar"))
runtimeOnly("org.joml:joml:1.10.2") implementation("org.jetbrains.exposed:exposed-core:0.37.3")
implementation("org.jetbrains.exposed:exposed-dao:0.37.3")
implementation("org.jetbrains.exposed:exposed-jdbc:0.37.3")
runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")
runtimeOnly("org.joml:joml:1.10.4")
runtimeOnly("org.anarres:jcpp:1.4.14") runtimeOnly("org.anarres:jcpp:1.4.14")
modImplementation(files("vendor/mods/baritone-unoptimized-fabric-1.8.2.jar")) modImplementation(files("vendor/mods/baritone-unoptimized-fabric-1.8.2.jar"))

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.ReceivePacketEvent; import codes.som.hibiscus.events.ReceivePacketEvent;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.Packet; import net.minecraft.network.Packet;
@ -15,7 +15,7 @@ public abstract class MixinClientConnection {
@Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true) @Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true)
private static <T extends PacketListener> void onHandlePacket(Packet<T> packet, PacketListener listener, CallbackInfo ci) { private static <T extends PacketListener> void onHandlePacket(Packet<T> packet, PacketListener listener, CallbackInfo ci) {
var event = new ReceivePacketEvent(packet); var event = new ReceivePacketEvent(packet);
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
if (event.isCancelled()) if (event.isCancelled())
ci.cancel(); ci.cancel();
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.SendPacketEvent; import codes.som.hibiscus.events.SendPacketEvent;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
@ -14,7 +14,7 @@ public abstract class MixinClientPlayNetworkHandler {
@Redirect(method = "sendPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;send(Lnet/minecraft/network/Packet;)V")) @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) { public void onSendPacket(ClientConnection clientConnection, Packet<?> packet) {
var event = new SendPacketEvent(packet); var event = new SendPacketEvent(packet);
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
if (!event.isCancelled()) { if (!event.isCancelled()) {
clientConnection.send(event.getPacket()); clientConnection.send(event.getPacket());
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.MovePlayerEvent; import codes.som.hibiscus.events.MovePlayerEvent;
import codes.som.hibiscus.events.PlayerPreTickEvent; import codes.som.hibiscus.events.PlayerPreTickEvent;
import codes.som.hibiscus.events.PlayerTickEvent; import codes.som.hibiscus.events.PlayerTickEvent;
@ -19,18 +19,18 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class MixinClientPlayerEntity { public abstract class MixinClientPlayerEntity {
@Inject(method = "tick", at = @At("HEAD")) @Inject(method = "tick", at = @At("HEAD"))
private void onPreTick(CallbackInfo ci) { private void onPreTick(CallbackInfo ci) {
HibiscusMod.bus().fire(PlayerPreTickEvent.INSTANCE); Hibiscus.bus().fire(PlayerPreTickEvent.INSTANCE);
} }
@Inject(method = "tick", at = @At("RETURN")) @Inject(method = "tick", at = @At("RETURN"))
private void onPostTick(CallbackInfo ci) { private void onPostTick(CallbackInfo ci) {
HibiscusMod.bus().fire(PlayerTickEvent.INSTANCE); Hibiscus.bus().fire(PlayerTickEvent.INSTANCE);
} }
@Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true) @Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
private void onChatMessage(String message, CallbackInfo ci) { private void onChatMessage(String message, CallbackInfo ci) {
var event = new SendChatEvent(message); var event = new SendChatEvent(message);
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
if (event.isCancelled()) if (event.isCancelled())
ci.cancel(); ci.cancel();
} }
@ -46,7 +46,7 @@ public abstract class MixinClientPlayerEntity {
@ModifyVariable(method = "move", at = @At(value = "HEAD", shift = At.Shift.AFTER), argsOnly = true) @ModifyVariable(method = "move", at = @At(value = "HEAD", shift = At.Shift.AFTER), argsOnly = true)
private Vec3d onMovePlayer(Vec3d movement) { private Vec3d onMovePlayer(Vec3d movement) {
var event = new MovePlayerEvent(movement.x, movement.y, movement.z, this.movementType); var event = new MovePlayerEvent(movement.x, movement.y, movement.z, this.movementType);
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
return new Vec3d(event.getX(), event.getY(), event.getZ()); return new Vec3d(event.getX(), event.getY(), event.getZ());
} }
} }

View File

@ -0,0 +1,14 @@
package codes.som.hibiscus.mixins;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.Session;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(MinecraftClient.class)
public interface MixinExtMinecraftClient {
@Accessor
@Mutable
void setSession(Session session);
}

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.Render3DEvent; import codes.som.hibiscus.events.Render3DEvent;
import codes.som.hibiscus.events.RenderHandEvent; import codes.som.hibiscus.events.RenderHandEvent;
import codes.som.hibiscus.util.graphics.MinecraftRenderPipelineProgress; import codes.som.hibiscus.util.graphics.MinecraftRenderPipelineProgress;
@ -44,7 +44,7 @@ public abstract class MixinGameRenderer {
matrices.push(); matrices.push();
RenderSystem.applyModelViewMatrix(); RenderSystem.applyModelViewMatrix();
HibiscusMod.bus().fire(new Render3DEvent(tickDelta, this.camera, matrices)); Hibiscus.bus().fire(new Render3DEvent(tickDelta, this.camera, matrices));
matrices.pop(); matrices.pop();
} }
@ -68,7 +68,7 @@ public abstract class MixinGameRenderer {
@Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true)
private void onRenderHand(MatrixStack matrices, Camera camera, float tickDelta, CallbackInfo ci) { private void onRenderHand(MatrixStack matrices, Camera camera, float tickDelta, CallbackInfo ci) {
var event = new RenderHandEvent(tickDelta); var event = new RenderHandEvent(tickDelta);
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
if (event.isCancelled()) if (event.isCancelled())
ci.cancel(); ci.cancel();
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.CharEvent; import codes.som.hibiscus.events.CharEvent;
import codes.som.hibiscus.events.KeyEvent; import codes.som.hibiscus.events.KeyEvent;
import net.minecraft.client.Keyboard; import net.minecraft.client.Keyboard;
@ -23,7 +23,7 @@ public abstract class MixinKeyboard {
if (window != this.client.getWindow().getHandle()) if (window != this.client.getWindow().getHandle())
return; // Just in case return; // Just in case
HibiscusMod.bus().fire(new KeyEvent(key, action)); Hibiscus.bus().fire(new KeyEvent(key, action));
} }
@Inject(method = "onChar", at = @At("HEAD")) @Inject(method = "onChar", at = @At("HEAD"))
@ -31,6 +31,6 @@ public abstract class MixinKeyboard {
if (window != this.client.getWindow().getHandle()) if (window != this.client.getWindow().getHandle())
return; return;
HibiscusMod.bus().fire(new CharEvent((char) character)); Hibiscus.bus().fire(new CharEvent((char) character));
} }
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.GetRenderViewEntityEvent; import codes.som.hibiscus.events.GetRenderViewEntityEvent;
import codes.som.hibiscus.events.PostRenderAllEvent; import codes.som.hibiscus.events.PostRenderAllEvent;
import codes.som.hibiscus.gui.ImGuiRenderer; import codes.som.hibiscus.gui.ImGuiRenderer;
@ -43,7 +43,7 @@ public abstract class MixinMinecraftClient {
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gl/Framebuffer;endWrite()V", shift = At.Shift.BEFORE)) @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) { private void onPostRenderEverything(boolean tick, CallbackInfo ci) {
float delta = this.paused ? this.pausedTickDelta : this.renderTickCounter.tickDelta; float delta = this.paused ? this.pausedTickDelta : this.renderTickCounter.tickDelta;
HibiscusMod.bus().fire(new PostRenderAllEvent(delta)); Hibiscus.bus().fire(new PostRenderAllEvent(delta));
ImGuiRenderer.INSTANCE.finishFrame(delta); ImGuiRenderer.INSTANCE.finishFrame(delta);
} }
@ -53,7 +53,7 @@ public abstract class MixinMinecraftClient {
if (view != null) { if (view != null) {
var event = new GetRenderViewEntityEvent(view); var event = new GetRenderViewEntityEvent(view);
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
cir.setReturnValue(event.getViewEntity()); cir.setReturnValue(event.getViewEntity());
} }
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.WorldCullingEvent; import codes.som.hibiscus.events.WorldCullingEvent;
import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -13,7 +13,7 @@ public abstract class MixinRenderSectionManager {
@Redirect(method = "initSearch", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;chunkCullingEnabled:Z")) @Redirect(method = "initSearch", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;chunkCullingEnabled:Z"))
public boolean cancelCulling(MinecraftClient client) { public boolean cancelCulling(MinecraftClient client) {
var event = new WorldCullingEvent(); var event = new WorldCullingEvent();
HibiscusMod.bus().fire(event); Hibiscus.bus().fire(event);
return client.chunkCullingEnabled && !event.isCancelled(); return client.chunkCullingEnabled && !event.isCancelled();
} }
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.mixins; package codes.som.hibiscus.mixins;
import codes.som.hibiscus.HibiscusMod; import codes.som.hibiscus.Hibiscus;
import codes.som.hibiscus.events.PostRenderEntitiesEvent; import codes.som.hibiscus.events.PostRenderEntitiesEvent;
import codes.som.hibiscus.events.PostRenderWorldEvent; import codes.som.hibiscus.events.PostRenderWorldEvent;
import codes.som.hibiscus.events.PreRenderEntitiesEvent; import codes.som.hibiscus.events.PreRenderEntitiesEvent;
@ -21,12 +21,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class MixinWorldRenderer { public abstract class MixinWorldRenderer {
@Inject(method = "render", at = @At("HEAD")) @Inject(method = "render", at = @At("HEAD"))
private void onPreRenderWorld(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { private void onPreRenderWorld(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
HibiscusMod.bus().fire(new PreRenderWorldEvent(tickDelta, camera, matrices)); Hibiscus.bus().fire(new PreRenderWorldEvent(tickDelta, camera, matrices));
} }
@Inject(method = "render", at = @At("HEAD")) @Inject(method = "render", at = @At("HEAD"))
private void onPostRenderWorld(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { private void onPostRenderWorld(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
HibiscusMod.bus().fire(new PostRenderWorldEvent(tickDelta, camera, matrices)); Hibiscus.bus().fire(new PostRenderWorldEvent(tickDelta, camera, matrices));
} }
/* Obsoleted by Sodium-compatible MixinRenderSectionManager /* Obsoleted by Sodium-compatible MixinRenderSectionManager
@ -40,12 +40,12 @@ public abstract class MixinWorldRenderer {
@Inject(method = "render", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=entities")) @Inject(method = "render", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=entities"))
private void startRenderEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { private void startRenderEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
MinecraftRenderPipelineProgress.INSTANCE.setRenderingEntities(true); MinecraftRenderPipelineProgress.INSTANCE.setRenderingEntities(true);
HibiscusMod.bus().fire(new PreRenderEntitiesEvent(tickDelta)); Hibiscus.bus().fire(new PreRenderEntitiesEvent(tickDelta));
} }
@Inject(method = "render", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=blockentities")) @Inject(method = "render", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=blockentities"))
private void startRenderBlockEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { private void startRenderBlockEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
MinecraftRenderPipelineProgress.INSTANCE.setRenderingEntities(false); MinecraftRenderPipelineProgress.INSTANCE.setRenderingEntities(false);
HibiscusMod.bus().fire(new PostRenderEntitiesEvent(tickDelta)); Hibiscus.bus().fire(new PostRenderEntitiesEvent(tickDelta));
} }
} }

View File

@ -4,22 +4,25 @@ import codes.som.hibiscus.api.event.EventBus
import codes.som.hibiscus.api.event.EventPhase import codes.som.hibiscus.api.event.EventPhase
import codes.som.hibiscus.api.keybinds.KeybindRegistry import codes.som.hibiscus.api.keybinds.KeybindRegistry
import codes.som.hibiscus.commands.CommandRegistry import codes.som.hibiscus.commands.CommandRegistry
import codes.som.hibiscus.data.DataManager
import codes.som.hibiscus.events.KeyEvent import codes.som.hibiscus.events.KeyEvent
import codes.som.hibiscus.features.FeaturesRegistry import codes.som.hibiscus.features.FeaturesRegistry
import codes.som.hibiscus.features.combat.Criticals import codes.som.hibiscus.features.combat.Criticals
import codes.som.hibiscus.features.exploits.AntiGhost import codes.som.hibiscus.features.exploits.AntiGhost
import codes.som.hibiscus.features.player.NoFallDamage import codes.som.hibiscus.features.player.NoFallDamage
import codes.som.hibiscus.features.player.NoSprintingPacket import codes.som.hibiscus.features.player.NoSprintingPacket
import codes.som.hibiscus.gui.ImGuiScreen import codes.som.hibiscus.gui.screens.AccountManagerUIScreen
import codes.som.hibiscus.gui.screens.InGameClientUIScreen
import codes.som.hibiscus.util.command.ChatCommandListener import codes.som.hibiscus.util.command.ChatCommandListener
import codes.som.hibiscus.util.input.KeybindDispatcher import codes.som.hibiscus.util.input.KeybindDispatcher
import codes.som.hibiscus.util.netmoving.NetworkMovingDispatcher import codes.som.hibiscus.util.netmoving.NetworkMovingDispatcher
import net.fabricmc.api.ModInitializer import net.fabricmc.api.ModInitializer
import net.minecraft.client.gui.screen.TitleScreen
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
import org.lwjgl.glfw.GLFW.* import org.lwjgl.glfw.GLFW.*
@Suppress("UNUSED") @Suppress("UNUSED")
object HibiscusMod : ModInitializer { object Hibiscus : ModInitializer {
private const val MOD_ID = "hibiscus_client" private const val MOD_ID = "hibiscus_client"
@JvmStatic @JvmStatic
@ -29,8 +32,11 @@ object HibiscusMod : ModInitializer {
val features = FeaturesRegistry() val features = FeaturesRegistry()
val commands = CommandRegistry() val commands = CommandRegistry()
val keybinds = KeybindRegistry() val keybinds = KeybindRegistry()
val data = DataManager()
override fun onInitialize() { override fun onInitialize() {
data.runMigrations()
for (feature in features.getAllFeatures()) { for (feature in features.getAllFeatures()) {
commands.register(feature.createFeatureCommand()) commands.register(feature.createFeatureCommand())
} }
@ -39,10 +45,10 @@ object HibiscusMod : ModInitializer {
if (event.key != GLFW_KEY_RIGHT_SHIFT || event.action != GLFW.GLFW_PRESS) if (event.key != GLFW_KEY_RIGHT_SHIFT || event.action != GLFW.GLFW_PRESS)
return@register return@register
if (mc.currentScreen != null) when (mc.currentScreen) {
return@register null -> mc.setScreen(InGameClientUIScreen)
is TitleScreen -> mc.setScreen(AccountManagerUIScreen)
mc.setScreen(ImGuiScreen) }
} }
bus.register(NetworkMovingDispatcher(), EventPhase.AFTER) bus.register(NetworkMovingDispatcher(), EventPhase.AFTER)
@ -50,12 +56,9 @@ object HibiscusMod : ModInitializer {
bus.register(KeybindDispatcher()) bus.register(KeybindDispatcher())
defaultConfig() defaultConfig()
// TODO: Load files
} }
fun shutdown() { fun shutdown() {
// TODO: Save files
for (system in sequenceOf(bus, features, commands, keybinds)) { for (system in sequenceOf(bus, features, commands, keybinds)) {
system.reset() system.reset()
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.api.feature package codes.som.hibiscus.api.feature
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.command.Command import codes.som.hibiscus.api.command.Command
import codes.som.hibiscus.api.event.* import codes.som.hibiscus.api.event.*
import codes.som.hibiscus.api.feature.values.ValueRegistry import codes.som.hibiscus.api.feature.values.ValueRegistry
@ -23,9 +23,9 @@ abstract class Feature(val name: String, val category: FeatureCategory) {
field = value field = value
if (value) { if (value) {
onEnable() onEnable()
listeners.forEach { HibiscusMod.bus.registerTyped(it) } listeners.forEach { Hibiscus.bus.registerTyped(it) }
} else { } else {
listeners.forEach { HibiscusMod.bus.unregisterTyped(it) } listeners.forEach { Hibiscus.bus.unregisterTyped(it) }
onDisable() onDisable()
} }
} }

View File

@ -1,7 +1,7 @@
package codes.som.hibiscus.api.feature package codes.som.hibiscus.api.feature
import codes.som.hibiscus.HibiscusLog import codes.som.hibiscus.HibiscusLog
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.command.Command import codes.som.hibiscus.api.command.Command
import codes.som.hibiscus.api.command.CommandContext import codes.som.hibiscus.api.command.CommandContext
import java.util.* import java.util.*
@ -11,7 +11,7 @@ class FeatureCommand(feature: Feature) : Command(feature.name.replace(" ", "").l
branch { branch {
feature.enabled = !feature.enabled feature.enabled = !feature.enabled
if (HibiscusMod.commands.context == CommandContext.MANUAL) { if (Hibiscus.commands.context == CommandContext.MANUAL) {
val state = if (feature.enabled) "enabled" else "disabled" val state = if (feature.enabled) "enabled" else "disabled"
HibiscusLog.info("${feature.name} is now $state.") HibiscusLog.info("${feature.name} is now $state.")
} }

View File

@ -1,13 +1,13 @@
package codes.som.hibiscus.commands package codes.som.hibiscus.commands
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.command.Command import codes.som.hibiscus.api.command.Command
class Reload : Command("reload") { class Reload : Command("reload") {
init { init {
branch { branch {
HibiscusMod.shutdown() Hibiscus.shutdown()
HibiscusMod.onInitialize() Hibiscus.onInitialize()
} }
} }
} }

View File

@ -0,0 +1,20 @@
package codes.som.hibiscus.data
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
object MinecraftAccounts : IntIdTable("mc_accounts") {
val name = varchar("name", 64)
val lastKnownDisplayName = varchar("last_display_name", 32).nullable()
val loginData = text("login_data", eagerLoading = true)
}
class MinecraftAccount(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<MinecraftAccount>(MinecraftAccounts)
var name by MinecraftAccounts.name
var lastKnownDisplayName by MinecraftAccounts.lastKnownDisplayName
var loginData by MinecraftAccounts.loginData
}

View File

@ -0,0 +1,55 @@
package codes.som.hibiscus.data
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.transaction
import java.nio.file.Files
import java.nio.file.Paths
import java.sql.Connection
import java.sql.SQLException
class DataManager {
private val db: Database = Database.connect("jdbc:sqlite:${getDatabaseLocation()}").also {
TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
}
fun runMigrations() {
val latestId = try {
txn {
HibiscusDataMigrations.selectAll().orderBy(
HibiscusDataMigrations.id,
SortOrder.DESC
).limit(1).lastOrNull()?.get(HibiscusDataMigrations.id)?.value
}
} catch (e: SQLException) {
null
} ?: -1
txn {
for ((idx, migration) in HIBISCUS_MIGRATIONS().withIndex()) {
if (idx <= latestId)
continue
migration(this)
HibiscusDataMigrations.insert { it[id] = idx }
}
}
}
private fun getDatabaseLocation(): String {
val osName = System.getProperty("os.name")
val databasePath = when {
osName.contains("Windows") -> {
Paths.get(System.getenv("APPDATA"), "hibiscus-client", "hibiscus-client.db")
}
else -> {
Paths.get(System.getProperty("user.home"), ".config", "hibiscus-client", "hibiscus-client.db")
}
}
Files.createDirectories(databasePath.parent)
return databasePath.toString()
}
fun <T> txn(stmnt: Transaction.() -> T) = transaction(db, stmnt)
}

View File

@ -0,0 +1,13 @@
package codes.som.hibiscus.data
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.Transaction
object HibiscusDataMigrations : IntIdTable("_hibiscus_migrations")
@Suppress("FunctionName")
fun HIBISCUS_MIGRATIONS(): Sequence<Transaction.() -> Unit> = sequenceOf(
{ SchemaUtils.create(HibiscusDataMigrations) },
{ SchemaUtils.create(MinecraftAccounts) }
)

View File

@ -15,7 +15,8 @@ import codes.som.hibiscus.features.visual.Fullbright
import codes.som.hibiscus.features.visual.Xray import codes.som.hibiscus.features.visual.Xray
import codes.som.hibiscus.util.Resettable import codes.som.hibiscus.util.Resettable
fun allFeatureClasses(): Array<() -> Feature> = arrayOf( @Suppress("FunctionName")
fun FEATURE_CONSTRUCTORS(): Array<() -> Feature> = arrayOf(
::NoFallDamage, ::NoFallDamage,
::Flight, ::Flight,
::Overlay, ::Overlay,
@ -46,7 +47,7 @@ class FeaturesRegistry : Resettable {
getAllFeatures().first { it.javaClass == type } as T getAllFeatures().first { it.javaClass == type } as T
private fun registerFeatures() { private fun registerFeatures() {
features.addAll(allFeatureClasses().map { it() }) features.addAll(FEATURE_CONSTRUCTORS().map { it() })
} }
override fun reset() { override fun reset() {

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.features.overlay package codes.som.hibiscus.features.overlay
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.feature.Feature import codes.som.hibiscus.api.feature.Feature
import codes.som.hibiscus.api.feature.FeatureCategory import codes.som.hibiscus.api.feature.FeatureCategory
import codes.som.hibiscus.events.PostRenderAllEvent import codes.som.hibiscus.events.PostRenderAllEvent
@ -40,7 +40,7 @@ class Overlay : Feature("Overlay", FeatureCategory.OVERLAY) {
private fun drawEnabledFeatures() { private fun drawEnabledFeatures() {
val displayedFeatures = val displayedFeatures =
HibiscusMod.features.getAllFeatures() Hibiscus.features.getAllFeatures()
.filter { !it.hiddenInOverlay } .filter { !it.hiddenInOverlay }
.filter { it.enabled }.toList() .filter { it.enabled }.toList()

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.features.visual package codes.som.hibiscus.features.visual
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.feature.Feature import codes.som.hibiscus.api.feature.Feature
import codes.som.hibiscus.api.feature.FeatureCategory import codes.som.hibiscus.api.feature.FeatureCategory
import codes.som.hibiscus.events.* import codes.som.hibiscus.events.*
@ -131,7 +131,7 @@ class Freecam : Feature("Freecam", FeatureCategory.VISUAL) {
var lastMouseY = 0.0 var lastMouseY = 0.0
var mouseDeltaX = 0.0 var mouseDeltaX = 0.0
var mouseDeltaY = 0.0 var mouseDeltaY = 0.0
HibiscusMod.bus.register { _: PostRenderWorldEvent -> Hibiscus.bus.register { _: PostRenderWorldEvent ->
mouseDeltaX = mc.mouse.x - lastMouseX mouseDeltaX = mc.mouse.x - lastMouseX
mouseDeltaY = mc.mouse.y - lastMouseY mouseDeltaY = mc.mouse.y - lastMouseY
lastMouseX = mc.mouse.x lastMouseX = mc.mouse.x

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.gui package codes.som.hibiscus.gui
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.feature.Feature import codes.som.hibiscus.api.feature.Feature
import codes.som.hibiscus.api.feature.FeatureCategory import codes.som.hibiscus.api.feature.FeatureCategory
import codes.som.hibiscus.features.overlay.Overlay import codes.som.hibiscus.features.overlay.Overlay
@ -11,13 +11,13 @@ import imgui.flag.ImGuiWindowFlags
import imgui.flag.ImGuiWindowFlags.AlwaysVerticalScrollbar import imgui.flag.ImGuiWindowFlags.AlwaysVerticalScrollbar
import imgui.type.ImBoolean import imgui.type.ImBoolean
object ModuleControlsUI { object FeatureControlsUI {
private val moduleValueWindows = mutableMapOf<Feature, ImBoolean>() private val moduleValueWindows = mutableMapOf<Feature, ImBoolean>()
private fun drawCategoryPanel(category: FeatureCategory, ) { private fun drawCategoryPanel(category: FeatureCategory) {
ImGui.begin(category.humanName, AlwaysVerticalScrollbar) ImGui.begin(category.humanName, AlwaysVerticalScrollbar)
for (feature in HibiscusMod.features.getAllFeatures().filter { it.category == category }) { for (feature in Hibiscus.features.getAllFeatures().filter { it.category == category }) {
drawFeatureControls(feature) drawFeatureControls(feature)
} }
@ -63,34 +63,34 @@ object ModuleControlsUI {
} }
} }
} }
private fun drawOverlaySettings() { private fun drawOverlaySettings() {
val overlayFeature = HibiscusMod.features.getFeature<Overlay>() val overlayFeature = Hibiscus.features.getFeature<Overlay>()
if (ImGui.begin("${overlayFeature.name}##Feature Controls")) if (ImGui.begin("${overlayFeature.name}##Feature Controls"))
for (value in overlayFeature.values) for (value in overlayFeature.values)
value.drawUIControl() value.drawUIControl()
ImGui.end() ImGui.end()
} }
fun render(delta: Float) { fun render(delta: Float) {
var yOffset = 0f var yOffset = 0f
fun pushInitialPanelConfig() { fun pushInitialPanelConfig() {
val initialX = ImGui.getMainViewport().posX + 10f val initialX = ImGui.getMainViewport().posX + 10f
val initialY = ImGui.getMainViewport().posY + 10f + yOffset val initialY = ImGui.getMainViewport().posY + 10f + yOffset
ImGui.setNextWindowPos(initialX, initialY, Once) ImGui.setNextWindowPos(initialX, initialY, Once)
ImGui.setNextWindowCollapsed(true, Once) ImGui.setNextWindowCollapsed(true, Once)
ImGui.setNextWindowSize(300f, 0f, Once) ImGui.setNextWindowSize(300f, 0f, Once)
} }
for (category in FeatureCategory.values()) { for (category in FeatureCategory.values()) {
if (category == FeatureCategory.OVERLAY) if (category == FeatureCategory.OVERLAY)
continue continue
pushInitialPanelConfig() pushInitialPanelConfig()
drawCategoryPanel(category) drawCategoryPanel(category)
yOffset += 30f yOffset += 30f
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.gui package codes.som.hibiscus.gui
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import imgui.ImFontConfig import imgui.ImFontConfig
import imgui.ImGui import imgui.ImGui
import imgui.ImGuiStyle import imgui.ImGuiStyle
@ -83,7 +83,7 @@ fun applyHibiscusImGuiTheme() {
style.setColor(ImGuiCol.TabUnfocusedActive, colMed(1.0f)) style.setColor(ImGuiCol.TabUnfocusedActive, colMed(1.0f))
with(ImGui.getIO().fonts) { with(ImGui.getIO().fonts) {
val interTTF = HibiscusMod.javaClass.getResourceAsStream("/assets/inter/Inter-V.ttf") val interTTF = Hibiscus.javaClass.getResourceAsStream("/assets/inter/Inter-V.ttf")
?: error("Couldn't find Inter TTF in assets!") ?: error("Couldn't find Inter TTF in assets!")
addFontFromMemoryTTF(interTTF.readAllBytes(), 20f, ImFontConfig().apply { addFontFromMemoryTTF(interTTF.readAllBytes(), 20f, ImFontConfig().apply {
setName("Inter") setName("Inter")

View File

@ -0,0 +1,190 @@
package codes.som.hibiscus.gui.screens
import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.data.MinecraftAccount
import codes.som.hibiscus.mixins.MixinExtMinecraftClient
import imgui.ImGui
import imgui.flag.ImGuiInputTextFlags
import imgui.type.ImBoolean
import imgui.type.ImInt
import imgui.type.ImString
import net.hycrafthd.minecraft_authenticator.login.Authenticator
import net.hycrafthd.minecraft_authenticator.login.User
import net.hycrafthd.minecraft_authenticator.login.file.AuthenticationFile
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.util.Session
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
import java.io.ByteArrayOutputStream
import java.util.*
object AccountManagerUIScreen : Screen(Text.of("account management hacker menu")) {
private var accounts = emptyList<MinecraftAccount>()
private val createAccountPanelOpen = ImBoolean(false)
private var selectedAccountId = -1
init {
refreshAccounts()
}
private fun refreshAccounts() {
this.accounts = Hibiscus.data.txn {
MinecraftAccount.all().toList()
}
}
override fun render(matrices: MatrixStack?, mouseX: Int, mouseY: Int, delta: Float) {
renderBackground(matrices)
if (ImGui.begin("Accounts")) {
ImGui.text("Available accounts: ${accounts.size}")
ImGui.text("Logged in as: ${client!!.session.username}")
if (ImGui.button("Add Account")) {
createAccountPanelOpen.set(true)
}
val calculatedHeight = (accounts.size.coerceIn(4, 20) * 28f)
if (ImGui.beginListBox("Accounts", 0f, calculatedHeight)) {
for (account in accounts) {
if (ImGui.selectable(account.name, account.id.value == selectedAccountId)) {
selectedAccountId = account.id.value
}
}
ImGui.endListBox()
}
accounts.firstOrNull { it.id.value == selectedAccountId }?.let { account ->
ImGui.text("Selected account: ${account.name}")
ImGui.text("Last known username: ${account.lastKnownDisplayName}")
if (ImGui.button("Log In")) {
try {
val loginFile = AuthenticationFile.read(account.loginData.byteInputStream(Charsets.UTF_8))
val loginResult = Authenticator.of(loginFile).shouldAuthenticate().run()
if (loginResult.user.isPresent) {
val user = loginResult.user.get()
(client!! as MixinExtMinecraftClient).setSession(user.createSession())
val loginData = ByteArrayOutputStream()
.apply { loginResult.resultFile.write(this) }
.toString(Charsets.UTF_8)
Hibiscus.data.txn {
account.lastKnownDisplayName = user.name
account.loginData = loginData
refreshAccounts()
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
ImGui.sameLine()
if (ImGui.button("Remove")) {
// TODO: Some confirmation modal
Hibiscus.data.txn {
account.delete()
refreshAccounts()
}
}
}
}
ImGui.end()
drawCreateAccountPanel()
}
private val loginType = ImInt(1)
private val yggdrasilUsername = ImString(320)
private val yggdrasilPassword = ImString(256)
private val microsoftToken = ImString(256)
private fun drawCreateAccountPanel() {
if (createAccountPanelOpen.get()) {
if (ImGui.begin("Add Account", createAccountPanelOpen)) {
ImGui.pushItemWidth(ImGui.getContentRegionMaxX() - ImGui.getWindowContentRegionMinX())
ImGui.text("Login Type:")
ImGui.combo(
"Login Type",
loginType,
arrayOf("Yggdrasil", "Microsoft")
)
ImGui.separator()
when (loginType.get()) {
0 -> {
ImGui.text("Login Name (Username or Email):")
ImGui.inputText("##new-account-login-name", yggdrasilUsername)
ImGui.text("Password:")
ImGui.inputText("##new-account-login-password", yggdrasilPassword, ImGuiInputTextFlags.Password)
}
1 -> {
ImGui.text("You may want to visit the Microsoft login site.")
if (ImGui.button("Copy URL")) {
ImGui.setClipboardText(Authenticator.microsoftLogin().toString())
}
ImGui.text("Login Token:")
ImGui.inputText("##new-account-login-token", microsoftToken)
}
}
ImGui.popItemWidth()
ImGui.separator()
if (ImGui.button("Log In")) {
val authenticator = when (loginType.get()) {
0 -> Authenticator.ofYggdrasil("-", yggdrasilUsername.get(), yggdrasilPassword.get())
1 -> Authenticator.ofMicrosoft(microsoftToken.get())
else -> throw IllegalStateException()
}.shouldAuthenticate()
try {
val loginResult = authenticator.run()
if (loginResult.user.isPresent) {
val user = loginResult.user.get()
val loginData = ByteArrayOutputStream()
.apply { loginResult.resultFile.write(this) }
.toString(Charsets.UTF_8)
yggdrasilUsername.set("")
yggdrasilPassword.set("")
microsoftToken.set("")
Hibiscus.data.txn {
MinecraftAccount.new {
this.name = user.name
this.lastKnownDisplayName = user.name
this.loginData = loginData
}
refreshAccounts()
(client!! as MixinExtMinecraftClient).setSession(user.createSession())
}
}
} catch (e: Exception) {
e.printStackTrace()
// TODO: Display some error
}
}
}
ImGui.end()
}
}
private fun User.createSession() = Session(
name,
uuid,
accessToken,
Optional.empty(),
Optional.empty(),
Session.AccountType.byName(type)
)
}

View File

@ -1,14 +1,15 @@
package codes.som.hibiscus.gui package codes.som.hibiscus.gui.screens
import codes.som.hibiscus.gui.FeatureControlsUI
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.util.math.MatrixStack import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text import net.minecraft.text.Text
object ImGuiScreen : Screen(Text.of("hacker menu")) { object InGameClientUIScreen : Screen(Text.of("in game hacker menu")) {
override fun render(matrices: MatrixStack?, mouseX: Int, mouseY: Int, delta: Float) { override fun render(matrices: MatrixStack?, mouseX: Int, mouseY: Int, delta: Float) {
super.render(matrices, mouseX, mouseY, delta) super.render(matrices, mouseX, mouseY, delta)
ModuleControlsUI.render(delta) FeatureControlsUI.render(delta)
} }
override fun isPauseScreen() = false override fun isPauseScreen() = false

View File

@ -1,13 +1,13 @@
package codes.som.hibiscus.subsystems.fullbright package codes.som.hibiscus.subsystems.fullbright
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.features.visual.Fullbright import codes.som.hibiscus.features.visual.Fullbright
object FullbrightSystem { object FullbrightSystem {
@JvmStatic @JvmStatic
fun shouldRenderFullbright(): Boolean { fun shouldRenderFullbright(): Boolean {
try { try {
return HibiscusMod.features.getFeature<Fullbright>().enabled return Hibiscus.features.getFeature<Fullbright>().enabled
} catch (_: Exception) { } catch (_: Exception) {
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.subsystems.xray package codes.som.hibiscus.subsystems.xray
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.features.visual.Xray import codes.som.hibiscus.features.visual.Xray
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.FluidBlock import net.minecraft.block.FluidBlock
@ -11,7 +11,7 @@ object XraySystem {
@JvmStatic @JvmStatic
fun shouldRenderXray(): Boolean { fun shouldRenderXray(): Boolean {
try { try {
return HibiscusMod.features.getFeature<Xray>().enabled return Hibiscus.features.getFeature<Xray>().enabled
} catch (_: Exception) { } catch (_: Exception) {
} }

View File

@ -1,7 +1,7 @@
package codes.som.hibiscus.util.command package codes.som.hibiscus.util.command
import codes.som.hibiscus.HibiscusLog import codes.som.hibiscus.HibiscusLog
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.command.CommandContext import codes.som.hibiscus.api.command.CommandContext
import codes.som.hibiscus.api.command.exceptions.CommandExecutionException import codes.som.hibiscus.api.command.exceptions.CommandExecutionException
import codes.som.hibiscus.api.event.TypedListener import codes.som.hibiscus.api.event.TypedListener
@ -11,8 +11,8 @@ class ChatCommandListener : TypedListener<SendChatEvent>(SendChatEvent::class.ja
override fun on(event: SendChatEvent) { override fun on(event: SendChatEvent) {
if (event.message.startsWith(".")) { if (event.message.startsWith(".")) {
try { try {
HibiscusMod.commands.context = CommandContext.MANUAL Hibiscus.commands.context = CommandContext.MANUAL
HibiscusMod.commands.executeCommand(event.message.substring(1)) Hibiscus.commands.executeCommand(event.message.substring(1))
} catch (e: CommandExecutionException) { } catch (e: CommandExecutionException) {
// e.printStackTrace() // e.printStackTrace()
e.cause?.message?.let { HibiscusLog.error(it) } e.cause?.message?.let { HibiscusLog.error(it) }

View File

@ -1,7 +1,7 @@
package codes.som.hibiscus.util.input package codes.som.hibiscus.util.input
import codes.som.hibiscus.HibiscusLog import codes.som.hibiscus.HibiscusLog
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.command.CommandContext import codes.som.hibiscus.api.command.CommandContext
import codes.som.hibiscus.api.command.exceptions.CommandExecutionException import codes.som.hibiscus.api.command.exceptions.CommandExecutionException
import codes.som.hibiscus.api.event.TypedListener import codes.som.hibiscus.api.event.TypedListener
@ -12,10 +12,10 @@ import org.lwjgl.glfw.GLFW
class KeybindDispatcher : TypedListener<KeyEvent>(KeyEvent::class.java) { class KeybindDispatcher : TypedListener<KeyEvent>(KeyEvent::class.java) {
override fun on(event: KeyEvent) { override fun on(event: KeyEvent) {
if (mc.isWindowFocused && mc.currentScreen == null && event.action == GLFW.GLFW_PRESS) { if (mc.isWindowFocused && mc.currentScreen == null && event.action == GLFW.GLFW_PRESS) {
HibiscusMod.keybinds.getBinds(event.key).forEach { bind -> Hibiscus.keybinds.getBinds(event.key).forEach { bind ->
try { try {
HibiscusMod.commands.context = CommandContext.KEYBIND Hibiscus.commands.context = CommandContext.KEYBIND
HibiscusMod.commands.executeCommand(bind) Hibiscus.commands.executeCommand(bind)
} catch (e: CommandExecutionException) { } catch (e: CommandExecutionException) {
e.cause?.message?.let { HibiscusLog.error(it) } e.cause?.message?.let { HibiscusLog.error(it) }
} }

View File

@ -1,6 +1,6 @@
package codes.som.hibiscus.util.netmoving package codes.som.hibiscus.util.netmoving
import codes.som.hibiscus.HibiscusMod import codes.som.hibiscus.Hibiscus
import codes.som.hibiscus.api.event.TypedListener import codes.som.hibiscus.api.event.TypedListener
import codes.som.hibiscus.events.NetworkMovingEvent import codes.som.hibiscus.events.NetworkMovingEvent
import codes.som.hibiscus.events.SendPacketEvent import codes.som.hibiscus.events.SendPacketEvent
@ -21,7 +21,7 @@ class NetworkMovingDispatcher : TypedListener<SendPacketEvent>(SendPacketEvent::
packet.getYaw(player.yaw), packet.getPitch(player.pitch), packet.isOnGround packet.getYaw(player.yaw), packet.getPitch(player.pitch), packet.isOnGround
) )
HibiscusMod.bus.fire(movingEvent) Hibiscus.bus.fire(movingEvent)
if (movingEvent.cancelled) if (movingEvent.cancelled)
event.cancel() event.cancel()

View File

@ -17,7 +17,7 @@
"main": [ "main": [
{ {
"adapter": "kotlin", "adapter": "kotlin",
"value": "codes.som.hibiscus.HibiscusMod" "value": "codes.som.hibiscus.Hibiscus"
} }
] ]
}, },

View File

@ -11,6 +11,7 @@
"MixinClientPlayNetworkHandler", "MixinClientPlayNetworkHandler",
"MixinExtClientPlayerEntity", "MixinExtClientPlayerEntity",
"MixinExtEntity", "MixinExtEntity",
"MixinExtMinecraftClient",
"MixinExtPlayerInteractEntityC2SPacket", "MixinExtPlayerInteractEntityC2SPacket",
"MixinExtPlayerMoveC2SPacket", "MixinExtPlayerMoveC2SPacket",
"MixinExtUpdatePlayerAbilitiesC2SPacket", "MixinExtUpdatePlayerAbilitiesC2SPacket",