Skip to content

Commit

Permalink
Fix freestanding ladders not popping off when the top is broken. Fixes
Browse files Browse the repository at this point in the history
…#4843

* Fix freestanding ladders not popping off when the top is broken. Also simplify the logic a little bit. Fixes #4843
* Better ladder injection thanks thundxr
  • Loading branch information
quat1024 authored Jul 13, 2024
1 parent b16d24e commit 1e1175e
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 39 deletions.
3 changes: 2 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
- Fallen logs can rarely spawn on water
- Fallen logs can no longer spawn on ice and other non terrain blocks (added tag for them)
- Fallen log decoration (moss and vines) are now biome temperature and humidify dependent. No more moss in snowy biomes
- Freestanding ladders will now break off the wall when you break the top block
- Matrix Enchanting Table appears in creative if automaticallyConvert is off
- Fixed Skull Pikes not functioning when there's a block on top, by lowering the detection point
- Fixed Skull Pikes not functioning when there's a block on top, by lowering the detection point
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import net.minecraft.client.player.Input;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -21,13 +20,13 @@
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LadderBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
Expand Down Expand Up @@ -64,10 +63,12 @@ public class EnhancedLaddersModule extends ZetaModule {
@Config
public static boolean allowInventorySneak = true;

private static boolean staticEnabled;
public static boolean staticEnabled;
private static TagKey<Item> laddersTag;
private static TagKey<Block> laddersBlockTag;

private static final DirectionProperty FACING = LadderBlock.FACING;

@LoadEvent
public final void setup(ZCommonSetup event) {
laddersTag = ItemTags.create(new ResourceLocation(Quark.MOD_ID, "ladders"));
Expand Down Expand Up @@ -106,35 +107,23 @@ public void addAdditionalHints(ZGatherHints event) {
event.accept(item, comp);
}

private static boolean canAttachTo(BlockState state, Block ladder, LevelReader world, BlockPos pos, Direction facing) {
if(ladder instanceof LadderBlock) {
if(allowFreestanding)
return canLadderSurvive(state, world, pos);

BlockPos offset = pos.relative(facing);
BlockState blockstate = world.getBlockState(offset);
return !blockstate.isSignalSource() && blockstate.isFaceSturdy(world, offset, facing);
}
// see LadderBlockMixin
public static boolean canSurviveTweak(boolean vanillaSurvive, BlockState state, LevelReader world, BlockPos pos) {
//With the freestanding feature enabled, ladders can survive if they are supported by a block (vanillaSurvive),
//or if they are underneath a ladder on the same wall.
if(vanillaSurvive)
return true;

return false;
}

// replaces ladder survives logic
public static boolean canLadderSurvive(BlockState state, LevelReader world, BlockPos pos) {
if(!staticEnabled || !allowFreestanding)
if(!staticEnabled || !allowFreestanding || !state.is(laddersBlockTag) || !state.hasProperty(FACING))
return false;
if(!state.is(laddersBlockTag))return false;

Direction facing = state.getValue(LadderBlock.FACING);
Direction opposite = facing.getOpposite();
BlockPos oppositePos = pos.relative(opposite);
BlockState oppositeState = world.getBlockState(oppositePos);

boolean solid = oppositeState.isFaceSturdy(world, oppositePos, facing) && !(oppositeState.getBlock() instanceof LadderBlock);
BlockState topState = world.getBlockState(pos.above());
return solid || (topState.getBlock() instanceof LadderBlock && (facing.getAxis() == Axis.Y || topState.getValue(LadderBlock.FACING) == facing));
BlockState aboveState = world.getBlockState(pos.above());
return aboveState.is(laddersBlockTag) && aboveState.hasProperty(FACING) && aboveState.getValue(FACING) == state.getValue(FACING);
}

public static boolean shouldDoUpdateShapeTweak(BlockState state) {
return staticEnabled && allowFreestanding && state.is(laddersBlockTag);
}

@PlayEvent
public void onInteract(ZRightClickBlock event) {
Expand Down Expand Up @@ -164,8 +153,7 @@ public void onInteract(ZRightClickBlock event) {
if(water || stateDown.isAir()) {
BlockState copyState = world.getBlockState(pos);

Direction facing = copyState.getValue(LadderBlock.FACING);
if(canAttachTo(copyState, block, world, posDown, facing.getOpposite())) {
if(copyState.canSurvive(world, posDown)) {
world.setBlockAndUpdate(posDown, copyState.setValue(BlockStateProperties.WATERLOGGED, water));
world.playSound(null, posDown.getX(), posDown.getY(), posDown.getZ(), SoundEvents.LADDER_PLACE, SoundSource.BLOCKS, 1F, 1F);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.violetmoon.quark.mixin.mixins;

import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
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;

/**
* Exists to be subclassed by LadderBlockMixin basically
*/
@Mixin(BlockBehaviour.class)
public class BlockBehaviourMixin {
@Inject(method = "tick", at = @At("HEAD"))
public void quark$tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, RandomSource pRandom, CallbackInfo ci) {

}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
package org.violetmoon.quark.mixin.mixins;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.LadderBlock;
import net.minecraft.world.level.block.state.BlockState;

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;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import org.violetmoon.quark.content.tweaks.module.EnhancedLaddersModule;

@Mixin(LadderBlock.class)
public class LadderBlockMixin {

public class LadderBlockMixin extends BlockBehaviourMixin {
@ModifyReturnValue(method = "canSurvive", at = @At("RETURN"))
private boolean canSurviveTweak(boolean original, BlockState state, LevelReader level, BlockPos pos) {
return EnhancedLaddersModule.canSurviveTweak(original, state, level, pos);
}

@Inject(method = "canSurvive", at = @At("HEAD"), cancellable = true)
private void canSurvive(BlockState state, LevelReader level, BlockPos pos, CallbackInfoReturnable<Boolean> callbackInfoReturnable) {
if(EnhancedLaddersModule.canLadderSurvive(state, level, pos)) {
callbackInfoReturnable.setReturnValue(true);
callbackInfoReturnable.cancel();
/**
* In vanilla, the only way to break a ladder is to break the block behind it. So in updateShape,
* vanilla only does ladder canSurvive checks if the update came from behind. But with Quark's
* freestanding ladder feature, it's possible to break a ladder by breaking a block *above* it.
*/
@Inject(method = "updateShape", at = @At(value = "HEAD"), cancellable = true)
private void updateShapeTweak(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pFacingPos, CallbackInfoReturnable<BlockState> cir) {
if(EnhancedLaddersModule.shouldDoUpdateShapeTweak(pState) && pFacing == Direction.UP) {
//This is just for fun. Makes the ladders break like bamboo instead of instantly.
pLevel.scheduleTick(pCurrentPos, (LadderBlock) (Object) this, 1);
cir.setReturnValue(pState);
}
}

/**
* Override from BlockBehaviourMixin which does the actual injection
*/
@Override
public void quark$tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, RandomSource pRandom, CallbackInfo ci) {
if(EnhancedLaddersModule.shouldDoUpdateShapeTweak(pState) && !pState.canSurvive(pLevel, pPos)) {
pLevel.destroyBlock(pPos, true);
}
}
}
1 change: 1 addition & 0 deletions src/main/resources/quark.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"BaseCoralPlantTypeBlockMixin",
"BeaconBlockEntityMixin",
"BeehiveBlockEntityMixin",
"BlockBehaviourMixin",
"BlockItemMixin",
"BoatMixin",
"CeilingHangingSignBlockMixin",
Expand Down

0 comments on commit 1e1175e

Please sign in to comment.