From 7b6093624b8f263477ff81be88d4257a4a40cd26 Mon Sep 17 00:00:00 2001 From: Fluffy Jenkins <31552479+FluffyJenkins@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:56:20 +0000 Subject: [PATCH] Create Compat(1.19.2): Fixed track outlines and picking (#693) * Fixed track outlines on ships and fixed interaction bug when near curved track and a ship * Moved around mixins to disable track outline mixins if interactive is installed * logging --- .../ValkyrienCommonMixinConfigPlugin.java | 10 ++ .../create/client/MixinTrackBlockOutline.java | 85 ++++++----- .../trackOutlines/MixinBigOutlines.java | 92 ++++++++++++ .../trackOutlines/MixinTrackBlockOutline.java | 134 ++++++++++++++++++ .../valkyrienskies-common.mixins.json | 2 + 5 files changed, 286 insertions(+), 37 deletions(-) create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinBigOutlines.java create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinTrackBlockOutline.java diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienCommonMixinConfigPlugin.java b/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienCommonMixinConfigPlugin.java index 3bc09f14e..ba5ad1b0a 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienCommonMixinConfigPlugin.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienCommonMixinConfigPlugin.java @@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.Mixins; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import org.spongepowered.asm.service.MixinService; import org.valkyrienskies.mod.compat.VSRenderer; /** @@ -72,6 +73,15 @@ public boolean shouldApplyMixin(final String s, final String mixinClassName) { if (mixinClassName.contains("org.valkyrienskies.mod.mixin.feature.render_pathfinding")) { return PATH_FINDING_DEBUG; } + if (mixinClassName.contains("org.valkyrienskies.mod.mixin.mod_compat.create.client.trackOutlines")) { + //interactive has its own track outline stuff so disable fixed version of VS2's track outline stuff + if (classExists("org.valkyrienskies.create_interactive.mixin.client.MixinTrackBlockOutline")) { + MixinService.getService().getLogger("mixin") + .info("[VS2] found Interactive, disabling VS2's trackOutline Compat - " + + mixinClassName.substring(mixinClassName.lastIndexOf(".") + 1)); + return false; + } + } return true; } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinTrackBlockOutline.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinTrackBlockOutline.java index 69d74d550..0eb6df4d8 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinTrackBlockOutline.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinTrackBlockOutline.java @@ -1,82 +1,93 @@ package org.valkyrienskies.mod.mixin.mod_compat.create.client; import com.simibubi.create.content.trains.track.TrackBlockOutline; +import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.utility.RaycastHelper; -import java.util.List; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult.Type; import net.minecraft.world.phys.Vec3; -import org.joml.Vector3d; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.valkyrienskies.core.api.ships.Ship; import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @Mixin(TrackBlockOutline.class) public class MixinTrackBlockOutline { + + @Shadow + public static BezierPointSelection result; + @Unique + private static boolean valkyrienskies$toShip = false; @Unique - private static boolean isShip = false; + private static Ship valkyrienskies$ship; @Unique - private static BlockPos shipBlockPos; + private static Vec3 valkyrienskies$originalOrigin; @Inject( - method = "pickCurves", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/player/LocalPlayer;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;" - ), locals = LocalCapture.CAPTURE_FAILHARD + method = "pickCurves", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;" + ), locals = LocalCapture.CAPTURE_FAILHARD ) private static void stuff(final CallbackInfo ci, final Minecraft mc) { - if (mc.hitResult != null && mc.level != null && mc.hitResult.getType() == Type.BLOCK) { - shipBlockPos = ((BlockHitResult) mc.hitResult).getBlockPos(); - - final List<Vector3d> - ships = VSGameUtilsKt.transformToNearbyShipsAndWorld(mc.level, shipBlockPos.getX(), shipBlockPos.getY(), - shipBlockPos.getZ(), 10); - isShip = !ships.isEmpty(); + if (mc.hitResult != null && mc.level != null && mc.player != null) { + valkyrienskies$toShip = false; + final boolean playerOnShip = VSGameUtilsKt.isBlockInShipyard(mc.level, mc.player.getOnPos()); + final boolean hitResultOnShip = + VSGameUtilsKt.isBlockInShipyard(mc.level, ((BlockHitResult) mc.hitResult).getBlockPos()); + if (playerOnShip && !hitResultOnShip) { + valkyrienskies$ship = VSGameUtilsKt.getShipManagingPos(mc.level, mc.player.getOnPos()); + //if blockstate is air then transform to ship + valkyrienskies$toShip = mc.level.getBlockState(BlockPos.containing(mc.hitResult.location)).isAir(); + } else if (hitResultOnShip) { + valkyrienskies$toShip = true; + valkyrienskies$ship = + VSGameUtilsKt.getShipManagingPos(mc.level, ((BlockHitResult) mc.hitResult).getBlockPos()); + } } } @Redirect( - method = "pickCurves()V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/player/LocalPlayer;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;" - ) + method = "pickCurves", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;" + ) ) private static Vec3 redirectedOrigin(final LocalPlayer instance, final float v) { final Vec3 eyePos = instance.getEyePosition(v); - if (isShip) { - final List<Vector3d> - ships = VSGameUtilsKt.transformToNearbyShipsAndWorld(instance.level, eyePos.x, eyePos.y, eyePos.z, 10); - if (ships.isEmpty()) { - return eyePos; - } - final Vector3d tempVec = ships.get(0); - return new Vec3(tempVec.x, tempVec.y, tempVec.z); + if (valkyrienskies$toShip) { + valkyrienskies$originalOrigin = eyePos; + return VectorConversionsMCKt.toMinecraft( + valkyrienskies$ship.getWorldToShip().transformPosition(VectorConversionsMCKt.toJOML(eyePos))); } else { return eyePos; } } @Redirect( - method = "pickCurves()V", - at = @At( - value = "INVOKE", - target = "Lcom/simibubi/create/foundation/utility/RaycastHelper;getTraceTarget(Lnet/minecraft/world/entity/player/Player;DLnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;" - ) + method = "pickCurves", + at = @At( + value = "INVOKE", + target = "Lcom/simibubi/create/foundation/utility/RaycastHelper;getTraceTarget(Lnet/minecraft/world/entity/player/Player;DLnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;" + ) ) private static Vec3 redirectedTarget(final Player playerIn, final double range, final Vec3 origin) { - if (isShip) { - return new Vec3(shipBlockPos.getX(), shipBlockPos.getY(), shipBlockPos.getZ()); + if (valkyrienskies$toShip) { + return VectorConversionsMCKt.toMinecraft( + valkyrienskies$ship.getWorldToShip().transformPosition(VectorConversionsMCKt.toJOML( + RaycastHelper.getTraceTarget(playerIn, range, valkyrienskies$originalOrigin)))); } else { return RaycastHelper.getTraceTarget(playerIn, range, origin); } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinBigOutlines.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinBigOutlines.java new file mode 100644 index 000000000..94ffa3406 --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinBigOutlines.java @@ -0,0 +1,92 @@ +package org.valkyrienskies.mod.mixin.mod_compat.create.client.trackOutlines; + +import com.simibubi.create.foundation.block.BigOutlines; +import com.simibubi.create.foundation.utility.RaycastHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult.Type; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; + +@Mixin(BigOutlines.class) +public class MixinBigOutlines { + @Unique + private static boolean valkyrienskies$toShip = false; + + @Unique + private static Ship valkyrienskies$ship; + @Unique + private static Vec3 valkyrienskies$originalOrigin; + + @Inject( + method = "pick", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;" + ), locals = LocalCapture.CAPTURE_FAILHARD + ) + private static void stuff(final CallbackInfo ci, final Minecraft mc) { + if (mc.hitResult != null && mc.level != null && mc.player != null && mc.hitResult.getType() == Type.BLOCK) { + valkyrienskies$toShip = false; + final boolean playerOnShip = VSGameUtilsKt.isBlockInShipyard(mc.level, mc.player.getOnPos()); + final boolean hitResultOnShip = + VSGameUtilsKt.isBlockInShipyard(mc.level, ((BlockHitResult) mc.hitResult).getBlockPos()); + if (playerOnShip && !hitResultOnShip) { + valkyrienskies$ship = VSGameUtilsKt.getShipManagingPos(mc.level, mc.player.getOnPos()); + //if blockstate is air then transform to ship + valkyrienskies$toShip = mc.level.getBlockState(BlockPos.containing(mc.hitResult.location)).isAir(); + } else if (hitResultOnShip) { + valkyrienskies$toShip = true; + valkyrienskies$ship = + VSGameUtilsKt.getShipManagingPos(mc.level, ((BlockHitResult) mc.hitResult).getBlockPos()); + } + } + } + + @Redirect( + method = "pick", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;getEyePosition(F)Lnet/minecraft/world/phys/Vec3;" + ) + ) + private static Vec3 redirectedOrigin(final LocalPlayer instance, final float v) { + final Vec3 eyePos = instance.getEyePosition(v); + if (valkyrienskies$toShip) { + valkyrienskies$originalOrigin = eyePos; + return VectorConversionsMCKt.toMinecraft( + valkyrienskies$ship.getWorldToShip().transformPosition(VectorConversionsMCKt.toJOML(eyePos))); + } else { + return eyePos; + } + } + + @Redirect( + method = "pick", + at = @At( + value = "INVOKE", + target = "Lcom/simibubi/create/foundation/utility/RaycastHelper;getTraceTarget(Lnet/minecraft/world/entity/player/Player;DLnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;" + ) + ) + private static Vec3 redirectedTarget(final Player playerIn, final double range, final Vec3 origin) { + if (valkyrienskies$toShip) { + return VectorConversionsMCKt.toMinecraft( + valkyrienskies$ship.getWorldToShip().transformPosition(VectorConversionsMCKt.toJOML( + RaycastHelper.getTraceTarget(playerIn, range, valkyrienskies$originalOrigin)))); + } else { + return RaycastHelper.getTraceTarget(playerIn, range, origin); + } + } +} diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinTrackBlockOutline.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinTrackBlockOutline.java new file mode 100644 index 000000000..1b8fbad96 --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/trackOutlines/MixinTrackBlockOutline.java @@ -0,0 +1,134 @@ +package org.valkyrienskies.mod.mixin.mod_compat.create.client.trackOutlines; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.simibubi.create.content.trains.track.TrackBlockOutline; +import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import org.joml.Quaterniond; +import org.joml.Vector3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.core.impl.game.ships.ShipObjectClient; +import org.valkyrienskies.mod.common.VSClientGameUtils; +import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; + +@Mixin(TrackBlockOutline.class) +public class MixinTrackBlockOutline { + @Unique + private static Vec3 valkyrienskies$cameraVec3; + @Unique + private static Vec3 valkyrienskies$vec; + @Unique + private static Vec3 valkyrienskies$angles; + + @Inject(method = "drawCurveSelection", + at = @At(value = "INVOKE", + target = "Lcom/simibubi/create/content/trains/track/TrackBlockOutline$BezierPointSelection;angles()Lnet/minecraft/world/phys/Vec3;"), + locals = LocalCapture.CAPTURE_FAILHARD) + private static void harvestDrawCurveSelection(final PoseStack ms, final MultiBufferSource buffer, final Vec3 camera, + final CallbackInfo ci, final Minecraft mc, + final BezierPointSelection result, final VertexConsumer vb, final Vec3 vec) { + valkyrienskies$cameraVec3 = camera; + valkyrienskies$vec = result.vec(); + valkyrienskies$angles = result.angles(); + } + @ModifyArg(method = "drawCurveSelection", + at = @At(value = "INVOKE", + target = "Lcom/simibubi/create/content/trains/track/TrackBlockOutline;renderShape(Lnet/minecraft/world/phys/shapes/VoxelShape;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Ljava/lang/Boolean;)V"), + index = 1) + private static PoseStack redirectTransformStackTranslate(final PoseStack ms) { + + final Level level = Minecraft.getInstance().level; + if (level != null && valkyrienskies$vec != null) { + final ShipObjectClient ship; + if ((ship = (ShipObjectClient) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$vec)) != null) { + final Quaterniond rotation = new Quaterniond().identity(); + final Quaterniond yawQuat = new Quaterniond().rotateY(valkyrienskies$angles.y); + final Quaterniond pitchQuat = new Quaterniond().rotateX(valkyrienskies$angles.x); + + yawQuat.mul(pitchQuat, rotation); + ship.getRenderTransform().getShipToWorldRotation().mul(rotation, rotation); + + final Vector3d worldVec = ship.getRenderTransform().getShipToWorld() + .transformPosition( + new Vector3d(valkyrienskies$vec.x, valkyrienskies$vec.y + .125, valkyrienskies$vec.z), + new Vector3d()); + + ms.popPose(); + ms.pushPose(); + ms.translate(worldVec.x - valkyrienskies$cameraVec3.x, + worldVec.y - valkyrienskies$cameraVec3.y, + worldVec.z - valkyrienskies$cameraVec3.z); + ms.mulPose(VectorConversionsMCKt.toFloat(rotation)); + ms.translate(-.5, -.125f, -.5); + } + } + return ms; + } + + @Unique + private static Camera valkyrienskies$info; + @Unique + private static BlockHitResult valkyrienskies$hitResult; + + @ModifyArg(method = "drawCustomBlockSelection", at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/level/border/WorldBorder;isWithinBounds(Lnet/minecraft/core/BlockPos;)Z")) + private static BlockPos modIsWithinBounds(final BlockPos blockPos) { + final Level level = Minecraft.getInstance().level; + if (level != null) { + final Ship ship; + if ((ship = VSGameUtilsKt.getShipManagingPos(level, blockPos)) != null) { + return BlockPos.containing(VectorConversionsMCKt.toMinecraft(ship.getShipToWorld() + .transformPosition(VectorConversionsMCKt.toJOMLD(blockPos)))); + } + } + return blockPos; + } + + @Inject(method = "drawCustomBlockSelection", + at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;translate(DDD)V")) + private static void harvest(final LevelRenderer context, final Camera info, final HitResult hitResult, + final float partialTicks, + final PoseStack ms, final MultiBufferSource buffers, final CallbackInfoReturnable<Boolean> cir) { + valkyrienskies$info = info; + valkyrienskies$hitResult = (BlockHitResult) hitResult; + } + + @Redirect(method = "drawCustomBlockSelection", + at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;translate(DDD)V")) + private static void redirectTranslate(final PoseStack instance, final double d, final double e, final double f) { + final Level level = Minecraft.getInstance().level; + if (level != null) { + final ShipObjectClient ship; + if ((ship = (ShipObjectClient) VSGameUtilsKt.getShipManagingPos(level, + valkyrienskies$hitResult.getBlockPos())) != null) { + final Vec3 camPos = valkyrienskies$info.getPosition(); + VSClientGameUtils.transformRenderWithShip(ship.getRenderTransform(), instance, + valkyrienskies$hitResult.getBlockPos(), + camPos.x, camPos.y, camPos.z); + } else { + instance.translate(d, e, f); + } + } else { + instance.translate(d, e, f); + } + } +} diff --git a/common/src/main/resources/valkyrienskies-common.mixins.json b/common/src/main/resources/valkyrienskies-common.mixins.json index 24a97da23..925b09556 100644 --- a/common/src/main/resources/valkyrienskies-common.mixins.json +++ b/common/src/main/resources/valkyrienskies-common.mixins.json @@ -160,6 +160,8 @@ "mod_compat.create.client.MixinTileEntityRenderHelper", "mod_compat.create.client.MixinTrackBlockOutline", "mod_compat.create.client.MixinTrainRelocator", + "mod_compat.create.client.trackOutlines.MixinBigOutlines", + "mod_compat.create.client.trackOutlines.MixinTrackBlockOutline", "mod_compat.create.client.MixinValueBox", "mod_compat.flywheel.InstancingEngineAccessor", "mod_compat.flywheel.MixinBlockEntityInstanceManager",