Skip to content

Commit

Permalink
Fix Create Schematic placement, rendering on ships (#690)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
Endalion and ewoudje authored Aug 8, 2024
1 parent 9ec9b1c commit eac19c8
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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)
* <p>
* 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<Vec3> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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
* <p>
* 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);
}
}
}
3 changes: 3 additions & 0 deletions common/src/main/resources/valkyrienskies-common.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit eac19c8

Please sign in to comment.