Skip to content

Commit

Permalink
Fix a bug and add momentum based camera movement.
Browse files Browse the repository at this point in the history
  • Loading branch information
enjarai committed Aug 25, 2022
1 parent 8105119 commit 76489f9
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
- Added the ability to switch the yaw and roll axes.
- Added sensitivity settings.
- Added controller compat via MidnightControls.
- Fixed camera drifting while game is paused (#5)
- Added momentum based camera movement option
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
98 changes: 78 additions & 20 deletions src/main/java/nl/enjarai/doabarrelroll/DoABarrelRollClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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.
*
* <p>
* <b>Only call if you're going to call
* {@link DoABarrelRollClient#changeElytraLook(double, double, double, Sensitivity, double)}
* right after this using the returned value.</b>
* Neglecting to do this will disrupt the smoothness of the camera.
* </p>
*/
private static double getDelta() {
double time = GlfwUtil.getTime();
double delta = time - lastLookUpdate;
lastLookUpdate = time;
return delta;
}

/**
* Only use if you <b>haven't</b> 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);
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/nl/enjarai/doabarrelroll/ModMath.java
Original file line number Diff line number Diff line change
@@ -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<Integer, Integer> 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;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
7 changes: 7 additions & 0 deletions src/main/java/nl/enjarai/doabarrelroll/config/ModConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

@Config(name = DoABarrelRollClient.MODID)
public class ModConfig implements ConfigData {
@ConfigEntry.Gui.Excluded
public static ModConfig INSTANCE;

public static void init() {
Expand All @@ -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);

Expand Down
37 changes: 37 additions & 0 deletions src/main/java/nl/enjarai/doabarrelroll/mixin/InGameHudMixin.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
44 changes: 0 additions & 44 deletions src/main/java/nl/enjarai/doabarrelroll/mixin/MouseMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/assets/do-a-barrel-roll/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 76489f9

Please sign in to comment.