Skip to content

Commit

Permalink
feature: Interpolate target vehicle head movements (#8)
Browse files Browse the repository at this point in the history
* Interpolate armour stand head movement when enabled

* Remove unneeded field from mixin

* Remove unneeded null checks

Intellij was just running old code and gaslighting me about it

* Update demo video in readme
  • Loading branch information
lucyydotp authored Jun 7, 2024
1 parent 4f60ca1 commit eb1344f
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Passenger Perspective (or PaPers for short) is a Fabric mod that improves the camera for theme park servers.

### Demo video (click to watch)
[![demo video](https://img.youtube.com/vi/4Bu7smcJ1GI/0.jpg)](https://youtu.be/4Bu7smcJ1GI)
[![demo video](https://img.youtube.com/vi/TC_92oMWGjE/0.jpg)](https://youtu.be/https://youtu.be/TC_92oMWGjE)

# How to use

Expand Down
15 changes: 14 additions & 1 deletion src/main/java/me/lucyydotp/papers/ArmorStandExt.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,18 @@
import net.minecraft.core.Rotations;

public interface ArmorStandExt {
Rotations paper$lastHeadRot();
/**
* Gets the armour stand's head rotation from the previous tick.
*/
Rotations papers$lastHeadRot();

/**
* Gets whether this armour stand should interpolate movement for its head pose.
*/
boolean papers$shouldInterpolateHead();

/**
* Sets whether this armour stand should interpolate movement for its head pose.
*/
void papers$shouldInterpolateHead(boolean value);
}
3 changes: 2 additions & 1 deletion src/main/java/me/lucyydotp/papers/CameraPerspectiveMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ final class ArmorStandHead implements CameraPerspectiveMode {

public ArmorStandHead(ArmorStand armorStand) {
this.armorStand = armorStand;
((ArmorStandExt) armorStand).papers$shouldInterpolateHead(true);
this.creationTime = armorStand.level.getGameTime();
this.lastYRot = armorStand.yHeadRot;
}
Expand All @@ -63,7 +64,7 @@ public void transform(PoseStack cameraPoseStack, float tickProgress, long time)
lastYRot = lerpedYRot;

final var pose = armorStand.getHeadPose();
final var lastPose = ((ArmorStandExt) armorStand).paper$lastHeadRot();
final var lastPose = ((ArmorStandExt) armorStand).papers$lastHeadRot();
final var forward = Vec3.directionFromRotation(0, lerpedYRot).toVector3f();

// fixme: properly slerp instead of doing whatever this is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package me.lucyydotp.papers.mixin;

import me.lucyydotp.papers.ArmorStandExt;
import net.minecraft.client.model.ArmorStandArmorModel;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.decoration.ArmorStand;
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(ArmorStandArmorModel.class)
public abstract class ArmorStandArmorModelMixin extends HumanoidModel<ArmorStand> {

public ArmorStandArmorModelMixin(ModelPart modelPart) {
super(modelPart);
}

@Inject(
method = "setupAnim(Lnet/minecraft/world/entity/decoration/ArmorStand;FFFFF)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/model/geom/ModelPart;copyFrom(Lnet/minecraft/client/model/geom/ModelPart;)V"
)
)
public void interpolateHeadIfNeeded(ArmorStand armorStand, float f, float g, float h, float i, float j, CallbackInfo ci) {
if (((ArmorStandExt) armorStand).papers$shouldInterpolateHead()) {
final var partialTickTime = h - (int) h;

final var lastPose = ((ArmorStandExt) armorStand).papers$lastHeadRot();

this.head.xRot = (float) Math.toRadians(Mth.rotLerp(
partialTickTime,
lastPose.getX(),
armorStand.getHeadPose().getX()
));

this.head.yRot = (float) Math.toRadians(Mth.rotLerp(
partialTickTime,
lastPose.getY(),
armorStand.getHeadPose().getY()
));

this.head.zRot = (float) Math.toRadians(Mth.rotLerp(
partialTickTime,
lastPose.getZ(),
armorStand.getHeadPose().getZ()
));
}
}
}
26 changes: 21 additions & 5 deletions src/main/java/me/lucyydotp/papers/mixin/ArmorStandMixin.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package me.lucyydotp.papers.mixin;

import com.llamalad7.mixinextras.sugar.Local;
import me.lucyydotp.papers.ArmorStandExt;
import me.lucyydotp.papers.CameraPerspectiveMode;
import me.lucyydotp.papers.PassengerPerspectiveMod;
import net.minecraft.core.Rotations;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.*;
Expand All @@ -15,7 +15,7 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ArmorStand.class)
public abstract class ArmorStandMixin extends Entity implements ArmorStandExt {
public abstract class ArmorStandMixin extends LivingEntity implements ArmorStandExt {

@Shadow
@Final
Expand All @@ -24,10 +24,14 @@ public abstract class ArmorStandMixin extends Entity implements ArmorStandExt {
@Shadow
private Rotations headPose;

@SuppressWarnings("UnusedAssignment")
@Unique
private Rotations papers$lastHeadRot = DEFAULT_HEAD_POSE;

public ArmorStandMixin(EntityType<?> entityType, Level level) {
@Unique
private boolean papers$shouldInterpolateHead;

public ArmorStandMixin(EntityType<? extends LivingEntity> entityType, Level level) {
super(entityType, level);
throw new AbstractMethodError("Mixin abstract class constructor");
}
Expand All @@ -37,7 +41,9 @@ public ArmorStandMixin(EntityType<?> entityType, Level level) {
at = @At("HEAD")
)
public void clearLastHeadPose(CallbackInfo ci) {
papers$lastHeadRot = headPose;
if (headPose != null) {
papers$lastHeadRot = headPose;
}
}

/**
Expand All @@ -55,7 +61,17 @@ public boolean isCurrentlyGlowing() {
}

@Override
public Rotations paper$lastHeadRot() {
public Rotations papers$lastHeadRot() {
return papers$lastHeadRot;
}

@Override
public boolean papers$shouldInterpolateHead() {
return papers$shouldInterpolateHead;
}

@Override
public void papers$shouldInterpolateHead(boolean value) {
papers$shouldInterpolateHead = value;
}
}
6 changes: 3 additions & 3 deletions src/main/resources/passenger-perspective.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"required": true,
"package": "me.lucyydotp.papers.mixin",
"client": [
"GameRendererMixin",
"ArmorStandMixin"

"ArmorStandArmorModelMixin",
"ArmorStandMixin",
"GameRendererMixin"
]
}

0 comments on commit eb1344f

Please sign in to comment.