diff --git a/README.md b/README.md index e689ff4..d4abfa2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,16 @@ which was originally for 1.20.1. I've ported the mod to 1.21.8, but there's still a major bug, which is if you're using the powered jetback in quirk armor, it won't show it on your player model. + +This version also adds hover flying and creative flying. +Hover is by default bound to H, and creative fly is bound by default to J. + +| Jetpack type | Hover | Creative | +|-------------- |------- |---------- | +| Basic | ❌ | ❌ | +| Advanced | ✅ | ❌ | +| Industrial | ✅ | ✅ | + # Powered Jetpacks A simple fabric mod about jetpacks powered with E energy. diff --git a/gradle.properties b/gradle.properties index 598beb9..5903c9d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ maven_group=konhaiii.powered_jetpacks archives_base_name=powered_jetpacks # Dependencies -energy_version=4.2.0 +energy_version=4.2.1 trinkets_version=3.11.0-1.21.6 fabric_version=0.134.0+1.21.8 cca_version=7.0.0-beta.1 \ No newline at end of file diff --git a/src/client/java/konhaiii/powered_jetpacks/PoweredJetpacksClient.java b/src/client/java/konhaiii/powered_jetpacks/PoweredJetpacksClient.java index c6bf7d1..85a5b6c 100644 --- a/src/client/java/konhaiii/powered_jetpacks/PoweredJetpacksClient.java +++ b/src/client/java/konhaiii/powered_jetpacks/PoweredJetpacksClient.java @@ -1,27 +1,134 @@ package konhaiii.powered_jetpacks; import konhaiii.powered_jetpacks.hud.JetpackHUD; +import konhaiii.powered_jetpacks.item.special.JetpackItem; import konhaiii.powered_jetpacks.models.JetpackModel; import konhaiii.powered_jetpacks.renderers.JetpackRenderer; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRendererRegistrationCallback; import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.option.KeyBinding; import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.util.InputUtil; import net.minecraft.entity.EntityType; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; import net.minecraft.registry.tag.EntityTypeTags; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import org.lwjgl.glfw.GLFW; +import org.spongepowered.asm.mixin.Unique; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + public class PoweredJetpacksClient implements ClientModInitializer { + public static KeyBinding hoverKeybinding = KeyBindingHelper.registerKeyBinding(new KeyBinding( + "key.powered_jetpack.hover", + InputUtil.Type.KEYSYM, + GLFW.GLFW_KEY_H, + "category.powered_jetpack" + )); + + public static KeyBinding creativeKeybinding = KeyBindingHelper.registerKeyBinding(new KeyBinding( + "key.powered_jetpack.creative", + InputUtil.Type.KEYSYM, + GLFW.GLFW_KEY_J, + "category.powered_jetpack" + )); + + public static boolean toggledHover = false; + public static boolean toggledCreative = false; + + public static ItemStack getJetpack(ClientPlayerEntity player) { + ItemStack chestStack = player.getEquippedStack(EquipmentSlot.CHEST); + ItemStack backStack = ItemStack.EMPTY; + + if (PoweredJetpacks.isTrinketsLoaded) { + try { + Class optionalClass = Class.forName("konhaiii.powered_jetpacks.compat.TrinketsServer"); + Method getBackStackMethod = optionalClass.getMethod("getBackStack", LivingEntity.class); + backStack = (ItemStack) getBackStackMethod.invoke(null, player); + } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | + IllegalAccessException e) { + PoweredJetpacks.LOGGER.error("ClientPlayerEntityMixin: Could not load Trinkets compat class."); + } + } + + ItemStack jetpackStack = ItemStack.EMPTY; + if (isValidJetpack(chestStack)) { + jetpackStack = chestStack; + } else if (isValidJetpack(backStack)) { + jetpackStack = backStack; + } + + + return jetpackStack; + } + @Unique + private static boolean isValidJetpack(ItemStack stack) { + if (stack.getItem() instanceof JetpackItem jetpack) { + if (jetpack.getEnergyCost() <= 0) { + return true; + } + return jetpack.getStoredEnergy(stack) > 0; + } + return false; + } @Override public void onInitializeClient() { ItemTooltipCallback.EVENT.register(new StackToolTipHandler()); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + while (creativeKeybinding.wasPressed()) { + if (client.player != null) { + ItemStack stack = getJetpack(client.player); + if (!stack.isEmpty() && ((JetpackItem)stack.getItem()).allowCreative) { + if (toggledHover) { + toggledHover = false; + client.player.setNoGravity(toggledHover); + } + toggledCreative = !toggledCreative; + if (!toggledCreative) { + client.player.getAbilities().allowFlying = false; + client.player.getAbilities().flying = false; + } else { + client.player.getAbilities().allowFlying = true; + client.player.getAbilities().flying = true; + client.player.sendAbilitiesUpdate(); + } + + } + } + } + }); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + while (hoverKeybinding.wasPressed()) { + if (client.player != null) { + ItemStack stack = getJetpack(client.player); + if (!stack.isEmpty() && ((JetpackItem)stack.getItem()).allowHover) { + if (toggledCreative) { + toggledCreative = false; + client.player.getAbilities().allowFlying = false; + client.player.getAbilities().flying = false; + } + + toggledHover = !toggledHover; + client.player.setNoGravity(toggledHover); + } + } + } + }); LivingEntityFeatureRendererRegistrationCallback.EVENT.register( (entityType, entityRenderer, registrationHelper, context) -> { if (entityRenderer != null && entityType == EntityType.PLAYER) { diff --git a/src/client/java/konhaiii/powered_jetpacks/hud/JetpackHUD.java b/src/client/java/konhaiii/powered_jetpacks/hud/JetpackHUD.java index 28c34c8..4e5a129 100644 --- a/src/client/java/konhaiii/powered_jetpacks/hud/JetpackHUD.java +++ b/src/client/java/konhaiii/powered_jetpacks/hud/JetpackHUD.java @@ -1,6 +1,7 @@ package konhaiii.powered_jetpacks.hud; import konhaiii.powered_jetpacks.PoweredJetpacks; +import konhaiii.powered_jetpacks.PoweredJetpacksClient; import konhaiii.powered_jetpacks.item.special.JetpackItem; import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElement; import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; @@ -59,8 +60,22 @@ public class JetpackHUD implements HudElement { TextRenderer textRenderer = client.textRenderer; int percentage = percentage(energy, maxEnergy); String energyText = translate("hud.powered_jetpacks.jetpack_power").concat(String.valueOf(percentage)).concat("%"); - drawContext.drawTextWithShadow(textRenderer, energyText, 10, 10, 0xFFFFFFFF); + + String hoverStatus = PoweredJetpacksClient.toggledHover ? "ON" : "OFF"; + String creativeStatus = PoweredJetpacksClient.toggledCreative ? "ON" : "OFF"; + + if(!jetpack.allowCreative) { + creativeStatus = "DISABLED"; + } + if(!jetpack.allowHover) { + hoverStatus = "DISABLED"; + } + + if(jetpack.allowHover || jetpack.allowCreative) { + String statusText = translate("hud.powered_jetpacks.status", hoverStatus, creativeStatus); + drawContext.drawTextWithShadow(textRenderer, statusText, 10, 20, 0xFFFFFFFF); + } } } } \ No newline at end of file diff --git a/src/client/java/konhaiii/powered_jetpacks/mixin/client/ClientPlayerEntityMixin.java b/src/client/java/konhaiii/powered_jetpacks/mixin/client/ClientPlayerEntityMixin.java index e57748f..9ed48e6 100644 --- a/src/client/java/konhaiii/powered_jetpacks/mixin/client/ClientPlayerEntityMixin.java +++ b/src/client/java/konhaiii/powered_jetpacks/mixin/client/ClientPlayerEntityMixin.java @@ -1,15 +1,11 @@ package konhaiii.powered_jetpacks.mixin.client; -import konhaiii.powered_jetpacks.PoweredJetpacks; +import konhaiii.powered_jetpacks.PoweredJetpacksClient; import konhaiii.powered_jetpacks.item.special.JetpackItem; import konhaiii.powered_jetpacks.packet.JetpackPacket; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.entity.EquipmentSlot; -import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; import net.minecraft.util.math.Vec3d; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -17,75 +13,103 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - @Mixin(ClientPlayerEntity.class) public abstract class ClientPlayerEntityMixin { - @Unique - private int soundCounter = 8; + @Unique + private int soundCounter = 8; - @Inject(method = "tick", at = @At("HEAD")) - private void onTick(CallbackInfo ci) { - ClientPlayerEntity player = (ClientPlayerEntity) (Object) this; - if (player.input.playerInput.jump()) { - ItemStack chestStack = player.getEquippedStack(EquipmentSlot.CHEST); - ItemStack backStack = ItemStack.EMPTY; + @Inject(method = "tick", at = @At("HEAD")) + private void onTick(CallbackInfo ci) { + ClientPlayerEntity player = (ClientPlayerEntity) (Object) this; - if (PoweredJetpacks.isTrinketsLoaded) { - try { - Class optionalClass = Class.forName("konhaiii.powered_jetpacks.compat.TrinketsServer"); - Method getBackStackMethod = optionalClass.getMethod("getBackStack", LivingEntity.class); - backStack = (ItemStack) getBackStackMethod.invoke(null, player); - } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | - IllegalAccessException e) { - PoweredJetpacks.LOGGER.error("ClientPlayerEntityMixin: Could not load Trinkets compat class."); - } - } + ItemStack jetpackStack = PoweredJetpacksClient.getJetpack(player); - ItemStack jetpackStack = null; - if (isValidJetpack(chestStack)) { - jetpackStack = chestStack; - } else if (isValidJetpack(backStack)) { - jetpackStack = backStack; - } + if (!jetpackStack.isEmpty()) { + JetpackPacket packet; - if (jetpackStack != null) { - JetpackPacket packet; + JetpackItem jetpack = (JetpackItem) jetpackStack.getItem(); + if (PoweredJetpacksClient.toggledCreative && !jetpack.allowCreative) { + PoweredJetpacksClient.toggledCreative = false; + player.getAbilities().allowFlying = false; + player.getAbilities().flying = false; + } - JetpackItem jetpack = (JetpackItem) jetpackStack.getItem(); - Vec3d velocity = player.getVelocity(); - float horizontalBoost = jetpack.getFlightSpeed(); - player.setVelocity( - velocity.x + (player.getRotationVector().x * horizontalBoost), - jetpack.addToVerticalVelocity(player.getVelocity().y), - velocity.z + (player.getRotationVector().z * horizontalBoost) - ); - player.fallDistance = 0; + if (PoweredJetpacksClient.toggledHover && !jetpack.allowHover) { + PoweredJetpacksClient.toggledHover = false; + player.setNoGravity(false); + } - soundCounter++; - if (soundCounter >= 8) { - packet = new JetpackPacket(true); - soundCounter = 0; - } else { - packet = new JetpackPacket(false); - } - ClientPlayNetworking.send(packet); - } else if (soundCounter != 8) { - soundCounter = 8; - } - } else if (soundCounter != 8) { - soundCounter = 8; - } - } - @Unique - private boolean isValidJetpack(ItemStack stack) { - if (stack.getItem() instanceof JetpackItem jetpack) { - if (jetpack.getEnergyCost() <= 0) { - return true; - } - return jetpack.getStoredEnergy(stack) > 0; - } - return false; - } + Vec3d velocity = player.getVelocity(); + + boolean sendPacket = PoweredJetpacksClient.toggledCreative && !player.isOnGround(); + + if (PoweredJetpacksClient.toggledHover && jetpack.allowHover && !player.isOnGround()) { + double vertical = 0.0; + double hoverUpSpeed = 0.5; + double hoverDownSpeed = 0.4; + double horizontalSpeed = 0.35; + double inertia = 0.25; + + if (player.input.playerInput.jump()) { + vertical += hoverUpSpeed; + } else if (player.input.playerInput.sneak()) { + vertical -= hoverDownSpeed; + } else { + vertical = 0.0; + } + + Vec3d lookDir = player.getRotationVector().normalize(); + Vec3d strafeDir = new Vec3d(-lookDir.z, 0, lookDir.x).normalize(); + Vec3d move = Vec3d.ZERO; + + if (player.input.playerInput.forward()) move = move.add(lookDir); + if (player.input.playerInput.backward()) move = move.subtract(lookDir); + if (player.input.playerInput.right()) move = move.add(strafeDir); + if (player.input.playerInput.left()) move = move.subtract(strafeDir); + + if (move.lengthSquared() > 0) { + move = move.normalize().multiply(horizontalSpeed); + } + + Vec3d targetVel = new Vec3d(move.x, vertical, move.z); + Vec3d currentVel = player.getVelocity(); + + Vec3d blended = currentVel.multiply(inertia).add(targetVel.multiply(1 - inertia)); + player.setVelocity(blended); + sendPacket = true; + } else if (player.input.playerInput.jump()) { + float horizontalBoost = jetpack.getFlightSpeed(); + player.setVelocity(velocity.x + (player.getRotationVector().x * horizontalBoost), jetpack.addToVerticalVelocity(player.getVelocity().y), velocity.z + (player.getRotationVector().z * horizontalBoost)); + sendPacket = true; + } + + player.fallDistance = 0; + + if (sendPacket) { + soundCounter++; + + if (soundCounter >= 8) { + packet = new JetpackPacket(true); + soundCounter = 0; + } else { + packet = new JetpackPacket(false); + } + ClientPlayNetworking.send(packet); + } + } else { + if (PoweredJetpacksClient.toggledCreative) { + PoweredJetpacksClient.toggledCreative = false; + player.getAbilities().allowFlying = false; + player.getAbilities().flying = false; + } + + if (PoweredJetpacksClient.toggledHover) { + PoweredJetpacksClient.toggledHover = false; + player.setNoGravity(false); + } + } + if (soundCounter != 8) { + soundCounter = 8; + } + } } \ No newline at end of file diff --git a/src/main/java/konhaiii/powered_jetpacks/item/ModItems.java b/src/main/java/konhaiii/powered_jetpacks/item/ModItems.java index 1c260c9..5c4ff66 100644 --- a/src/main/java/konhaiii/powered_jetpacks/item/ModItems.java +++ b/src/main/java/konhaiii/powered_jetpacks/item/ModItems.java @@ -35,19 +35,19 @@ public class ModItems { public static final Item BASIC_JETPACK = register( "basic_jetpack", - settings -> new JetpackItem(settings, PoweredJetpacks.config.basicJetpackMaxEnergy, PoweredJetpacks.config.basicJetpackInputEnergy, PoweredJetpacks.config.basicJetpackVerticalSpeed, PoweredJetpacks.config.basicJetpackHorizontalSpeed, PoweredJetpacks.config.basicJetpackEnergyCost), + settings -> new JetpackItem(settings, PoweredJetpacks.config.basicJetpackMaxEnergy, PoweredJetpacks.config.basicJetpackInputEnergy, PoweredJetpacks.config.basicJetpackVerticalSpeed, PoweredJetpacks.config.basicJetpackHorizontalSpeed, PoweredJetpacks.config.basicJetpackEnergyCost, false, false), new Item.Settings().armor(ArmorMaterials.IRON, EquipmentType.CHESTPLATE) ); public static final Item ADVANCED_JETPACK = register( "advanced_jetpack", - settings -> new JetpackItem(settings, PoweredJetpacks.config.advancedJetpackMaxEnergy, PoweredJetpacks.config.advancedJetpackInputEnergy, PoweredJetpacks.config.advancedJetpackVerticalSpeed, PoweredJetpacks.config.advancedJetpackHorizontalSpeed, PoweredJetpacks.config.advancedJetpackEnergyCost), + settings -> new JetpackItem(settings, PoweredJetpacks.config.advancedJetpackMaxEnergy, PoweredJetpacks.config.advancedJetpackInputEnergy, PoweredJetpacks.config.advancedJetpackVerticalSpeed, PoweredJetpacks.config.advancedJetpackHorizontalSpeed, PoweredJetpacks.config.advancedJetpackEnergyCost, true, false), new Item.Settings().armor(ArmorMaterials.DIAMOND, EquipmentType.CHESTPLATE) ); public static final Item INDUSTRIAL_JETPACK = register( "industrial_jetpack", - settings -> new JetpackItem(settings, PoweredJetpacks.config.industrialJetpackMaxEnergy, PoweredJetpacks.config.industrialJetpackInputEnergy, PoweredJetpacks.config.industrialJetpackVerticalSpeed, PoweredJetpacks.config.industrialJetpackHorizontalSpeed, PoweredJetpacks.config.industrialJetpackEnergyCost), + settings -> new JetpackItem(settings, PoweredJetpacks.config.industrialJetpackMaxEnergy, PoweredJetpacks.config.industrialJetpackInputEnergy, PoweredJetpacks.config.industrialJetpackVerticalSpeed, PoweredJetpacks.config.industrialJetpackHorizontalSpeed, PoweredJetpacks.config.industrialJetpackEnergyCost, true, true), new Item.Settings().armor(ArmorMaterials.NETHERITE, EquipmentType.CHESTPLATE) ); diff --git a/src/main/java/konhaiii/powered_jetpacks/item/special/JetpackItem.java b/src/main/java/konhaiii/powered_jetpacks/item/special/JetpackItem.java index 241c00d..20ae258 100644 --- a/src/main/java/konhaiii/powered_jetpacks/item/special/JetpackItem.java +++ b/src/main/java/konhaiii/powered_jetpacks/item/special/JetpackItem.java @@ -21,14 +21,19 @@ public class JetpackItem extends Item implements SimpleEnergyItem { private final float flightPower; private final float flightSpeed; private final int energyCost; + public final boolean allowHover; + public final boolean allowCreative; - public JetpackItem(Settings settings, int maxEnergy, int inputEnergy, float flightPower, float flightSpeed, int energyCost) { + public JetpackItem(Settings settings, int maxEnergy, int inputEnergy, float flightPower, float flightSpeed, int energyCost, boolean allowHover, boolean allowCreative) { super(settings.maxCount(1)); this.maxEnergy = maxEnergy; this.inputEnergy = inputEnergy; this.flightPower = flightPower; this.flightSpeed = flightSpeed; this.energyCost = energyCost; + this.allowHover = allowHover; + this.allowCreative = allowCreative; + DispenserBlock.registerBehavior(this, DispenserBehavior.NOOP); } diff --git a/src/main/resources/assets/powered_jetpacks/lang/en_us.json b/src/main/resources/assets/powered_jetpacks/lang/en_us.json index 5ed0d48..32f04c2 100644 --- a/src/main/resources/assets/powered_jetpacks/lang/en_us.json +++ b/src/main/resources/assets/powered_jetpacks/lang/en_us.json @@ -8,5 +8,9 @@ "tooltip.powered_jetpacks.input_rate": "Input Rate", "tooltip.powered_jetpacks.output_rate": "Output Rate", "tooltip.powered_jetpacks.transfer_rate": "Transfer Rate", - "hud.powered_jetpacks.jetpack_power": "Jetpack Power: " + "hud.powered_jetpacks.jetpack_power": "Jetpack Power: ", + "key.powered_jetpack.hover": "Hover", + "key.powered_jetpack.creative": "Creative Fly", + "category.powered_jetpack": "Powered Jetpacks", + "hud.powered_jetpacks.status": "HOVER: %s, CREATIVE: %s" } \ No newline at end of file