summary refs log tree commit diff
path: root/src/main/java/wtf/kity/uncrackable/mixin/FallingBlockEntityMixin.java
blob: bd4548843b773513e3f083729acda77a9461bf6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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.DragonEggBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
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().getBlock() instanceof DragonEggBlock) {
            return;
        }
        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().getBlock() instanceof DragonEggBlock) {
            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 Block block,
            @Local BlockPos blockPos
    ) {
        if (original.call(instance, blockPlaceContext)) {
            return true;
        }

        if (block instanceof DragonEggBlock) {
            @Nullable BlockEntity blockentity = this.level().getBlockEntity(blockPos);
            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 instanceof DragonEggBlock;
    }
}