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

Fix Create Schematic placement, rendering on ships #690

Merged
merged 4 commits into from
Aug 8, 2024
Merged
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
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 @@ -168,6 +168,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.trackOutlines.MixinTrackBlockOutline",
"mod_compat.create.client.MixinValueBox",
Expand Down
Loading