Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes two gameplay bugs related to heatable blocks and anvil hammer interactions, and adjusts frost metal block tag behavior to allow Wither/Ender Dragon destruction.
Changes:
- Fixes anvil hammer left-click behavior after using items in the offhand by no longer relying on
Player#getUsedItemHand(). - Prevents TNT ignition from normal-tier heatable blocks (e.g., normal tungsten), while still igniting TNT for hotter tiers (and when placing a hot block adjacent to TNT).
- Removes
WITHER_IMMUNE/DRAGON_IMMUNEtags from frost metal-related blocks so they are no longer immune.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/main/java/dev/dubhe/anvilcraft/item/AnvilHammerItem.java |
Adjusts left-click anvil hammer logic to use main-hand item/slot instead of last-used hand. |
src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java |
Removes Wither/Dragon immunity tags from frost metal blocks; minor formatting adjustments. |
src/main/java/dev/dubhe/anvilcraft/block/heatable/HeatableBlock.java |
Gates TNT ignition logic on heat tier (non-NORMAL), and adds ignition check on placement. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Direction[] directions = Direction.values(); | ||
| for (Direction direction : directions) { | ||
| if (level.getBlockState(pos.relative(direction)).is(Blocks.TNT) | ||
| && HeatRecorder.getTier(level, pos, state).orElse(HeatTier.NORMAL) != HeatTier.NORMAL | ||
| ) { |
There was a problem hiding this comment.
In onPlace, HeatRecorder.getTier(level, pos, state) is recomputed for every direction even though it only depends on the placed block. Consider computing the tier (or an isHot boolean) once before the loop, and reusing it, to avoid repeated registry scans and improve readability.
| Direction[] directions = Direction.values(); | |
| for (Direction direction : directions) { | |
| if (level.getBlockState(pos.relative(direction)).is(Blocks.TNT) | |
| && HeatRecorder.getTier(level, pos, state).orElse(HeatTier.NORMAL) != HeatTier.NORMAL | |
| ) { | |
| boolean isHot = HeatRecorder.getTier(level, pos, state).orElse(HeatTier.NORMAL) != HeatTier.NORMAL; | |
| Direction[] directions = Direction.values(); | |
| for (Direction direction : directions) { | |
| if (level.getBlockState(pos.relative(direction)).is(Blocks.TNT) && isHot) { |
| public static boolean dropAnvil(@Nullable Player player, Level level, BlockPos blockPos) { | ||
| if (player == null || level.isClientSide) return false; | ||
| ItemStack itemStack = player.getItemInHand(player.getUsedItemHand()); | ||
| ItemStack itemStack = player.getMainHandItem(); | ||
| Item item = itemStack.getItem(); | ||
| if (!(item instanceof AnvilHammerItem anvilHammerItem)) return false; | ||
| if (player.getCooldowns().isOnCooldown(anvilHammerItem)) { | ||
| return false; | ||
| } | ||
| if (player.getCooldowns().isOnCooldown(anvilHammerItem)) return false; | ||
| player.getCooldowns().addCooldown(itemStack.getItem(), 5); | ||
| FallingBlockEntity dummyAnvilEntity = new FallingBlockEntity(EntityType.FALLING_BLOCK, level); | ||
| dummyAnvilEntity.blockState = anvilHammerItem.getAnvil().defaultBlockState(); | ||
| AnvilEvent.OnLand event = new AnvilEvent.OnLand(level, blockPos.above(), dummyAnvilEntity, player.fallDistance); | ||
| NeoForge.EVENT_BUS.post(event); | ||
| level.playSound(null, blockPos, SoundEvents.ANVIL_LAND, SoundSource.BLOCKS, 1f, 1f); | ||
| itemStack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(player.getUsedItemHand())); | ||
| itemStack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(InteractionHand.MAIN_HAND)); | ||
| TriggerUtil.anvilHammerClickBlock(level, blockPos, "left_click"); |
There was a problem hiding this comment.
dropAnvil is now hard-coded to the main hand (getMainHandItem() / InteractionHand.MAIN_HAND), but the call site triggers it based on PlayerInteractEvent.LeftClickBlock#getHand(). If the event can ever fire for OFF_HAND (or if this method gets reused elsewhere), this will cancel the event while not operating on the actual hand/item. Consider passing InteractionHand hand into dropAnvil and using player.getItemInHand(hand) + LivingEntity.getSlotForHand(hand) instead of assuming main hand.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (canStart) { | ||
| this.startWaiting(level, pos, stateGetter, generator); | ||
| this.updateBlockAndNeighbours(level, pos, stateGetter, generator); | ||
| } | ||
|
|
||
| this.checkIsDeadlock(level, pos, stateGetter, generator); |
There was a problem hiding this comment.
update() no longer calls updateBlockAndNeighbours() when canStart is false. This breaks cases where the block's redstone output should change without starting a new cycle (e.g., toggling outputInvert via PulseGeneratorBlockEntity#setOutputMode, or syncing POWERED after load/move), because update() is the mechanism those setters/load paths use to refresh the block state. Consider restoring an unconditional updateBlockAndNeighbours(...) at the end of update() (or otherwise ensuring it runs whenever generator.isOutputting() may have changed).
| if (canStart) { | ||
| this.startWaiting(level, pos, stateGetter, generator); | ||
| this.updateBlockAndNeighbours(level, pos, stateGetter, generator); | ||
| } | ||
|
|
||
| this.checkIsDeadlock(level, pos, stateGetter, generator); |
There was a problem hiding this comment.
This PR is scoped to fixes for #3375 and #2811, but it also changes PulseGenerator behavior (reorders/removes updateBlockAndNeighbours calls). If this is intentional, please mention it in the PR description; otherwise consider reverting or moving these PulseGenerator changes into a separate PR to keep the fix scope focused.
Uh oh!
There was an error while loading. Please reload this page.