Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show Ridden Entities in the Player Model HUD, Allow Potion Blacklisting #134

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 142 additions & 11 deletions src/main/java/io/github/darkkronicle/kronhud/gui/hud/PlayerHud.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
Expand All @@ -28,15 +30,22 @@ public class PlayerHud extends BoxHudEntry {
private final KronDouble rotation = new KronDouble("rotation", ID.getPath(), 0, 0, 360);
private final KronBoolean dynamicRotation = new KronBoolean("dynamicrotation", ID.getPath(), true);

private final KronBoolean boatFacing = new KronBoolean("boatfacing", ID.getPath(), false);

private float lastYawOffset = 0;
private float yawOffset = 0;
private float lastYOffset = 0;
private float yOffset = 0;

// this is for smoothing on boats, since boats don't have a yaw delta
private float currentYaw = 0;
private float lastYaw = 0;


public PlayerHud() {
super(62, 94, true);
KronHudHooks.PLAYER_DIRECTION_CHANGE.register(this::onPlayerDirectionChange);
KronHudHooks.MOUNT_DIRECTION_CHANGE.register(this::onMountDirectionChange);
}

@Override
Expand All @@ -53,6 +62,14 @@ public void renderPlayer(double x, double y, float delta) {
if (client.player == null) {
return;
}
Entity player = client.player;
Entity baseVehicle = getBaseVehicle(player);

float scaleFraction = 1 / Math.max(getRenderWidth(baseVehicle), getRenderHeight(baseVehicle) / 2.5f);
float scale = getScale() * 40;
float scaleSub = scale * (1 - scaleFraction);
y -= 86 * scaleSub / 80.0;
scale -= scaleSub;

float lerpY = (lastYOffset + ((yOffset - lastYOffset) * delta));

Expand All @@ -64,18 +81,24 @@ public void renderPlayer(double x, double y, float delta) {
RenderSystem.applyModelViewMatrix();
MatrixStack nextStack = new MatrixStack();
nextStack.translate(0, 0, 1000);
float scale = getScale() * 40;
nextStack.scale(scale, scale, scale);
Quaternionf quaternion = RotationAxis.POSITIVE_Z.rotationDegrees(180);

nextStack.multiply(quaternion);
// Rotate to whatever is wanted. Also make sure to offset the yaw
float deltaYaw = client.player.getYaw(delta);
if (dynamicRotation.getValue()) {
deltaYaw -= (lastYawOffset + ((yawOffset - lastYawOffset) * delta));
if (isInBoat(player) && boatFacing.getValue()) { // the camera faces the boat if the boat is the focus
float deltaYaw = player.getVehicle().getYaw(delta);
if (dynamicRotation.getValue()) {
deltaYaw -= (lastYawOffset + ((yawOffset - lastYawOffset) * delta));
}
nextStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(deltaYaw - 180 + rotation.getValue().floatValue()));
} else { // regular player-facing camera
float deltaYaw = client.player.getYaw(delta);
if (dynamicRotation.getValue()) {
deltaYaw -= (lastYawOffset + ((yawOffset - lastYawOffset) * delta));
}
nextStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(deltaYaw - 180 + rotation.getValue().floatValue()));
}
nextStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(deltaYaw - 180 + rotation.getValue().floatValue()));

// Save these to set them back later
float pastYaw = client.player.getYaw();
float pastPrevYaw = client.player.prevYaw;
Expand All @@ -86,21 +109,128 @@ public void renderPlayer(double x, double y, float delta) {
renderer.setRenderShadows(false);

VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
renderMounts(
baseVehicle,
baseVehicle.getX() - player.getX(),
baseVehicle.getY() - player.getY(),
baseVehicle.getZ() - player.getZ(),
delta,
renderer,
nextStack,
immediate
);

renderer.render(client.player, 0, 0, 0, 0, delta, nextStack, immediate, 15728880);
immediate.draw();
renderer.setRenderShadows(true);
matrixStack.pop();

client.player.setYaw(pastYaw);
client.player.prevYaw = pastPrevYaw;
player.setYaw(pastYaw);
player.prevYaw = pastPrevYaw;

RenderSystem.applyModelViewMatrix();
DiffuseLighting.enableGuiDepthLighting();
}

private Entity getBaseVehicle(Entity entity) {
if (entity.hasVehicle()) {
return getBaseVehicle(entity.getVehicle());
} else {
return entity;
}
}

private boolean isInBoat(Entity entity) {
if (entity.hasVehicle()) {
Entity vehicle = entity.getVehicle();
return vehicle.getType() == EntityType.BOAT || vehicle.getType() == EntityType.CHEST_BOAT;
} else {
return false;
}
}

/**
* This returns the stack height (in blocks) of the mounted entity stack this entity is the base of
* (or just the height of the entity if they aren't part of any stack)
*/
private float getRenderHeight(Entity entity) {
float renderHeight;
if (entity == client.player && !client.player.hasVehicle()) {
renderHeight = 2.5f;
} else {
renderHeight = (float) entity.getVisibilityBoundingBox().getYLength();
}
if (entity.hasPassengers()) {
float maxPassengerHeight = Float.NEGATIVE_INFINITY;
for (Entity other : entity.getPassengerList()) {
double relativeY = other.getY() - entity.getY();
maxPassengerHeight = Math.max(getRenderHeight(other) + (float) relativeY, maxPassengerHeight);
}
renderHeight += maxPassengerHeight;
}
return renderHeight;
}

/**
* Same as getRenderHeight, but for width
*/
private float getRenderWidth(Entity entity) {
float renderWidth = (float)Math.max(
entity.getVisibilityBoundingBox().getXLength(),
entity.getVisibilityBoundingBox().getZLength()
);
for (Entity other : entity.getPassengerList()) {
renderWidth = Math.max(getRenderWidth(other),renderWidth);
}
return renderWidth;
}

/**
* Recursively render everything in the entity stack rooted at this entity
*/
private void renderMounts(Entity entity, double xOffset, double yOffset, double zOffset, float delta, EntityRenderDispatcher renderer, MatrixStack nextStack, VertexConsumerProvider.Immediate immediate) {
boolean isBoat = (entity.getType() == EntityType.BOAT || entity.getType() == EntityType.CHEST_BOAT);
renderer.render(
entity,
xOffset,
yOffset,
zOffset,
isBoat ? entity.getYaw(delta) : 0,
delta,
nextStack,
immediate,
15728880
);
for (Entity other : entity.getPassengerList()) {
renderMounts(
other,
xOffset + (other.getX() - entity.getX()),
yOffset + (other.getY() - entity.getY()),
zOffset + (other.getZ() - entity.getZ()),
delta,
renderer,
nextStack,
immediate
);
}
}

public void onPlayerDirectionChange(float prevPitch, float prevYaw, float pitch, float yaw) {
yawOffset += (yaw - prevYaw) / 2;
if (!(boatFacing.getValue() && isInBoat(client.player))) {
yawOffset += (yaw - prevYaw) / 2;
}
}

private float mod (float a, float b) {
return a - (float)Math.floor(a / b) * b;
}

public void onMountDirectionChange(float yaw) {
if (boatFacing.getValue() && isInBoat(client.player)) {
lastYaw = currentYaw;
currentYaw = yaw;
float difference = mod((currentYaw - lastYaw + 180), 360) - 180;
yawOffset += difference / 2;
}
}

@Override
Expand All @@ -123,7 +253,7 @@ public void tick() {
} else if (client.player != null && client.player.isFallFlying()) {
// Elytra!

float j = (float)client.player.getRoll() + 1;
float j = (float) client.player.getRoll() + 1;
float k = MathHelper.clamp(j * j / 100.0F, 0.0F, 1.0F);

float pitch = k * (-90.0F - client.player.getPitch()) + 90;
Expand Down Expand Up @@ -153,6 +283,7 @@ public boolean movable() {
public List<KronConfig<?>> getConfigurationOptions() {
List<KronConfig<?>> options = super.getConfigurationOptions();
options.add(dynamicRotation);
options.add(boatFacing);
options.add(rotation);
options.add(background);
options.add(backgroundColor);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package io.github.darkkronicle.kronhud.gui.hud;

import com.mojang.blaze3d.systems.RenderSystem;
import io.github.darkkronicle.kronhud.config.DefaultOptions;
import io.github.darkkronicle.kronhud.config.KronBoolean;
import io.github.darkkronicle.kronhud.config.KronConfig;
import io.github.darkkronicle.kronhud.config.KronOptionList;
import io.github.darkkronicle.kronhud.config.*;
import io.github.darkkronicle.kronhud.gui.component.DynamicallyPositionable;
import io.github.darkkronicle.kronhud.gui.entry.TextHudEntry;
import io.github.darkkronicle.kronhud.gui.layout.AnchorPoint;
Expand All @@ -21,6 +18,7 @@
import net.minecraft.util.Identifier;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class PotionsHud extends TextHudEntry implements DynamicallyPositionable {
Expand All @@ -30,6 +28,7 @@ public class PotionsHud extends TextHudEntry implements DynamicallyPositionable
private final KronOptionList<AnchorPoint> anchor = DefaultOptions.getAnchorPoint(AnchorPoint.TOP_LEFT);

private final KronOptionList<CardinalOrder> order = DefaultOptions.getCardinalOrder(CardinalOrder.TOP_DOWN);
private final KronString potionBlacklist = new KronString("potionblacklist",ID.getPath(),"");

private final KronBoolean iconsOnly = new KronBoolean("iconsonly", ID.getPath(), false);

Expand Down Expand Up @@ -62,10 +61,16 @@ private int calculateHeight(List<StatusEffectInstance> effects) {
@Override
public void renderComponent(MatrixStack matrices, float delta) {
List<StatusEffectInstance> effects = new ArrayList<>(client.player.getStatusEffects());
if (effects.isEmpty()) {
List<String> blacklist = Arrays.asList(
potionBlacklist.getValue().replace(" ","").split(",")
);
List<StatusEffectInstance> filteredEffects = effects.stream()
.filter(effect -> !blacklist.contains(effect.getEffectType().getTranslationKey()))
.toList();
if (filteredEffects.isEmpty()) {
return;
}
renderEffects(matrices, effects);
renderEffects(matrices, filteredEffects);
}

private void renderEffects(MatrixStack matrices, List<StatusEffectInstance> effects) {
Expand Down Expand Up @@ -129,6 +134,7 @@ public List<KronConfig<?>> getConfigurationOptions() {
options.add(anchor);
options.add(order);
options.add(iconsOnly);
options.add(potionBlacklist);
return options;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.darkkronicle.kronhud.hooks;

public interface EntityYawCallback {

void onChange(float yaw);

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public class KronHudHooks {
}
));

public static final Event<EntityYawCallback> MOUNT_DIRECTION_CHANGE = EventFactory.createArrayBacked(EntityYawCallback.class, listeners -> (
(yaw) -> {
for (EntityYawCallback listener : listeners) {
listener.onChange(yaw);
}
}
));

public static final Event<KeyBindingCallback.ChangeBind> KEYBIND_CHANGE = EventFactory.createArrayBacked(
KeyBindingCallback.ChangeBind.class, listeners -> (
(key) -> {
Expand All @@ -46,5 +54,4 @@ public class KronHudHooks {
)
);


}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.darkkronicle.kronhud.mixins;

import io.github.darkkronicle.kronhud.hooks.KronHudHooks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -9,13 +10,17 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.List;

@Mixin(Entity.class)
public abstract class MixinEntity {

@Shadow public abstract float getPitch();

@Shadow public abstract float getYaw();

@Shadow public abstract List<Entity> getPassengerList();

@Inject(method = "changeLookDirection", at = @At("HEAD"))
private void updateLookDirection(double mouseDeltaX, double mouseDeltaY, CallbackInfo ci) {
if (mouseDeltaX == 0 && mouseDeltaY == 0) {
Expand All @@ -30,4 +35,11 @@ private void updateLookDirection(double mouseDeltaX, double mouseDeltaY, Callbac
KronHudHooks.PLAYER_DIRECTION_CHANGE.invoker().onChange(prevPitch, prevYaw, pitch, yaw);
}

@Inject(method = "setYaw", at = @At("TAIL"))
private void updateEntityYaw(float yaw, CallbackInfo ci) {
if (this.getPassengerList().contains(MinecraftClient.getInstance().player)) {
KronHudHooks.MOUNT_DIRECTION_CHANGE.invoker().onChange(yaw);
}
}

}
9 changes: 8 additions & 1 deletion src/main/resources/assets/kronhud/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@
"option.kronhud.togglesprint.placeholder.comment": "The Placeholder to use when no keys are pressed/toggled.",
"option.kronhud.playerhud.rotation": "Model Rotation",
"option.kronhud.playerhud.rotation.comment": "The rotation of the model.",
"option.kronhud.playerhud.boatfacing": "Boat Faces Camera",
"option.kronhud.playerhud.boatfacing.comment": "If enabled, the boat faces towards the camera instead of the player when the player rides in a boat.",
"option.kronhud.minwidth": "Minimum Width",
"option.kronhud.irltimehud.dateformat": "Time Format",
"option.kronhud.gametimehud.is12hour": "12-hour Format",
Expand Down Expand Up @@ -228,5 +230,10 @@
"option.kronhud.scoreboardhud.toppadding.comment": "Padding around the title component on the scoreboard",

"option.kronhud.playerhud.dynamicrotation": "Dynamic Rotation",
"option.kronhud.playerhud.dynamicrotation.comment": "Rotation of the player is shown and then slowly turns back to looking straight"
"option.kronhud.playerhud.dynamicrotation.comment": "Rotation of the player is shown and then slowly turns back to looking straight",

"option.kronhud.potionshud.potionblacklist": "Effect Blacklist",
"option.kronhud.potionshud.iconsonly": "Icons Only",
"option.kronhud.potionshud.potionblacklist.comment": "Blacklist potions by translation key (usually effect.minecraft.[effect id]).\nEnter keys as a comma-separated list.",
"option.kronhud.potionshud.iconsonly.comment": "Only display potions as icons (don't show durations)"
}