From eac19c84e2fe89f73e277e1383f3c164c7433829 Mon Sep 17 00:00:00 2001 From: FlamingAssembler <34496536+Endalion@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:12:22 +0800 Subject: [PATCH] Fix Create Schematic placement, rendering on ships (#690) * initial ugly schematic mixins * added javadoc descriptions for the mixins * Fix the other operations and clean up 6 months is a long time huh --------- Co-authored-by: ewoudje <7384674+ewoudje@users.noreply.github.com> --- .../create/client/MixinDeployTool.java | 67 ++++++++++++++++++ .../create/client/MixinSchematicToolBase.java | 70 +++++++++++++++++++ .../client/MixinSchematicTransformation.java | 57 +++++++++++++++ .../valkyrienskies-common.mixins.json | 3 + 4 files changed, 197 insertions(+) create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinDeployTool.java create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicToolBase.java create mode 100644 common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicTransformation.java diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinDeployTool.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinDeployTool.java new file mode 100644 index 000000000..f10487ac3 --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinDeployTool.java @@ -0,0 +1,67 @@ +package org.valkyrienskies.mod.mixin.mod_compat.create.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.schematics.client.tools.DeployTool; +import com.simibubi.create.content.schematics.client.tools.SchematicToolBase; +import com.simibubi.create.foundation.render.SuperRenderTypeBuffer; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.common.VSClientGameUtils; +import org.valkyrienskies.mod.common.VSGameUtilsKt; + +/** + * DeployTool is responsible for the render transform of the placement bounding box (not the preview) + *

+ * Create applies both the camera and bounding-box position in the same PoseStack operation, + * the latter of which does not respect ship-space. + * This mixin cancels the aforementioned operation and injects the fix in front. + */ +@Mixin(value={DeployTool.class}) +public abstract class MixinDeployTool extends SchematicToolBase { + @Redirect( + method = "renderTool(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/simibubi/create/foundation/render/SuperRenderTypeBuffer;Lnet/minecraft/world/phys/Vec3;)V", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/PoseStack;translate(DDD)V", + ordinal = 0 + ) + ) + private void redirectTranslate(PoseStack ms, double _x, double _y, double _z) { + } + + @Inject( + method = "renderTool(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/simibubi/create/foundation/render/SuperRenderTypeBuffer;Lnet/minecraft/world/phys/Vec3;)V", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/PoseStack;translate(DDD)V", + ordinal = 0 + ) + ) + private void mixinRenderTool(PoseStack ms, SuperRenderTypeBuffer buffer, Vec3 camera, CallbackInfo ci) { + float pt = AnimationTickHolder.getPartialTicks(); + double x = Mth.lerp(pt, lastChasingSelectedPos.x, chasingSelectedPos.x); + double y = Mth.lerp(pt, lastChasingSelectedPos.y, chasingSelectedPos.y); + double z = Mth.lerp(pt, lastChasingSelectedPos.z, chasingSelectedPos.z); + Ship ship = VSGameUtilsKt.getShipObjectManagingPos(Minecraft.getInstance().level, x, y, z); + + AABB bounds = schematicHandler.getBounds(); + Vec3 center = bounds.getCenter(); + int centerX = (int) center.x; + int centerZ = (int) center.z; + + if (ship != null) { + VSClientGameUtils.transformRenderWithShip(ship.getTransform(), ms, x - centerX, y, z - centerZ, camera.x, camera.y, camera.z); + } else { + ms.translate(x - centerX - camera.x, y - camera.y, z - centerZ - camera.z); + } + } +} diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicToolBase.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicToolBase.java new file mode 100644 index 000000000..32a196e4e --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicToolBase.java @@ -0,0 +1,70 @@ +package org.valkyrienskies.mod.mixin.mod_compat.create.client; + +import static org.valkyrienskies.mod.common.util.VectorConversionsMCKt.toJOML; +import static org.valkyrienskies.mod.common.util.VectorConversionsMCKt.toMinecraft; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.simibubi.create.content.schematics.client.SchematicTransformation; +import com.simibubi.create.content.schematics.client.tools.SchematicToolBase; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.common.VSGameUtilsKt; + +/** + * SchematicToolBase is responsible for the placement position of the schematic. + */ +@Mixin(value={SchematicToolBase.class}) +public abstract class MixinSchematicToolBase { + /** + * Create uses HitResult::getLocation to get the schematic placement position, which doesn't respect ship-space. + * This mixin conditionally changes it to BlockHitResult::getBlockPos instead which *does* respect ship-space. + * The original behaviour is otherwise not changed. + */ + @Redirect( + method = "updateTargetPos()V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/phys/BlockHitResult;getLocation()Lnet/minecraft/world/phys/Vec3;", + ordinal = 0 + ) + ) + public Vec3 redirectGetLocation(BlockHitResult instance) { + BlockPos b = instance.getBlockPos(); + Ship ship = VSGameUtilsKt.getShipObjectManagingPos(Minecraft.getInstance().level, b); + if (ship != null) { + // The return value is used to form a BlockPos, + // so the vec position within a block should not make a difference + return Vec3.atLowerCornerOf(b); + } else { + return instance.getLocation(); + } + } + + /** + * Create chose to... uh... evaluate the player look in the local space of the transform. That means we need to + * mixin toLocalSpace and transform the player position to the ship-space this schematic is on. + * The original behaviour is otherwise not changed. + */ + @WrapOperation( + method = "updateTargetPos", + at = @At( + value = "INVOKE", + target = "Lcom/simibubi/create/content/schematics/client/SchematicTransformation;toLocalSpace(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;" + ) + ) + public Vec3 wrapLocalSpaceToShip(SchematicTransformation transformation, Vec3 vec, Operation original) { + Ship ship = VSGameUtilsKt.getShipObjectManagingPos(Minecraft.getInstance().level, transformation.getAnchor()); + if (ship != null) { + return original.call(transformation, toMinecraft(ship.getWorldToShip().transformPosition(toJOML(vec)))); + } + + return original.call(transformation, vec); + } +} diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicTransformation.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicTransformation.java new file mode 100644 index 000000000..5c6d76c84 --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/client/MixinSchematicTransformation.java @@ -0,0 +1,57 @@ +package org.valkyrienskies.mod.mixin.mod_compat.create.client; + +import com.jozufozu.flywheel.util.transform.TransformStack; +import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.content.schematics.client.SchematicTransformation; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.world.phys.Vec3; +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; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.common.VSClientGameUtils; +import org.valkyrienskies.mod.common.VSGameUtilsKt; + +/** + * SchematicTransformation is responsible for the render transform of the schematic preview + *

+ * Create applies both the camera and schematic positions in the same operation, the latter of which does not respect ship-space. + * This mixin redirects the operation and fixes it by extracting the position components from the argument. + * I can't think of a better way to get around it. + */ +@Mixin(value = {SchematicTransformation.class}, remap = false) +public abstract class MixinSchematicTransformation { + @Shadow + private BlockPos target; + @Shadow + private Vec3 chasingPos; + @Shadow + private Vec3 prevChasingPos; + + @Redirect( + method = {"applyTransformations(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/phys/Vec3;)V"}, + at = @At( + value = "INVOKE", + target = "Lcom/jozufozu/flywheel/util/transform/TransformStack;translate(Lnet/minecraft/world/phys/Vec3;)Ljava/lang/Object;", + ordinal = 0 + ) + ) + private Object redirectTranslate(TransformStack instance, Vec3 orig) { + PoseStack ms = (PoseStack)instance; + Ship ship = VSGameUtilsKt.getShipObjectManagingPos(Minecraft.getInstance().level, target.getX(), target.getY(), target.getZ()); + + if (ship != null) { + float pt = AnimationTickHolder.getPartialTicks(); + Vec3 pos = VecHelper.lerp(pt, prevChasingPos, chasingPos); + Vec3 camera = pos.subtract(orig); + VSClientGameUtils.transformRenderWithShip(ship.getTransform(), ms, pos.x, pos.y, pos.z, camera.x, camera.y, camera.z); + return instance; + } else { + return instance.translate(orig); + } + } +} diff --git a/common/src/main/resources/valkyrienskies-common.mixins.json b/common/src/main/resources/valkyrienskies-common.mixins.json index 3260c9970..152af005d 100644 --- a/common/src/main/resources/valkyrienskies-common.mixins.json +++ b/common/src/main/resources/valkyrienskies-common.mixins.json @@ -166,6 +166,9 @@ "mod_compat.create.client.MixinSoundScapes", "mod_compat.create.client.MixinTileEntityRenderHelper", "mod_compat.create.client.MixinTrainRelocator", + "mod_compat.create.client.MixinDeployTool", + "mod_compat.create.client.MixinSchematicToolBase", + "mod_compat.create.client.MixinSchematicTransformation", "mod_compat.create.client.trackOutlines.MixinBigOutlines", "mod_compat.create.client.MixinValueBox", "mod_compat.flywheel.InstancingEngineAccessor",