summary refs log tree commit diff
path: root/src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java
diff options
context:
space:
mode:
authorash lea <example@thisismyactual.email>2026-06-01 14:25:40 -0400
committerash lea <example@thisismyactual.email>2026-06-01 14:25:40 -0400
commit52b847653296f6e80fd68678b2a88ee9f560eaff (patch)
treeb52750d0b649f64a670552d1776e39f6a0a676d3 /src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java
initial commit
Diffstat (limited to 'src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java')
-rw-r--r--src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java b/src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java
new file mode 100644
index 0000000..500f970
--- /dev/null
+++ b/src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java
@@ -0,0 +1,112 @@
+package wtf.kity.uncrackable.mixin;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.item.FallingBlockEntity;
+import net.minecraft.world.item.context.BlockPlaceContext;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.phys.Vec3;
+import org.objectweb.asm.Opcodes;
+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.callback.CallbackInfo;
+
+@Mixin(FallingBlockEntity.class)
+public abstract class FallingBlockEntityMixin extends Entity {
+    public FallingBlockEntityMixin(EntityType<?> entityType, Level level) {
+        super(entityType, level);
+    }
+
+    /// If the egg falls into the void, teleport back up to build limit.
+    @Inject(method = "tick", at = @At("HEAD"))
+    private void beforeTick(CallbackInfo ci) {
+        Vec3 pos = this.position();
+        if (pos.y < this.level().getMinBuildHeight()) {
+            this.teleportTo(pos.x, this.level().getMaxBuildHeight(), pos.z);
+        }
+    }
+
+    /// Egg should never time out. Skip add-assign operation entirely for the egg.
+    @WrapOperation(
+            method = "tick",
+            at = @At(
+                value = "FIELD",
+                target = "Lnet/minecraft/world/entity/item/FallingBlockEntity;time:I",
+                opcode = Opcodes.PUTFIELD
+            )
+    )
+    private void setTime(FallingBlockEntity instance, int value, Operation<Void> original) {
+        if (!instance.getBlockState().is(Blocks.DRAGON_EGG)) {
+            original.call(instance, value);
+        }
+    }
+
+    /// Egg should not drop as an item if it lands above build height.
+    @WrapOperation(
+            method = "tick",
+            at = @At(
+                    value = "FIELD",
+                    target = "Lnet/minecraft/world/entity/item/FallingBlockEntity;dropItem:Z",
+                    opcode = Opcodes.GETFIELD
+            )
+    )
+    private boolean getDropItem(FallingBlockEntity instance, Operation<Boolean> original) {
+        if (instance.getBlockState().is(Blocks.DRAGON_EGG)) {
+            return false;
+        }
+        return original.call(instance);
+    }
+
+    /// If it lands inside a block, destroy the block as if by piston push.
+    /// We override block shapes for non-piston-destructible blocks in`BlockBehaviorMixin`
+    /// so normally this only applies to piston-destructible blocks, unless a block is pushed
+    /// into the egg while it's an entity.
+    @WrapOperation(
+            method = "tick",
+            at = @At(
+                    value = "INVOKE",
+                    target = "Lnet/minecraft/world/level/block/state/BlockState;canBeReplaced(Lnet/minecraft/world/item/context/BlockPlaceContext;)Z"
+            )
+    )
+    private boolean canBeReplaced(
+            BlockState instance,
+            BlockPlaceContext blockPlaceContext,
+            Operation<Boolean> original,
+            @Local BlockPos blockPos
+    ) {
+        if (original.call(instance, blockPlaceContext)) {
+            return true;
+        }
+
+        if (instance.is(Blocks.DRAGON_EGG)) {
+            BlockEntity blockentity = instance.hasBlockEntity() ? this.level().getBlockEntity(blockPos) : null;
+            Block.dropResources(instance, this.level(), blockPos, blockentity);
+            instance.onDestroyedByPushReaction(this.level(), blockPos, Direction.DOWN, this.level().getFluidState(blockPos));
+            return true;
+        }
+
+        return false;
+    }
+
+    /// The egg should never drop as an item, so we always pretend that the ground beneath it is landable.
+    @WrapOperation(
+            method = "tick",
+            at = @At(
+                    value = "INVOKE",
+                    target = "Lnet/minecraft/world/level/block/FallingBlock;isFree(Lnet/minecraft/world/level/block/state/BlockState;)Z"
+            )
+    )
+    private boolean isFree(BlockState state, Operation<Boolean> original, @Local Block block) {
+        return original.call(state) && block != Blocks.DRAGON_EGG;
+    }
+}