diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index e5d4c751..8bace745 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -100,4 +100,4 @@ jobs:
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
- github-token: ${{ secrets.TOKEN_GITHUB }}
+ github-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 33103032..d4ea4ac3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,2 @@
-- Added the ability to switch the yaw and roll axes.
-- Added sensitivity settings.
-- Added controller compat via MidnightControls.
\ No newline at end of file
+- Fixed camera drifting while game is paused (#5)
+- Added momentum based camera movement option
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 1210bab3..677e3240 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,8 +4,8 @@ minecraft_version=1.19
yarn_mappings=1.19+build.4
loader_version=0.14.8
-release_fancyname = 1.1.0 for 1.19.x
-mod_version = 1.1.0+1.19
+release_fancyname = 1.2.0 for 1.19.x
+mod_version = 1.2.0+1.19
maven_group = nl.enjarai
archives_base_name = do-a-barrel-roll
diff --git a/src/main/java/nl/enjarai/doabarrelroll/DoABarrelRollClient.java b/src/main/java/nl/enjarai/doabarrelroll/DoABarrelRollClient.java
index cd321daa..badcb352 100644
--- a/src/main/java/nl/enjarai/doabarrelroll/DoABarrelRollClient.java
+++ b/src/main/java/nl/enjarai/doabarrelroll/DoABarrelRollClient.java
@@ -8,6 +8,7 @@
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
+import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3f;
import nl.enjarai.doabarrelroll.config.ModConfig;
@@ -23,6 +24,7 @@ public class DoABarrelRollClient implements ClientModInitializer {
private static double lastLerpUpdate;
public static double landingLerp = 1;
public static Vec3d left;
+ public static Vec2f mouseTurnVec = Vec2f.ZERO;
@Override
@@ -43,70 +45,126 @@ public static void updateMouse(ClientPlayerEntity player, double cursorDeltaX, d
// smoothly lerp left vector to the assumed upright left if not in flight
if (!player.isFallFlying()) {
+
landingLerp = MathHelper.lerp(MathHelper.clamp(lerpDelta * 2, 0, 1), landingLerp, 1);
// round the lerp off when done to hopefully avoid world flickering
if (landingLerp > 0.9) landingLerp = 1;
- clearSmoothers();
+ clearValues();
player.changeLookDirection(cursorDeltaX, cursorDeltaY);
left = left.lerp(ElytraMath.getAssumedLeft(player.getYaw()), landingLerp);
+
return;
}
+
+ // reset the landing animation when flying
landingLerp = 0;
- changeElytraLook(cursorDeltaY, 0, cursorDeltaX, ModConfig.INSTANCE.desktopSensitivity);
+ if (ModConfig.INSTANCE.momentumBasedMouse) {
+
+ // add the mouse movement to the current vector and normalize if needed
+ var turnVec = mouseTurnVec.add(new Vec2f((float) cursorDeltaX, (float) cursorDeltaY).multiply(1f / 300));
+ if (turnVec.lengthSquared() > 1) {
+ turnVec = turnVec.normalize();
+ }
+ mouseTurnVec = turnVec;
+
+ // enlarge the vector and apply it to the camera
+ var delta = getDelta();
+ var readyTurnVec = mouseTurnVec.multiply(1200 * (float) delta);
+ changeElytraLook(readyTurnVec.y, 0, readyTurnVec.x, ModConfig.INSTANCE.desktopSensitivity, delta);
+
+ } else {
+
+ // if we are not using a momentum based mouse, we can reset it and apply the values directly
+ mouseTurnVec = Vec2f.ZERO;
+ changeElytraLook(cursorDeltaY, 0, cursorDeltaX, ModConfig.INSTANCE.desktopSensitivity);
+ }
}
public static void onWorldRender(MinecraftClient client, float tickDelta, long limitTime, MatrixStack matrix) {
if (client.player == null || !client.player.isFallFlying()) {
- clearSmoothers();
+ clearValues();
} else {
- var yawDelta = 25f;
- var yaw = 0;
+ if (client.isPaused()) {
- // Strafe buttons
- if (client.options.leftKey.isPressed()) {
- yaw -= yawDelta;
- }
- if (client.options.rightKey.isPressed()) {
- yaw += yawDelta;
- }
+ // keep updating the last look update time when paused to prevent large jumps after unpausing
+ lastLookUpdate = GlfwUtil.getTime();
- changeElytraLook(0, yaw, 0, ModConfig.INSTANCE.desktopSensitivity);
+ } else {
+ var yawDelta = 25f;
+ var yaw = 0;
+
+ // Strafe buttons
+ if (client.options.leftKey.isPressed()) {
+ yaw -= yawDelta;
+ }
+ if (client.options.rightKey.isPressed()) {
+ yaw += yawDelta;
+ }
+
+ changeElytraLook(0, yaw, 0, ModConfig.INSTANCE.desktopSensitivity);
+ }
}
if (landingLerp < 1) {
+ // calculate the camera angle and apply it
double angle = -Math.acos(left.dotProduct(ElytraMath.getAssumedLeft(client.player.getYaw()))) * ElytraMath.TODEG;
if (left.getY() < 0) angle *= -1;
-
matrix.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion((float) angle));
}
}
+ public static void onRenderCrosshair(MatrixStack matrices, int scaledWidth, int scaledHeight) {
+ if (!DoABarrelRollClient.isFallFlying() || !ModConfig.INSTANCE.momentumBasedMouse || !ModConfig.INSTANCE.showMomentumWidget) return;
+
+ MomentumCrosshairWidget.render(matrices, scaledWidth, scaledHeight, mouseTurnVec);
+ }
+
- private static void clearSmoothers() {
+ private static void clearValues() {
pitchSmoother.clear();
yawSmoother.clear();
rollSmoother.clear();
+ mouseTurnVec = Vec2f.ZERO;
}
- public static void changeElytraLook(double pitch, double yaw, double roll, Sensitivity sensitivity) {
- var player = MinecraftClient.getInstance().player;
- if (player == null) return;
-
- // calculate time since last update
+ /**
+ * Returns the time since the last look update.
+ *
+ *
+ * Only call if you're going to call
+ * {@link DoABarrelRollClient#changeElytraLook(double, double, double, Sensitivity, double)}
+ * right after this using the returned value.
+ * Neglecting to do this will disrupt the smoothness of the camera.
+ *
+ */
+ private static double getDelta() {
double time = GlfwUtil.getTime();
double delta = time - lastLookUpdate;
lastLookUpdate = time;
+ return delta;
+ }
+
+ /**
+ * Only use if you haven't called {@link DoABarrelRollClient#getDelta()} before this.
+ */
+ public static void changeElytraLook(double pitch, double yaw, double roll, Sensitivity sensitivity) {
+ changeElytraLook(pitch, yaw, roll, sensitivity, getDelta());
+ }
+
+ public static void changeElytraLook(double pitch, double yaw, double roll, Sensitivity sensitivity, double delta) {
+ var player = MinecraftClient.getInstance().player;
+ if (player == null) return;
// smooth the look changes
pitch = pitchSmoother.smooth(pitch, sensitivity.pitch * delta);
diff --git a/src/main/java/nl/enjarai/doabarrelroll/ModMath.java b/src/main/java/nl/enjarai/doabarrelroll/ModMath.java
new file mode 100644
index 00000000..71b40f52
--- /dev/null
+++ b/src/main/java/nl/enjarai/doabarrelroll/ModMath.java
@@ -0,0 +1,37 @@
+package nl.enjarai.doabarrelroll;
+
+import java.util.function.BiConsumer;
+
+public class ModMath {
+
+ public static void forBresenhamLine(int x0, int y0, int x1, int y1, BiConsumer consumer) {
+
+ int dx = Math.abs(x1 - x0);
+ int dy = Math.abs(y1 - y0);
+
+ int sx = x0 < x1 ? 1 : -1;
+ int sy = y0 < y1 ? 1 : -1;
+
+ int err = dx - dy;
+ int e2;
+
+ while (true) {
+
+ consumer.accept(x0, y0);
+
+ if (x0 == x1 && y0 == y1) break;
+
+ e2 = 2 * err;
+
+ if (e2 > -dy) {
+ err = err - dy;
+ x0 = x0 + sx;
+ }
+
+ if (e2 < dx) {
+ err = err + dx;
+ y0 = y0 + sy;
+ }
+ }
+ }
+}
diff --git a/src/main/java/nl/enjarai/doabarrelroll/MomentumCrosshairWidget.java b/src/main/java/nl/enjarai/doabarrelroll/MomentumCrosshairWidget.java
new file mode 100644
index 00000000..2634bba9
--- /dev/null
+++ b/src/main/java/nl/enjarai/doabarrelroll/MomentumCrosshairWidget.java
@@ -0,0 +1,43 @@
+package nl.enjarai.doabarrelroll;
+
+import com.mojang.blaze3d.platform.GlStateManager;
+import com.mojang.blaze3d.systems.RenderSystem;
+import net.minecraft.client.render.*;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.util.math.Vec2f;
+
+public class MomentumCrosshairWidget {
+
+ public static void render(MatrixStack matrices, int scaledWidth, int scaledHeight, Vec2f mouseTurnVec) {
+ int color = 0xffffffff;
+ int centerX = scaledWidth / 2;
+ int centerY = scaledHeight / 2 - 1;
+ var turnVec = mouseTurnVec.multiply(50);
+ var lineVec = turnVec.add(turnVec.negate().normalize().multiply(Math.min(turnVec.length(), 10f)));
+
+ if (!lineVec.equals(Vec2f.ZERO)) {
+
+ RenderSystem.enableBlend();
+ RenderSystem.disableTexture();
+ RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.ONE_MINUS_DST_COLOR, GlStateManager.DstFactor.ONE_MINUS_SRC_COLOR, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO);
+ RenderSystem.setShader(GameRenderer::getPositionColorShader);
+ ModMath.forBresenhamLine(centerX, centerY, centerX + (int) lineVec.x, centerY + (int) lineVec.y, (x, y) -> {
+
+ var matrix = matrices.peek().getPositionMatrix();
+ var bufferBuilder = Tessellator.getInstance().getBuffer();
+
+ bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
+ bufferBuilder.vertex(matrix, (float) x, (float) y + 1, 0.0F).color(color).next();
+ bufferBuilder.vertex(matrix, (float) x + 1, (float) y + 1, 0.0F).color(color).next();
+ bufferBuilder.vertex(matrix, (float) x + 1, (float) y, 0.0F).color(color).next();
+ bufferBuilder.vertex(matrix, (float) x, (float) y, 0.0F).color(color).next();
+ BufferRenderer.drawWithShader(bufferBuilder.end());
+
+ });
+ RenderSystem.enableTexture();
+ }
+
+ // change the position of the crosshair, which is rendered up the stack
+ matrices.translate((int) turnVec.x, (int) turnVec.y, 0);
+ }
+}
diff --git a/src/main/java/nl/enjarai/doabarrelroll/config/ModConfig.java b/src/main/java/nl/enjarai/doabarrelroll/config/ModConfig.java
index 4ca0e186..0b483011 100644
--- a/src/main/java/nl/enjarai/doabarrelroll/config/ModConfig.java
+++ b/src/main/java/nl/enjarai/doabarrelroll/config/ModConfig.java
@@ -9,6 +9,7 @@
@Config(name = DoABarrelRollClient.MODID)
public class ModConfig implements ConfigData {
+ @ConfigEntry.Gui.Excluded
public static ModConfig INSTANCE;
public static void init() {
@@ -19,6 +20,12 @@ public static void init() {
@ConfigEntry.Gui.Tooltip
public boolean switchRollAndYaw = false;
+ @ConfigEntry.Gui.Tooltip
+ public boolean momentumBasedMouse = false;
+
+ @ConfigEntry.Gui.Tooltip
+ public boolean showMomentumWidget = true;
+
@ConfigEntry.Gui.CollapsibleObject
public Sensitivity desktopSensitivity = new Sensitivity(1, 0.4, 1);
diff --git a/src/main/java/nl/enjarai/doabarrelroll/mixin/InGameHudMixin.java b/src/main/java/nl/enjarai/doabarrelroll/mixin/InGameHudMixin.java
new file mode 100644
index 00000000..24e63e1f
--- /dev/null
+++ b/src/main/java/nl/enjarai/doabarrelroll/mixin/InGameHudMixin.java
@@ -0,0 +1,37 @@
+package nl.enjarai.doabarrelroll.mixin;
+
+import com.mojang.blaze3d.platform.GlStateManager;
+import com.mojang.blaze3d.systems.RenderSystem;
+import net.minecraft.client.gui.DrawableHelper;
+import net.minecraft.client.gui.hud.InGameHud;
+import net.minecraft.client.util.math.MatrixStack;
+import nl.enjarai.doabarrelroll.DoABarrelRollClient;
+import nl.enjarai.doabarrelroll.ElytraMath;
+import nl.enjarai.doabarrelroll.ModMath;
+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.Redirect;
+
+@Mixin(InGameHud.class)
+public abstract class InGameHudMixin extends DrawableHelper {
+
+ @Shadow private int scaledWidth;
+ @Shadow private int scaledHeight;
+
+ @Shadow abstract void renderCrosshair(MatrixStack matrices);
+
+ @Redirect(
+ method = "render(Lnet/minecraft/client/util/math/MatrixStack;F)V",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/hud/InGameHud;renderCrosshair(Lnet/minecraft/client/util/math/MatrixStack;)V"
+ )
+ )
+ private void onRenderCrosshair(InGameHud inGameHud, MatrixStack matrixStack) {
+ matrixStack.push();
+ DoABarrelRollClient.onRenderCrosshair(matrixStack, scaledWidth, scaledHeight);
+ renderCrosshair(matrixStack);
+ matrixStack.pop();
+ }
+}
diff --git a/src/main/java/nl/enjarai/doabarrelroll/mixin/MouseMixin.java b/src/main/java/nl/enjarai/doabarrelroll/mixin/MouseMixin.java
index 72ec5a2b..2d379020 100644
--- a/src/main/java/nl/enjarai/doabarrelroll/mixin/MouseMixin.java
+++ b/src/main/java/nl/enjarai/doabarrelroll/mixin/MouseMixin.java
@@ -10,50 +10,6 @@
@Mixin(Mouse.class)
public abstract class MouseMixin {
-// @Shadow @Final private SmoothUtil cursorXSmoother;
-// @Shadow @Final private SmoothUtil cursorYSmoother;
-//
-//
-// // force enable the smooth camera while flying
-// @Redirect(
-// method = "updateMouse",
-// at = @At(
-// value = "FIELD",
-// target = "Lnet/minecraft/client/option/GameOptions;smoothCameraEnabled:Z"
-// )
-// )
-// private boolean smoothCameraEnabled(GameOptions options) {
-// return options.smoothCameraEnabled || DoABarrelRollClient.shouldSmooth();
-// }
-//
-//
-// // use our own smoothing while in flight
-//
-// // X axis
-// @Redirect(
-// method = "updateMouse",
-// at = @At(
-// value = "FIELD",
-// target = "Lnet/minecraft/client/Mouse;cursorXSmoother:Lnet/minecraft/client/util/SmoothUtil;"
-// )
-// )
-// private SmoothUtil modXSmoother(Mouse thiz) {
-// return DoABarrelRollClient.shouldSmooth() ? DoABarrelRollClient.rollSmoother : cursorXSmoother;
-// }
-//
-// // Y axis
-// @Redirect(
-// method = "updateMouse",
-// at = @At(
-// value = "FIELD",
-// target = "Lnet/minecraft/client/Mouse;cursorYSmoother:Lnet/minecraft/client/util/SmoothUtil;"
-// )
-// )
-// private SmoothUtil modYSmoother(Mouse thiz) {
-// return DoABarrelRollClient.shouldSmooth() ? DoABarrelRollClient.pitchSmoother : cursorYSmoother;
-// }
-
-
// redirect mouse handling to our own code
@Redirect(
method = "updateMouse",
diff --git a/src/main/resources/assets/do-a-barrel-roll/lang/en_us.json b/src/main/resources/assets/do-a-barrel-roll/lang/en_us.json
index e17f1037..2180110b 100644
--- a/src/main/resources/assets/do-a-barrel-roll/lang/en_us.json
+++ b/src/main/resources/assets/do-a-barrel-roll/lang/en_us.json
@@ -2,6 +2,10 @@
"text.autoconfig.do-a-barrel-roll.title": "§lDo a Barrel Roll",
"text.autoconfig.do-a-barrel-roll.option.switchRollAndYaw": "Switch roll and yaw",
"text.autoconfig.do-a-barrel-roll.option.switchRollAndYaw.@Tooltip": "Switch the roll and yaw axis, not recommended but might make flying easier for some people.",
+ "text.autoconfig.do-a-barrel-roll.option.momentumBasedMouse": "Use momentum based camera",
+ "text.autoconfig.do-a-barrel-roll.option.momentumBasedMouse.@Tooltip": "Makes it easier to make continuous movements with the mouse.",
+ "text.autoconfig.do-a-barrel-roll.option.showMomentumWidget": "Show momentum widget",
+ "text.autoconfig.do-a-barrel-roll.option.showMomentumWidget.@Tooltip": "Turn the crosshair into a helpful widget when using the momentum based camera.",
"text.autoconfig.do-a-barrel-roll.option.desktopSensitivity": "Mouse and keyboard sensitivity",
"text.autoconfig.do-a-barrel-roll.option.desktopSensitivity.pitch": "Pitch",
"text.autoconfig.do-a-barrel-roll.option.desktopSensitivity.yaw": "Yaw",
diff --git a/src/main/resources/do-a-barrel-roll.mixins.json b/src/main/resources/do-a-barrel-roll.mixins.json
index ef55e910..b2020dcf 100644
--- a/src/main/resources/do-a-barrel-roll.mixins.json
+++ b/src/main/resources/do-a-barrel-roll.mixins.json
@@ -6,9 +6,12 @@
"client": [
"ClientPlayerEntityMixin",
"GameRendererMixin",
- "MouseMixin"
+ "MouseMixin",
+ "InGameHudMixin"
],
"injectors": {
"defaultRequire": 1
- }
+ },
+ "mixins": [
+ ]
}