package com.thebrokenrail.energonrelics.mixin; import com.thebrokenrail.energonrelics.EnergonRelics; import com.thebrokenrail.energonrelics.block.forcefield.util.BeamBlock; import com.thebrokenrail.energonrelics.block.portal.PortalCooldownEntity; import com.thebrokenrail.energonrelics.config.HardcodedConfig; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.function.Predicate; @Mixin(Entity.class) public abstract class MixinEntity implements PortalCooldownEntity { @Unique private int energyPortalCooldown = 0; @Unique private boolean touchingBeam = false; @Shadow public abstract Box getBoundingBox(); @Shadow public abstract World getEntityWorld(); @Shadow public abstract MinecraftServer getServer(); @Unique private boolean isTouching(Predicate test) { if (getServer() == null || getServer().getThread() == Thread.currentThread()) { getEntityWorld().getProfiler().push("energonrelics:isTouching"); Box box = getBoundingBox(); int i = MathHelper.floor(box.minX); int j = MathHelper.ceil(box.maxX); int k = MathHelper.floor(box.minY); int l = MathHelper.ceil(box.maxY); int m = MathHelper.floor(box.minZ); int n = MathHelper.ceil(box.maxZ); BlockPos.Mutable pos = new BlockPos.Mutable(); for (int p = i; p < j; ++p) { for (int q = k; q < l; ++q) { for (int r = m; r < n; ++r) { pos.set(p, q, r); BlockState state = getEntityWorld().getBlockState(pos); if (state.getCollisionShape(getEntityWorld(), pos).isEmpty() && test.test(state.getBlock())) { getEntityWorld().getProfiler().pop(); return true; } } } } } getEntityWorld().getProfiler().pop(); return false; } @Unique private boolean saving = false; @Inject(at = @At("HEAD"), method = "hasNoGravity", cancellable = true) public void hasNoGravity(CallbackInfoReturnable info) { if (!saving && touchingBeam) { info.setReturnValue(true); } } @Inject(at = @At("HEAD"), method = "toTag") public void toTagHead(CompoundTag tag, CallbackInfoReturnable info) { saving = true; tag.putInt(EnergonRelics.NAMESPACE + ":EnergyPortalCooldown", energyPortalCooldown); } @Inject(at = @At("RETURN"), method = "toTag") public void toTagReturn(CompoundTag tag, CallbackInfoReturnable info) { saving = false; } @Inject(at = @At("HEAD"), method = "fromTag") public void fromTag(CompoundTag tag, CallbackInfo info) { energyPortalCooldown = tag.getInt(EnergonRelics.NAMESPACE + ":EnergyPortalCooldown"); } @Inject(at = @At("HEAD"), method = "tick") public void tickHead(CallbackInfo info) { touchingBeam = isTouching(block -> block instanceof BeamBlock); } @Inject(at = @At("RETURN"), method = "tick") public void tickReturn(CallbackInfo info) { energyPortalCooldown--; } @Override public void resetEnergyPortalCooldown() { energyPortalCooldown = HardcodedConfig.ENERGY_PORTAL_COOLDOWN; } @Override public boolean isEnergyPortalCooldown() { return energyPortalCooldown > 0; } }