Skip to content

Commit

Permalink
#37 v0.3.0
Browse files Browse the repository at this point in the history
- Players now look at their perceived down (e.g. the seat they're sitting in) rather than the real ground. #32
- Fixed jittery leaning. #22
- When targetting a block with the crosshair, the mod now makes some adjustments to target the block you should be looking at instead of the block the game thinks you're looking at. #35
  - This is probably incompatible with anti-cheat mods/plugins.
  - The feature is also still *ever so slightly* janky, but for most purposes it should be very usable.
- Fixed jittering of hand when traveling along the negative X axis.
- Fabric only: added a contact email.
  • Loading branch information
der-fruhling authored May 17, 2024
2 parents 6d0f738 + 0ce9377 commit 5305768
Show file tree
Hide file tree
Showing 16 changed files with 252 additions and 85 deletions.
37 changes: 28 additions & 9 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
- Fixed incorrect rolling when looking certain directions
- Now compatible with [do a barrel roll](https://modrinth.com/mod/do-a-barrel-roll) and hopefully other camera roll kinds of mods.
- The third-person camera while seated on a train is now improved. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/24)
Major update to fix major problems. The mod is in a pretty good state now.

Known issues:
- The mod's leaning is a bit jittery. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/22)
- This is probably more of a limitation of Minecraft itself. It might be fixable with a config option to emulate pitch, but that wouldn't make the player appear correctly to other players.
- Update: it's most definitely possible to fix this up.
- The easing back to normal posture after jumping off a train on a slope could use some work. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/23)
The scoops:
- Players now look at their perceived down (e.g. the seat they're sitting in) rather than the real ground. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/32)
- Fixed jittery leaning. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/22)
- When targetting a block with the crosshair, the mod now makes some adjustments to target the block you should be looking at instead of the block the game thinks you're looking at. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/35)
- This is probably incompatible with anti-cheat mods/plugins.
- The feature is also still _ever so slightly_ janky, but for most purposes it should be very usable.
- Fixed jittering of hand when traveling along the negative X axis.
- Fabric only: added a contact email.

[View full change log.](https://github.com/der-fruhling/create-train-perspective/compare/v0.2.2...v0.2.3)
[View full change log.](https://github.com/der-fruhling/create-train-perspective/compare/v0.2.3...v0.3.0)

---

In 0.1.2, I decided that the mod was basically ready and marked it as a Release version.

On second thought, I have realized the state of the mod and decided that Beta better describes its current state.
I have marked versions 0.2.2+ as Beta and all versions before that as Alpha to better represent this.

Of course, this does not mean that the mod is unusable or is going to break _everything_.
It just doesn't hold all the qualities I want it to.
In my opinion, A full Release version should be highly functional and configurable,
while retaining good compatibility with popular mods.

On that note, this version is _quality_ enough to be a release candidate,
and would be if it weren't for the missing things below:
- Configuration. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/36)
- More accurate perspective. For a mod called "Create: _Train Perspective_", this is an important issue. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/38)
- Some sound system and fog issues. Nothing major, but slightly annoying. [View issue.](https://github.com/der-fruhling-entertainment/create-train-perspective/issues/39)

---

Expand Down
21 changes: 10 additions & 11 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
Minor update to fix some issues.
Major update to fix major problems. The mod is in a pretty good state now.

- Fixed incorrect rolling when looking certain directions
- Now compatible with [do a barrel roll] and hopefully other camera roll kinds of mods.
- The third-person camera while seated on a train is now improved. https://github.com/der-fruhling-entertainment/create-train-perspective/issues/24
[Changelog]
- Players now look at their perceived down (e.g. the seat they're sitting in) rather than the real ground. https://github.com/der-fruhling-entertainment/create-train-perspective/issues/32
- Fixed jittery leaning. https://github.com/der-fruhling-entertainment/create-train-perspective/issues/22
- When targetting a block with the crosshair, the mod now makes some adjustments to target the block you should be looking at instead of the block the game thinks you're looking at. https://github.com/der-fruhling-entertainment/create-train-perspective/issues/35
- This is probably incompatible with anti-cheat mods/plugins.
- The feature is also still *ever so slightly* janky, but for most purposes it should be very usable.
- Fixed jittering of hand when traveling along the negative X axis.
- Fabric only: added a contact email.

Known issues:
- The mod's leaning is a bit jittery. https://github.com/der-fruhling-entertainment/create-train-perspective/issues/22
- This is probably more of a limitation of Minecraft itself. It might be fixable with a config option to emulate pitch, but that wouldn't make the player appear correctly to other players.
- Update: it's most definitely possible to fix this up.
- The easing back to normal posture after jumping off a train on a slope could use some work. https://github.com/der-fruhling-entertainment/create-train-perspective/issues/23

https://github.com/der-fruhling/create-train-perspective/compare/v0.2.2...v0.2.3
Commits: https://github.com/der-fruhling/create-train-perspective/compare/v0.2.3...v0.3.0

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

public interface Camera3D {
float getZRot();
float getExtraYRot();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
import org.apache.commons.lang3.mutable.MutableInt;
import org.slf4j.Logger;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;

// The value here should match an entry in the META-INF/mods.toml file
public class CreateTrainPerspectiveMod {
Expand All @@ -30,7 +28,10 @@ public CreateTrainPerspectiveMod() {
private static class RotationState {
public final CarriageContraptionEntity entity;
private float lastYaw;
public boolean standingState, isMounted, shouldTickState = true;
public boolean standingState;
public boolean isMounted;
public boolean shouldTickState = true;
public int ticksSinceLastUpdate = 0;

public RotationState(CarriageContraptionEntity entity, boolean standingState, boolean isMounted) {
this.entity = entity;
Expand All @@ -40,6 +41,14 @@ public RotationState(CarriageContraptionEntity entity, boolean standingState, bo
}

public float getYawDelta() {
while (entity.yaw - lastYaw < -180.0f) {
lastYaw -= 360.0f;
}

while (entity.yaw - lastYaw >= 180.0f) {
lastYaw += 360.0f;
}

var rotation = entity.yaw - lastYaw;
lastYaw = entity.yaw;
return rotation;
Expand All @@ -60,40 +69,31 @@ public void onEntityMount(boolean isMounting, Entity entityMounting, Entity enti
states.put(entityMounting.getUUID(), state);
persp.enable(state.entity.pitch, state.entity.yaw);
} else {
states.get(entityMounting.getUUID()).isMounted = true;
var state = states.get(entityMounting.getUUID());
state.isMounted = true;
state.shouldTickState = true;
}
} else {
if(states.containsKey(entityMounting.getUUID())) {
if(states.get(entityMounting.getUUID()).standingState) {
states.get(entityMounting.getUUID()).isMounted = false;
} else {
states.remove(entityMounting.getUUID());
persp.disable();
}
states.remove(entityMounting.getUUID());
persp.disable();
}
}
}
}

public void tickStandingPlayers(final CarriageContraptionEntity contraption) {
for(Map.Entry<Entity, MutableInt> entry : contraption.collidingEntities.entrySet()) {
var entity = entry.getKey();
var ticks = entry.getValue();
if(entity instanceof LocalPlayer player) {
if(player.getVehicle() != null) continue;

var state = states.get(player.getUUID());
if (state == null) {
var persp = (Perspective) Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player);
state = new RotationState(contraption, true, false);
states.put(player.getUUID(), state);
persp.enable(state.entity.pitch, state.entity.yaw);
} else if(ticks.getValue() >= 2) {
state.shouldTickState = false;
} else if(!state.shouldTickState) {
state.shouldTickState = true;
}
}
public void tickStandingPlayer(final CarriageContraptionEntity contraption, final Player player) {
if(player.getVehicle() != null) return;

var state = states.get(player.getUUID());

if (state == null || !Objects.equals(state.entity, contraption)) {
var persp = (Perspective) Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player);
state = new RotationState(contraption, true, false);
states.put(player.getUUID(), state);
persp.enable(state.entity.pitch, state.entity.yaw);
} else {
state.ticksSinceLastUpdate = 0;
}
}

Expand All @@ -104,6 +104,14 @@ private void tickState(LocalPlayer player) {
persp.setYaw(state.entity.yaw);
player.setYRot(player.getYRot() + state.getYawDelta());
player.setYBodyRot(player.getYRot());

if(state.standingState && !state.isMounted) {
state.ticksSinceLastUpdate += 1;

if(state.ticksSinceLastUpdate > 5) {
state.shouldTickState = false;
}
}
}

public void onTickPlayer(final Player player) {
Expand All @@ -115,12 +123,11 @@ public void onTickPlayer(final Player player) {
} else {
var persp = (Perspective) Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player);
persp.diminish();
}

if(localPlayer.onGround() && state.standingState) {
var persp = (Perspective) Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player);
states.remove(player.getUUID());
persp.disable();
if(persp.diminished()) {
states.remove(player.getUUID());
persp.disable();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
package net.derfruhling.minecraft.create.trainperspective;

import net.minecraft.client.Camera;
import net.minecraft.util.Mth;

public class MixinUtil {
private MixinUtil() {}

public static Camera3D asCamera3D(Camera camera) {
return (Camera3D) camera;
}

private static float invCos(float x) {
return Mth.cos(x + Mth.PI);
}

public static float applyDirectionXRotChange(Perspective persp, float xRot, float yRot, float f) {
return xRot - persp.getLean(f) * Mth.sin((persp.getYaw(f) - yRot) * Mth.DEG_TO_RAD);
}

public static float getExtraYRot(Perspective persp, float xRot, float yRot, float f) {
return persp.getLean(f) * (xRot / 90.0f) * invCos((persp.getYaw(f) - yRot) * Mth.DEG_TO_RAD);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package net.derfruhling.minecraft.create.trainperspective;

import net.minecraft.util.Mth;

public interface Perspective {
void enable(float initialLean, float initialYaw);
void disable();
boolean isEnabled();
void setLean(float lean);
void setYaw(float yaw);
float getLean();
float getYaw();
float getLean(float f);
float getYaw(float f);

default void diminish() {
setLean(getLean() * 0.97f);
setYaw(getYaw() * 0.97f);
setLean(getLean(1.0f) * 0.9f);
}

default boolean diminished() {
return Mth.abs(getLean(1.0f)) < 0.01f;
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
package net.derfruhling.minecraft.create.trainperspective.mixin;

import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.ContraptionCollider;
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;
import net.derfruhling.minecraft.create.trainperspective.CreateTrainPerspectiveMod;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
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.CallbackInfo;

@Mixin(ContraptionCollider.class)
public class ContraptionColliderMixin {
@Inject(method = "collideEntities", at = @At("HEAD"), remap = false)
private static void saveClientPlayerFromClipping(
AbstractContraptionEntity contraptionEntity,
@Mixin(AbstractContraptionEntity.class)
@Environment(EnvType.CLIENT)
public class AbstractContraptionEntityMixin {
@SuppressWarnings({"ConstantValue", "UnreachableCode"})
@Inject(method = "registerColliding", at = @At("TAIL"), remap = false)
private void onRegisterColliding(
Entity entity,
CallbackInfo ci
) {
if(contraptionEntity instanceof CarriageContraptionEntity carriage) {
CreateTrainPerspectiveMod.INSTANCE.tickStandingPlayers(carriage);
if((Object) this instanceof CarriageContraptionEntity carriage && entity instanceof Player player) {
CreateTrainPerspectiveMod.INSTANCE.tickStandingPlayer(carriage, player);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,72 @@

import com.llamalad7.mixinextras.sugar.Local;
import net.derfruhling.minecraft.create.trainperspective.Camera3D;
import net.derfruhling.minecraft.create.trainperspective.MixinUtil;
import net.derfruhling.minecraft.create.trainperspective.Perspective;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import org.joml.Quaternionf;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(Camera.class)
@Implements({@Interface(iface = Camera3D.class, prefix = "c3d$")})
@Environment(EnvType.CLIENT)
public abstract class CameraMixin {
@Shadow private Entity entity;
@Unique private float ctp$zRot;
@Unique private float ctp$extraYRot;

@Shadow protected abstract void setRotation(float f, float g);

@Shadow @Final private Quaternionf rotation;

@ModifyArg(method = "setRotation", at = @At(value = "INVOKE", target = "Lorg/joml/Quaternionf;rotationYXZ(FFF)Lorg/joml/Quaternionf;"), index = 2)
private float modifyRoll(float original) {
return original + ctp$zRot;
}

@Inject(method = "setRotation", at = @At(value = "INVOKE", target = "Lorg/joml/Quaternionf;rotationYXZ(FFF)Lorg/joml/Quaternionf;", shift = At.Shift.AFTER))
private void modifyQuaternion(float f, float g, CallbackInfo ci) {
this.rotation.rotateY(ctp$extraYRot);
}

@Unique
public float c3d$getZRot() {
return this.ctp$zRot;
}

@Unique
public float c3d$getExtraYRot() {
return this.ctp$extraYRot;
}

@Redirect(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setRotation(FF)V"))
public void modifyRotationsPrimary(Camera instance, float y, float x, @Local(argsOnly = true, ordinal = 1) boolean isThirdPerson) {
public void modifyRotationsPrimary(Camera instance,
float y,
float x,
@Local(argsOnly = true, ordinal = 0) boolean isThirdPerson,
@Local(argsOnly = true) float f) {
if(entity instanceof LocalPlayer player && !isThirdPerson) {
var persp = (Perspective) Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player);
ctp$zRot = persp.getLean() * Mth.cos((persp.getYaw() - y) * Mth.DEG_TO_RAD);
setRotation(y, x - persp.getLean() * Mth.sin((persp.getYaw() - y) * Mth.DEG_TO_RAD));
ctp$zRot = persp.getLean(f) * Mth.cos((persp.getYaw(f) - y) * Mth.DEG_TO_RAD);
ctp$extraYRot = MixinUtil.getExtraYRot(persp, x, y, f);
setRotation(
y,
MixinUtil.applyDirectionXRotChange(persp, x, y, f)
);
} else {
ctp$zRot = 0;
ctp$extraYRot = 0;
setRotation(y, x);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.derfruhling.minecraft.create.trainperspective.mixin;

import com.simibubi.create.foundation.utility.RaycastHelper;
import net.derfruhling.minecraft.create.trainperspective.MixinUtil;
import net.derfruhling.minecraft.create.trainperspective.Perspective;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;

@Mixin(RaycastHelper.class)
public class CreateRaycastHelperMixin {
@ModifyVariable(method = "getTraceTarget", at = @At("STORE"), index = 4)
private static float modifyXRot(float value, Player player) {
if(Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player) instanceof Perspective persp) {
return MixinUtil.applyDirectionXRotChange(persp, value, player.getYRot(), 1.0f);
} else return value;
}

@ModifyVariable(method = "getTraceTarget", at = @At("STORE"), index = 5)
private static float modifyYRot(float value, Player player) {
if(Minecraft.getInstance().getEntityRenderDispatcher().getRenderer(player) instanceof Perspective persp) {
return value + MixinUtil.getExtraYRot(persp, player.getXRot(), value, 1.0f);
} else return value;
}
}
Loading

0 comments on commit 5305768

Please sign in to comment.