From 7571bd68f67e5813c5673b81f6a18788d2dea66f Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Thu, 6 Jun 2024 16:02:21 +0530 Subject: [PATCH] chore(release): elytra-lock v0.1.0+1.20.6 --- build.gradle | 4 +- gradle.properties | 10 ++-- gradle/libs.versions.toml | 23 ------- .../xyz/devcomp/elytralock/ElytraLock.java | 60 +++++++++++++++++++ .../elytralock/config/ConfigHandler.java | 37 ++++++++++++ .../elytralock/config/ConfigModel.java | 11 ++++ .../devcomp/elytralock/config/ConfigUtil.java | 9 +++ .../events/ClientTickEndHandler.java | 33 ++++++++++ .../elytralock/events/HudRenderHandler.java | 24 ++++++++ .../integrations/ModMenuIntegration.java | 18 ++++++ .../ClientPlayerInteractionManagerMixin.java | 38 ++++++++++++ .../elytralock/mixin/PlayerEntityMixin.java | 33 ++++++++++ .../elytralock/util/RunOnceOnToggle.java | 28 +++++++++ 13 files changed, 298 insertions(+), 30 deletions(-) delete mode 100644 gradle/libs.versions.toml create mode 100644 remappedSrc/xyz/devcomp/elytralock/ElytraLock.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/config/ConfigHandler.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/config/ConfigModel.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/config/ConfigUtil.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/events/ClientTickEndHandler.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/events/HudRenderHandler.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/integrations/ModMenuIntegration.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/mixin/ClientPlayerInteractionManagerMixin.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/mixin/PlayerEntityMixin.java create mode 100644 remappedSrc/xyz/devcomp/elytralock/util/RunOnceOnToggle.java diff --git a/build.gradle b/build.gradle index 6f98cd4..b3fa346 100644 --- a/build.gradle +++ b/build.gradle @@ -49,7 +49,7 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - modImplementation "dev.isxander.yacl:yet-another-config-lib-fabric:${project.yacl_version}" + modImplementation "dev.isxander:yet-another-config-lib:${project.yacl_version}" modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}" } @@ -57,7 +57,7 @@ processResources { inputs.property "version", project.version filesMatching("fabric.mod.json") { expand "version": project.version, - "java_version": ">=17", + "java_version": ">=21", "minecraft_version": "~${project.minecraft_version}", "loader_version": ">=${project.loader_version}" } diff --git a/gradle.properties b/gradle.properties index 50c2d30..cbc4971 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,8 +4,8 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.20.4 -yarn_mappings=1.20.4+build.3 +minecraft_version=1.20.6 +yarn_mappings=1.20.6+build.3 loader_version=0.15.11 # Mod Properties @@ -14,6 +14,6 @@ maven_group=xyz.devcomp archives_base_name=elytra-lock # Dependencies -fabric_version=0.97.0+1.20.4 -yacl_version=3.3.2+1.20.4 -modmenu_version=9.0.0 \ No newline at end of file +fabric_version=0.99.4+1.20.6 +yacl_version=3.4.4+1.20.6-fabric +modmenu_version=10.0.0-beta.1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml deleted file mode 100644 index 6f4b647..0000000 --- a/gradle/libs.versions.toml +++ /dev/null @@ -1,23 +0,0 @@ -[versions] -minecraft = "1.20.2" -quilt_mappings = "1.20.2+build.3" -quilt_loader = "0.26.0-beta.1" - -quilted_fabric_api = "8.0.0-alpha.6+0.91.6-1.20.2" - -mixin_extras = "0.2.0" -quilt_parsers = "0.2.1" - -[libraries] -minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } -quilt_mappings = { module = "org.quiltmc:quilt-mappings", version.ref = "quilt_mappings" } -quilt_loader = { module = "org.quiltmc:quilt-loader", version.ref = "quilt_loader" } - -quilted_fabric_api = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api", version.ref = "quilted_fabric_api" } -quilted_fabric_api_deprecated = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api-deprecated", version.ref = "quilted_fabric_api" } - -[bundles] -quilted_fabric_api = ["quilted_fabric_api", "quilted_fabric_api_deprecated"] - -[plugins] -quilt_loom = { id = "org.quiltmc.loom", version = "1.6.7" } \ No newline at end of file diff --git a/remappedSrc/xyz/devcomp/elytralock/ElytraLock.java b/remappedSrc/xyz/devcomp/elytralock/ElytraLock.java new file mode 100644 index 0000000..3be9cd0 --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/ElytraLock.java @@ -0,0 +1,60 @@ +package xyz.devcomp.elytralock; + +import xyz.devcomp.elytralock.config.ConfigHandler; +import xyz.devcomp.elytralock.config.ConfigUtil; +import xyz.devcomp.elytralock.events.ClientTickEndHandler; +import xyz.devcomp.elytralock.events.HudRenderHandler; + +import org.lwjgl.glfw.GLFW; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.fabricmc.loader.api.FabricLoader; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; + +public class ElytraLock implements ClientModInitializer { + public static final Logger LOGGER = LoggerFactory.getLogger("Elytra Lock"); + public static final FabricLoader LOADER = FabricLoader.getInstance(); + private static KeyBinding lockKeybind; + private static boolean locked = false; + public static MinecraftClient client; + + @Override + public void onInitializeClient() { + LOGGER.info("ElytraLock initializing!"); + + lockKeybind = KeyBindingHelper.registerKeyBinding( + new KeyBinding("key.elytralock.lock", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_J, "category.elytralock")); + LOGGER.info("Registered keybind for locking elytra"); + + client = MinecraftClient.getInstance(); + + if (ConfigUtil.isYaclLoaded()) { + LOGGER.info("YACL_v3 is loaded, loading elytra toggle"); + locked = new ConfigHandler().getInstance().toggle; + } else { + LOGGER.warn("YACL_v3 is not loaded, not persisting elytra toggle"); + } + + HudRenderCallback.EVENT.register(new HudRenderHandler()); + ClientTickEvents.END_CLIENT_TICK.register(new ClientTickEndHandler()); + + LOGGER.info("Registered HUD_RENDER & END_CLIENT_TICK events successfully!"); + } + + public static boolean isLocked() { + if (lockKeybind.wasPressed()) { + locked = !locked; + } + + return locked; + } +} \ No newline at end of file diff --git a/remappedSrc/xyz/devcomp/elytralock/config/ConfigHandler.java b/remappedSrc/xyz/devcomp/elytralock/config/ConfigHandler.java new file mode 100644 index 0000000..a504338 --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/config/ConfigHandler.java @@ -0,0 +1,37 @@ +package xyz.devcomp.elytralock.config; + +import xyz.devcomp.elytralock.ElytraLock; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.Identifier; + +import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; +import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; + +public class ConfigHandler { + private boolean isLoaded = false; + public static final ConfigClassHandler HANDLER = ConfigClassHandler.createBuilder(ConfigModel.class) + .id(new Identifier("elytralock", "config")) + .serializer(config -> GsonConfigSerializerBuilder.create(config) + .setPath(ElytraLock.LOADER.getConfigDir().resolve("elytra-lock.json")) + .setJson5(true) + .build()) + .build(); + + private void loadConfig() { + if (!this.isLoaded) { + ElytraLock.LOGGER.info("ElytraLock config not loaded, loading"); + this.isLoaded = HANDLER.load(); + } + } + + public Screen showGui(Screen parent) { + this.loadConfig(); + return HANDLER.generateGui().generateScreen(parent); + } + + public ConfigModel getInstance() { + this.loadConfig(); + return HANDLER.instance(); + } +} \ No newline at end of file diff --git a/remappedSrc/xyz/devcomp/elytralock/config/ConfigModel.java b/remappedSrc/xyz/devcomp/elytralock/config/ConfigModel.java new file mode 100644 index 0000000..b2640a1 --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/config/ConfigModel.java @@ -0,0 +1,11 @@ +package xyz.devcomp.elytralock.config; + +import dev.isxander.yacl3.config.v2.api.SerialEntry; +import dev.isxander.yacl3.config.v2.api.autogen.*; + +public class ConfigModel { + @SerialEntry(comment = "The status of the lock toggle") + @AutoGen(category = "elytralock") + @TickBox + public boolean toggle = false; +} \ No newline at end of file diff --git a/remappedSrc/xyz/devcomp/elytralock/config/ConfigUtil.java b/remappedSrc/xyz/devcomp/elytralock/config/ConfigUtil.java new file mode 100644 index 0000000..de42b2f --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/config/ConfigUtil.java @@ -0,0 +1,9 @@ +package xyz.devcomp.elytralock.config; + +import xyz.devcomp.elytralock.ElytraLock; + +public class ConfigUtil { + public static boolean isYaclLoaded() { + return ElytraLock.LOADER.isModLoaded("yet_another_config_lib_v3"); + } +} diff --git a/remappedSrc/xyz/devcomp/elytralock/events/ClientTickEndHandler.java b/remappedSrc/xyz/devcomp/elytralock/events/ClientTickEndHandler.java new file mode 100644 index 0000000..870b3ec --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/events/ClientTickEndHandler.java @@ -0,0 +1,33 @@ +package xyz.devcomp.elytralock.events; + +import java.util.function.Consumer; + +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents.EndTick; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import xyz.devcomp.elytralock.ElytraLock; +import xyz.devcomp.elytralock.util.RunOnceOnToggle; + +public class ClientTickEndHandler implements EndTick { + private static RunOnceOnToggle impl = new RunOnceOnToggle( + new Consumer() { + public void accept(MinecraftClient client) { + PlayerInventory inventory = client.player.getInventory(); + + // 0 -> boots + // 1 -> leggings + // 2 -> chestplate + // 3 -> helmet + ItemStack chestArmor = inventory.armor.get(2); + if (chestArmor.isOf(Items.ELYTRA)) { + ElytraLock.LOGGER.info("Detected player wearing elytra even though it's locked"); + } + } + }); + + public void onEndTick(MinecraftClient client) { + impl.run(client); + } +} diff --git a/remappedSrc/xyz/devcomp/elytralock/events/HudRenderHandler.java b/remappedSrc/xyz/devcomp/elytralock/events/HudRenderHandler.java new file mode 100644 index 0000000..ea1b94f --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/events/HudRenderHandler.java @@ -0,0 +1,24 @@ +package xyz.devcomp.elytralock.events; + +import xyz.devcomp.elytralock.ElytraLock; + +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.util.Window; +import net.minecraft.util.Identifier; + +public class HudRenderHandler implements HudRenderCallback { + public static final int WIDTH = 16; + public static final int HEIGHT = 16; + + public void onHudRender(DrawContext context, float delta) { + // FIXME: Perhaps don't check whether the elytra is locked on every frame + Identifier icon = new Identifier("elytra-lock", + "textures/gui/" + (ElytraLock.isLocked() ? "locked" : "unlocked") + ".png"); + + Window window = ElytraLock.client.getWindow(); + int width = window.getScaledWidth(), height = window.getScaledHeight(); + + context.drawTexture(icon, (width / 2) + 95, height - HEIGHT - 3, 0, 0, WIDTH, HEIGHT, WIDTH, HEIGHT); + } +} \ No newline at end of file diff --git a/remappedSrc/xyz/devcomp/elytralock/integrations/ModMenuIntegration.java b/remappedSrc/xyz/devcomp/elytralock/integrations/ModMenuIntegration.java new file mode 100644 index 0000000..12253a4 --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/integrations/ModMenuIntegration.java @@ -0,0 +1,18 @@ +package xyz.devcomp.elytralock.integrations; + +import xyz.devcomp.elytralock.config.ConfigHandler; +import xyz.devcomp.elytralock.config.ConfigUtil; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; + +public class ModMenuIntegration implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return (parent) -> { + if (!ConfigUtil.isYaclLoaded()) + return parent; + return new ConfigHandler().showGui(parent); + }; + } +} diff --git a/remappedSrc/xyz/devcomp/elytralock/mixin/ClientPlayerInteractionManagerMixin.java b/remappedSrc/xyz/devcomp/elytralock/mixin/ClientPlayerInteractionManagerMixin.java new file mode 100644 index 0000000..591b3b0 --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/mixin/ClientPlayerInteractionManagerMixin.java @@ -0,0 +1,38 @@ +package xyz.devcomp.elytralock.mixin; + +import xyz.devcomp.elytralock.ElytraLock; + +import org.apache.commons.lang3.mutable.MutableObject; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.llamalad7.mixinextras.sugar.Local; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; + +@Environment(EnvType.CLIENT) +@Mixin(ClientPlayerInteractionManager.class) +public class ClientPlayerInteractionManagerMixin { + @Inject(method = "interactItem(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;", at = @At(value = "INVOKE", target = "net/minecraft/client/network/ClientPlayerInteractionManager.sendSequencedPacket (Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/client/network/SequencedPacketCreator;)V"), cancellable = true) + private void skipElytra(PlayerEntity player, Hand hand, CallbackInfoReturnable info, @Local MutableObject mutableObject) { + ItemStack itemStack = player.getStackInHand(hand); + if (itemStack.isOf(Items.ELYTRA) && ElytraLock.isLocked()) { + ElytraLock.LOGGER.info("Skipping sending PlayerInteractItemC2SPacket for locked elytra"); + ElytraLock.client.inGameHud.getChatHud().addMessage(Text.translatable("elytralock.chat.lockedMessage")); + + mutableObject.setValue(ActionResult.FAIL); + info.setReturnValue((ActionResult) mutableObject.getValue()); + } + } +} diff --git a/remappedSrc/xyz/devcomp/elytralock/mixin/PlayerEntityMixin.java b/remappedSrc/xyz/devcomp/elytralock/mixin/PlayerEntityMixin.java new file mode 100644 index 0000000..39f8975 --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/mixin/PlayerEntityMixin.java @@ -0,0 +1,33 @@ +package xyz.devcomp.elytralock.mixin; + +import java.util.function.Consumer; + +import xyz.devcomp.elytralock.ElytraLock; +import xyz.devcomp.elytralock.util.RunOnceOnToggle; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.entity.player.PlayerEntity; + +// TODO: In the future, make fall flying prevention and elytra lock separate +// Fall flying prevention should be subset of elytra locking which should be +// individually toggleable + +@Mixin(PlayerEntity.class) +public class PlayerEntityMixin { + private static RunOnceOnToggle logOnce = new RunOnceOnToggle( + new Consumer() { + public void accept(String msg) { + ElytraLock.LOGGER.info(msg); + } + }); + + @Inject(method = "checkFallFlying()Z", at = @At("HEAD"), cancellable = true) + private void preventFallFlying(CallbackInfoReturnable info) { + if (logOnce.run("Elytra is locked, so preventing fall flying")) + info.setReturnValue(false); + } +} \ No newline at end of file diff --git a/remappedSrc/xyz/devcomp/elytralock/util/RunOnceOnToggle.java b/remappedSrc/xyz/devcomp/elytralock/util/RunOnceOnToggle.java new file mode 100644 index 0000000..8aa004b --- /dev/null +++ b/remappedSrc/xyz/devcomp/elytralock/util/RunOnceOnToggle.java @@ -0,0 +1,28 @@ +package xyz.devcomp.elytralock.util; + +import java.util.function.Consumer; + +import xyz.devcomp.elytralock.ElytraLock; + +public class RunOnceOnToggle { + private static boolean hasRun = false; + private Consumer toRun; + + public RunOnceOnToggle(Consumer toRun) { + this.toRun = toRun; + } + + public boolean run(T param) { + boolean isLocked = ElytraLock.isLocked(); + if (isLocked) { + if (!hasRun) { + toRun.accept(param); + hasRun = true; + } + } else { + hasRun = false; + } + + return isLocked; + } +}