diff --git a/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java b/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java index b48d726..ad95816 100644 --- a/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java +++ b/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java @@ -3,8 +3,10 @@ package org.saturnclient.saturnclient.event; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.option.Perspective; import net.minecraft.client.util.InputUtil; import org.saturnclient.saturnclient.menus.SaturnMenu; +import org.saturnclient.saturnmods.mods.FreeLook; import org.lwjgl.glfw.GLFW; /** @@ -15,9 +17,12 @@ public class KeyInputHandler { private static final String KEY_CATEGORY = "key.category.saturnclient"; private static final String MAIN_MENU_KEY_ID = "key.saturnclient.main_menu"; private static final int DEFAULT_MENU_KEY = GLFW.GLFW_KEY_RIGHT_SHIFT; - private static KeyBinding mainMenuKeyBinding; + private static final String FREELOOK_KEY_ID = "key.saturnclient.freelook"; + private static final int FREELOOK_KEY = GLFW.GLFW_KEY_M; + private static KeyBinding freelookKeyBinding; + /** * Registers all keybindings and their associated event handlers. * Should be called during mod initialization. @@ -30,10 +35,37 @@ public class KeyInputHandler { DEFAULT_MENU_KEY, KEY_CATEGORY)); + freelookKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding( + FREELOOK_KEY_ID, + InputUtil.Type.KEYSYM, + FREELOOK_KEY, + KEY_CATEGORY)); + // Register the event handler for the main menu key ClientTickEvents.END_CLIENT_TICK.register(client -> { if (mainMenuKeyBinding.wasPressed()) { client.setScreen(new SaturnMenu()); + } else if (freelookKeyBinding.wasPressed() && FreeLook.enabled.value && FreeLook.toggle.value) { + FreeLook.isFreeLooking = !FreeLook.isFreeLooking; + if (FreeLook.isFreeLooking) { + FreeLook.lastPerspective = client.options.getPerspective(); + client.options.setPerspective(Perspective.THIRD_PERSON_BACK); + } else if (FreeLook.lastPerspective != null) { + client.options.setPerspective(FreeLook.lastPerspective); + FreeLook.lastPerspective = null; + } + } else if (FreeLook.enabled.value && !FreeLook.toggle.value) { + if (freelookKeyBinding.isPressed()) { + if (!FreeLook.isFreeLooking) { + FreeLook.lastPerspective = client.options.getPerspective(); + client.options.setPerspective(Perspective.THIRD_PERSON_BACK); + FreeLook.isFreeLooking = true; + } + } else if (FreeLook.isFreeLooking && FreeLook.lastPerspective != null) { + client.options.setPerspective(FreeLook.lastPerspective); + FreeLook.isFreeLooking = false; + FreeLook.lastPerspective = null; + } } }); } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/CameraMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/CameraMixin.java new file mode 100644 index 0000000..55d0135 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/mixin/CameraMixin.java @@ -0,0 +1,47 @@ +package org.saturnclient.saturnclient.mixin; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.Camera; + +import org.saturnclient.saturnclient.mod_utils.CameraOverriddenEntity; +import org.saturnclient.saturnmods.mods.FreeLook; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.Entity; +import net.minecraft.world.BlockView; + +@Mixin(Camera.class) +public abstract class CameraMixin { + @Unique + boolean firstTime = true; + + @Shadow + protected abstract void setRotation(float yaw, float pitch); + + @Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER)) + public void lockRotation(BlockView focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing, + float tickDelta, CallbackInfo ci) { + if (FreeLook.isFreeLooking && cameraEntity instanceof ClientPlayerEntity) { + CameraOverriddenEntity cameraOverriddenEntity = (CameraOverriddenEntity) cameraEntity; + + if (firstTime && MinecraftClient.getInstance().player != null) { + cameraOverriddenEntity.freelook$setCameraPitch(MinecraftClient.getInstance().player.getPitch()); + cameraOverriddenEntity.freelook$setCameraYaw(MinecraftClient.getInstance().player.getYaw()); + firstTime = false; + } + this.setRotation(cameraOverriddenEntity.freelook$getCameraYaw(), + cameraOverriddenEntity.freelook$getCameraPitch()); + + } + if (!FreeLook.isFreeLooking && cameraEntity instanceof ClientPlayerEntity) { + firstTime = true; + } + } + +} diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/EntityMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/EntityMixin.java new file mode 100644 index 0000000..f452cd8 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/mixin/EntityMixin.java @@ -0,0 +1,62 @@ +package org.saturnclient.saturnclient.mixin; + +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; + +import org.saturnclient.saturnclient.mod_utils.CameraOverriddenEntity; +import org.saturnclient.saturnmods.mods.FreeLook; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Entity.class) +public class EntityMixin implements CameraOverriddenEntity { + @Unique + private float cameraPitch; + + @Unique + private float cameraYaw; + + @Inject(method = "changeLookDirection", at = @At("HEAD"), cancellable = true) + public void changeCameraLookDirection(double xDelta, double yDelta, CallbackInfo ci) { + // noinspection ConstantValue// IntelliJ is incorrect here, this code block is + // reachable + if (FreeLook.isFreeLooking && (Object) this instanceof ClientPlayerEntity) { + double pitchDelta = (yDelta * 0.15); + double yawDelta = (xDelta * 0.15); + + this.cameraPitch = MathHelper.clamp(this.cameraPitch + (float) pitchDelta, -90.0f, 90.0f); + this.cameraYaw += (float) yawDelta; + + ci.cancel(); + + } + } + + @Override + @Unique + public float freelook$getCameraPitch() { + return this.cameraPitch; + } + + @Override + @Unique + public float freelook$getCameraYaw() { + return this.cameraYaw; + } + + @Override + @Unique + public void freelook$setCameraPitch(float pitch) { + this.cameraPitch = pitch; + } + + @Override + @Unique + public void freelook$setCameraYaw(float yaw) { + this.cameraYaw = yaw; + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/mod_utils/CameraOverriddenEntity.java b/src/main/java/org/saturnclient/saturnclient/mod_utils/CameraOverriddenEntity.java new file mode 100644 index 0000000..a72664a --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/mod_utils/CameraOverriddenEntity.java @@ -0,0 +1,9 @@ +package org.saturnclient.saturnclient.mod_utils; + +public interface CameraOverriddenEntity { + float freelook$getCameraPitch(); + float freelook$getCameraYaw(); + + void freelook$setCameraPitch(float pitch); + void freelook$setCameraYaw(float yaw); +} diff --git a/src/main/java/org/saturnclient/saturnmods/ModManager.java b/src/main/java/org/saturnclient/saturnmods/ModManager.java index 604f089..f488a9c 100644 --- a/src/main/java/org/saturnclient/saturnmods/ModManager.java +++ b/src/main/java/org/saturnclient/saturnmods/ModManager.java @@ -15,7 +15,8 @@ public class ModManager { new ArmorDisplay(), new FpsDisplay(), new Particles(), - new Crosshair() + new Crosshair(), + new FreeLook() }; public static void init() { diff --git a/src/main/java/org/saturnclient/saturnmods/mods/FreeLook.java b/src/main/java/org/saturnclient/saturnmods/mods/FreeLook.java new file mode 100644 index 0000000..cd3719c --- /dev/null +++ b/src/main/java/org/saturnclient/saturnmods/mods/FreeLook.java @@ -0,0 +1,46 @@ +package org.saturnclient.saturnmods.mods; + +import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnclient.config.Property; +import org.saturnclient.saturnmods.SaturnMod; +import org.saturnclient.ui.Textures; + +import net.minecraft.client.option.Perspective; +import net.minecraft.util.Identifier; + +public class FreeLook implements SaturnMod { + public static boolean isFreeLooking = false; + public static Perspective lastPerspective = null; + + private static ConfigManager config = new ConfigManager("armor"); + public static Property enabled = config.property( + "Enabled", + new Property<>(false)); + + public static Property toggle = config.property( + "Toggle Free Look", + new Property<>(false)); + + public boolean isEnabled() { + return enabled.value; + } + + public void setEnabled(boolean e) { + enabled.value = e; + } + + @Override + public ConfigManager getConfig() { + return config; + } + + @Override + public Identifier getIconTexture() { + return Textures.getModIcon("freelook"); + } + + @Override + public String getName() { + return "Free Look"; + } +} diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.png b/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.png new file mode 100644 index 0000000..9418d12 Binary files /dev/null and b/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.png differ diff --git a/src/main/resources/saturnclient.mixins.json b/src/main/resources/saturnclient.mixins.json index 54fdca6..8aaefd3 100644 --- a/src/main/resources/saturnclient.mixins.json +++ b/src/main/resources/saturnclient.mixins.json @@ -10,7 +10,9 @@ "WhoAmI", "SaturnReload", "TotemParticleMixin", - "Crosshair" + "Crosshair", + "EntityMixin", + "CameraMixin" ], "injectors": { "defaultRequire": 1