Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dev.dubhe.anvilcraft.api.anvil.IAnvilBehavior;
import dev.dubhe.anvilcraft.api.event.AnvilEvent;
import dev.dubhe.anvilcraft.block.BlockDevourerBlock;
import dev.dubhe.anvilcraft.util.DevourUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
Expand Down Expand Up @@ -33,7 +34,7 @@ public boolean handle(Level level, BlockPos hitBlockPos, BlockState hitBlockStat
);
if (
hitBlockState.getValue(BlockDevourerBlock.FACING) == Direction.DOWN
&& BlockDevourerBlock.canDevour(level.getBlockState(hitBlockPos.below()))
&& DevourUtil.canDevour(level.getBlockState(hitBlockPos.below()))
) {
level.setBlockAndUpdate(hitBlockPos, Blocks.AIR.defaultBlockState());
level.setBlockAndUpdate(hitBlockPos.below(), hitBlockState.setValue(BlockDevourerBlock.TRIGGERED, true));
Expand Down
77 changes: 13 additions & 64 deletions src/main/java/dev/dubhe/anvilcraft/block/BlockDevourerBlock.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dev.dubhe.anvilcraft.block;

import com.google.common.collect.Streams;
import com.mojang.serialization.MapCodec;
import dev.dubhe.anvilcraft.AnvilCraft;
import dev.dubhe.anvilcraft.api.entity.fakeplayer.AnvilCraftFakePlayers;
Expand All @@ -10,7 +9,7 @@
import dev.dubhe.anvilcraft.init.block.ModBlockTags;
import dev.dubhe.anvilcraft.util.AnvilUtil;
import dev.dubhe.anvilcraft.util.BreakBlockUtil;
import dev.dubhe.anvilcraft.util.MultiPartBlockUtil;
import dev.dubhe.anvilcraft.util.DevourUtil;
import dev.dubhe.anvilcraft.util.TriggerUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
Expand Down Expand Up @@ -196,73 +195,25 @@ public void devourBlock(
) {
BlockPos outputPos = devourerPos.relative(devourerDirection.getOpposite());
BlockPos devourCenterPos = devourerPos.relative(devourerDirection);
List<BlockPos> filteredBlockPosList = new ArrayList<>();
Vec3 center = outputPos.getCenter();
final List<IItemHandler> itemHandlerList = ItemHandlerUtil.getTargetItemHandlerList(
outputPos,
devourerDirection,
level
);
Vec3 center = outputPos.getCenter();
Iterable<BlockPos> devourBlockPosList;
int maxY;
switch (devourerDirection) {
case DOWN, UP -> {
devourBlockPosList = BlockPos.betweenClosed(
devourCenterPos.relative(Direction.NORTH, range).relative(Direction.WEST, range),
devourCenterPos.relative(Direction.SOUTH, range).relative(Direction.EAST, range)
);
maxY = devourCenterPos.getY();
}
case NORTH, SOUTH -> {
devourBlockPosList = BlockPos.betweenClosed(
devourCenterPos.relative(Direction.UP, range).relative(Direction.WEST, range),
devourCenterPos.relative(Direction.DOWN, range).relative(Direction.EAST, range)
);
maxY = devourCenterPos.relative(Direction.UP, range).getY();
}
case WEST, EAST -> {
devourBlockPosList = BlockPos.betweenClosed(
devourCenterPos.relative(Direction.UP, range).relative(Direction.NORTH, range),
devourCenterPos.relative(Direction.DOWN, range).relative(Direction.SOUTH, range)
);
maxY = devourCenterPos.relative(Direction.UP, range).getY();
}
default -> {
devourBlockPosList = List.of(devourCenterPos);
maxY = devourCenterPos.getY();
}
}
devourBlockPosList = Streams.stream(devourBlockPosList).map(BlockPos::immutable).toList();

final List<BlockPos> chainDevourBlockPosList = new ArrayList<>();
final List<BlockPos> filteredBlockPosList = new ArrayList<>();
for (BlockPos devourBlockPos : devourBlockPosList) {
if (
AnvilCraft.CONFIG.blockDevourerUpwardChainDevouring && devourBlockPos.getY() == maxY
) {
for (BlockPos chainDevourBlockPos : BlockPos.betweenClosed(
devourBlockPos.above(), devourBlockPos.above(AnvilCraft.CONFIG.blockDevourerUpwardChainDevouringDistance)
)) {
if (!level.getBlockState(chainDevourBlockPos).is(ModBlockTags.BLOCK_DEVOURER_CHAIN_DEVOURING)) break;
chainDevourBlockPosList.add(chainDevourBlockPos.immutable());
}
}

devourSingleBlockInternalLogic(level, anvil, devourBlockPos, filteredBlockPosList, itemHandlerList, center);
}
for (BlockPos devourBlockPos : chainDevourBlockPosList) {
List<BlockPos> devourPosList = DevourUtil.getDevourPosList(
level,
devourCenterPos,
devourerDirection,
range,
AnvilCraft.CONFIG.blockDevourerUpwardChainDevouring ? AnvilCraft.CONFIG.blockDevourerUpwardChainDevouringDistance : 0
);
for (BlockPos devourBlockPos : devourPosList) {
devourSingleBlockInternalLogic(level, anvil, devourBlockPos, filteredBlockPosList, itemHandlerList, center);
}
}

/**
* 检查目标位置是否可以破坏
*
* @param devourBlockState 目标方块
* */
public static boolean canDevour(BlockState devourBlockState) {
return !devourBlockState.is(ModBlockTags.DEVOUR_BLACKLIST) && devourBlockState.getBlock().defaultDestroyTime() >= 0;
}

private static void devourSingleBlockInternalLogic(
ServerLevel level, @Nullable Block anvil, BlockPos devourBlockPos, List<BlockPos> filteredBlockPosList,
@Nullable List<IItemHandler> itemHandlerList, Vec3 center
Expand All @@ -273,8 +224,7 @@ private static void devourSingleBlockInternalLogic(

if (filteredBlockPosList.contains(devourBlockPos)) return;
BlockState devourBlockState = level.getBlockState(devourBlockPos);
if (devourBlockState.isAir()) return;
if (!BlockDevourerBlock.canDevour(devourBlockState)) return;
if (!DevourUtil.shouldDevour(devourBlockState)) return;
if (
!(anvil instanceof FrostAnvilBlock)
&& devourBlockState.is(ModBlockTags.BLOCK_DEVOURER_PROBABILITY_DROPPING)
Expand All @@ -283,8 +233,7 @@ private static void devourSingleBlockInternalLogic(
level.destroyBlock(devourBlockPos, false);
return;
}
devourBlockPos = MultiPartBlockUtil.getChainableMainPartPos(level, devourBlockPos);
devourBlockState = level.getBlockState(devourBlockPos);

if (anvil instanceof FrostAnvilBlock) {
ServerPlayer destroyer = AnvilCraftFakePlayers.anvilcraftDestroyer.offerPlayer(level);
ItemStack dummyTool = BreakBlockUtil.getDummyDisintegrationTool(level);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import dev.dubhe.anvilcraft.AnvilCraft;
import dev.dubhe.anvilcraft.api.amulet.AmuletManager;
import dev.dubhe.anvilcraft.api.power.PowerGrid;
import dev.dubhe.anvilcraft.block.BlockDevourerBlock;
import dev.dubhe.anvilcraft.block.item.ResinBlockItem;
import dev.dubhe.anvilcraft.entity.MagnetizedNodeEntity;
import dev.dubhe.anvilcraft.init.block.ModBlocks;
Expand All @@ -17,6 +16,7 @@
import dev.dubhe.anvilcraft.item.property.component.BoxContents;
import dev.dubhe.anvilcraft.network.DragonRodDevourPacket;
import dev.dubhe.anvilcraft.recipe.anvil.cache.RecipeCaches;
import dev.dubhe.anvilcraft.util.DevourUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
Expand Down Expand Up @@ -127,7 +127,7 @@ public static void handleDragonRod(PlayerInteractEvent.LeftClickBlock event) {
if (blockFace == null) return;
if (state.getDestroySpeed(level, pos) < 0.0F) return;
if (!stack.has(ModComponents.DEVOUR_RANGE)) return;
if (!DragonRodItem.canDevour(player, stack) || !BlockDevourerBlock.canDevour(state)) {
if (!DragonRodItem.canDevour(player, stack) || !DevourUtil.canDevour(state)) {
event.setCanceled(true);
return;
}
Expand Down
154 changes: 75 additions & 79 deletions src/main/java/dev/dubhe/anvilcraft/item/DragonRodItem.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package dev.dubhe.anvilcraft.item;

import com.google.common.collect.Streams;
import dev.dubhe.anvilcraft.block.BlockDevourerBlock;
import dev.dubhe.anvilcraft.init.block.ModBlockTags;
import dev.dubhe.anvilcraft.init.item.ModComponents;
import dev.dubhe.anvilcraft.init.item.ModItems;
import dev.dubhe.anvilcraft.util.BreakBlockUtil;
import dev.dubhe.anvilcraft.util.DevourUtil;
import dev.dubhe.anvilcraft.util.InventoryUtil;
import dev.dubhe.anvilcraft.util.MultiPartBlockUtil;
import it.unimi.dsi.fastutil.ints.IntIterators;
import it.unimi.dsi.fastutil.ints.IntListIterator;
import lombok.extern.slf4j.Slf4j;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.effect.MobEffects;
Expand Down Expand Up @@ -94,7 +93,7 @@ public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPo
return false;
}

@SuppressWarnings("DataFlowIssue")

public static void devourBlock(
ServerLevel level, Player player, InteractionHand hand,
BlockPos centerPos, BlockState centerState, Direction clickedSide
Expand All @@ -106,76 +105,17 @@ public static void devourBlock(
int range = dragonRod.getOrDefault(ModComponents.DEVOUR_RANGE, -1);
if (range == -1) return;
range = (range - 1) / 2;
Iterable<BlockPos> devouringPoses;
switch (clickedSide) {
case DOWN, UP -> devouringPoses = BlockPos.betweenClosed(
centerPos.relative(Direction.NORTH, range).relative(Direction.WEST, range),
centerPos.relative(Direction.SOUTH, range).relative(Direction.EAST, range)
);
case NORTH, SOUTH -> devouringPoses = BlockPos.betweenClosed(
centerPos.relative(Direction.UP, range).relative(Direction.WEST, range),
centerPos.relative(Direction.DOWN, range).relative(Direction.EAST, range)
);
case WEST, EAST -> devouringPoses = BlockPos.betweenClosed(
centerPos.relative(Direction.UP, range).relative(Direction.NORTH, range),
centerPos.relative(Direction.DOWN, range).relative(Direction.SOUTH, range)
);
default -> devouringPoses = List.of(centerPos);
}
devouringPoses = Streams.stream(devouringPoses).map(BlockPos::immutable).toList();

for (BlockPos devouringPos : devouringPoses) {
BlockState devouringState = level.getBlockState(devouringPos);
if (devouringState.isAir()) continue;
if (!BlockDevourerBlock.canDevour(devouringState)) continue;
if (devouringState.is(ModBlockTags.BLOCK_DEVOURER_PROBABILITY_DROPPING)
&& level.random.nextDouble() > 0.05) {
level.destroyBlock(devouringPos, false);
continue;
}

devouringPos = MultiPartBlockUtil.getChainableMainPartPos(level, devouringPos);
devouringState = level.getBlockState(devouringPos);

if (!player.getAbilities().instabuild) {
List<ItemStack> dropList = BreakBlockUtil.dropWithTool(level, devouringPos, dragonRod);
Inventory inventory = player.getInventory();
for (ItemStack drop : dropList) {
if (drop.isEmpty()) continue;
ItemStack remaining = InventoryUtil.insertItem(inventory, drop);
if (!remaining.isEmpty()) {
Block.popResource(level, devouringPos, remaining);
}
}
// 特判雕纹书架一类
IItemHandler source = level.getCapability(Capabilities.ItemHandler.BLOCK, devouringPos, null);
if (source != null && dropList.isEmpty()) {
for (IntListIterator it = IntIterators.fromTo(0, source.getSlots()); it.hasNext(); ) {
int slot = it.nextInt();
ItemStack stack = source.getStackInSlot(slot);
if (stack.isEmpty()) continue;
stack = InventoryUtil.insertItem(inventory, stack);
if (!stack.isEmpty()) {
Block.popResource(level, devouringPos, stack);
}
}
}
// 特判讲台
BlockEntity devouringBlockEntity = level.getBlockEntity(devouringPos);
if (devouringBlockEntity instanceof LecternBlockEntity lectern) {
ItemStack bookStack = lectern.getBook();
bookStack = InventoryUtil.insertItem(inventory, bookStack);
lectern.setBook(bookStack);
if (!bookStack.isEmpty()) {
Block.popResource(level, devouringPos, bookStack);
lectern.setBook(ItemStack.EMPTY);
}
}
}
if (!(devouringState.getBlock() instanceof DoublePlantBlock)) {
devouringState.getBlock().playerWillDestroy(level, devouringPos, devouringState, player);
}
level.destroyBlock(devouringPos, false);
List<BlockPos> devourPosList = DevourUtil.getDevourPosList(
level,
centerPos,
clickedSide,
range,
0
);

for (BlockPos devouringPos : devourPosList) {
devourSingleBlockInternalLogic(level, player, dragonRod, devouringPos);
}

int cooldown = calculateCooldown(player);
Expand All @@ -187,16 +127,72 @@ public static void devourBlock(
player.getCooldowns().addCooldown(dragonRod.getItem(), cooldown);
}

dragonRod.hurtAndBreak(calculateDamage(dragonRod), level, player, item -> {
player.onEquippedItemBroken(item, LivingEntity.getSlotForHand(hand));
EventHooks.onPlayerDestroyItem(player, dragonRod, hand);
});
dragonRod.hurtAndBreak(
calculateDamage(dragonRod), level, player, item -> {
player.onEquippedItemBroken(item, LivingEntity.getSlotForHand(hand));
EventHooks.onPlayerDestroyItem(player, dragonRod, hand);
}
);
}

@SuppressWarnings("DataFlowIssue")
private static void devourSingleBlockInternalLogic(
ServerLevel level,
Player player,
ItemStack dragonRod,
BlockPos devourBlockPos) {
BlockState devouringState = level.getBlockState(devourBlockPos);
if (!DevourUtil.shouldDevour(devouringState)) {
return;
}
boolean shouldDrop = !devouringState.is(ModBlockTags.BLOCK_DEVOURER_PROBABILITY_DROPPING)
|| level.random.nextDouble() <= 0.05;

if (!player.getAbilities().instabuild && shouldDrop) {
List<ItemStack> dropList = BreakBlockUtil.dropWithTool(level, devourBlockPos, dragonRod);
Inventory inventory = player.getInventory();
Comment thread
Chrise2024 marked this conversation as resolved.
for (ItemStack drop : dropList) {
if (drop.isEmpty()) continue;
ItemStack remaining = InventoryUtil.insertItem(inventory, drop);
if (!remaining.isEmpty()) {
Block.popResource(level, devourBlockPos, remaining);
}
}
// 特判雕纹书架一类
IItemHandler source = level.getCapability(Capabilities.ItemHandler.BLOCK, devourBlockPos, null);
if (source != null && dropList.isEmpty()) {
for (IntListIterator it = IntIterators.fromTo(0, source.getSlots()); it.hasNext(); ) {
int slot = it.nextInt();
ItemStack stack = source.getStackInSlot(slot);
if (stack.isEmpty()) continue;
stack = InventoryUtil.insertItem(inventory, stack);
if (!stack.isEmpty()) {
Block.popResource(level, devourBlockPos, stack);
}
}
}
// 特判讲台
BlockEntity devouringBlockEntity = level.getBlockEntity(devourBlockPos);
if (devouringBlockEntity instanceof LecternBlockEntity lectern) {
ItemStack bookStack = lectern.getBook();
bookStack = InventoryUtil.insertItem(inventory, bookStack);
lectern.setBook(bookStack);
if (!bookStack.isEmpty()) {
Block.popResource(level, devourBlockPos, bookStack);
lectern.setBook(ItemStack.EMPTY);
}
}
}
if (!(devouringState.getBlock() instanceof DoublePlantBlock)) {
devouringState.getBlock().playerWillDestroy(level, devourBlockPos, devouringState, player);
}
level.destroyBlock(devourBlockPos, false);
}

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean canDevour(Player player, ItemStack dragonRod) {
return dragonRod.getDamageValue() < dragonRod.getMaxDamage() - 1
&& !player.getCooldowns().isOnCooldown(dragonRod.getItem());
&& !player.getCooldowns().isOnCooldown(dragonRod.getItem());
}

public static int calculateDamage(ItemStack dragonRod) {
Expand All @@ -207,7 +203,7 @@ public static int calculateDamage(ItemStack dragonRod) {
case 9 -> 4;
default -> 0;
};
return Math.min(damage, Math.max(dragonRod.getMaxDamage() - dragonRod.getDamageValue(), 1));
return Mth.clamp(dragonRod.getMaxDamage() - dragonRod.getDamageValue(), 1, damage);
}

public static int calculateCooldown(Player player) {
Expand Down
Loading
Loading