Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
395
src/main/java/com/tiedup/remake/blocks/BlockRopeTrap.java
Normal file
395
src/main/java/com/tiedup/remake/blocks/BlockRopeTrap.java
Normal file
@@ -0,0 +1,395 @@
|
||||
package com.tiedup.remake.blocks;
|
||||
|
||||
import com.tiedup.remake.blocks.entity.TrapBlockEntity;
|
||||
import com.tiedup.remake.core.SystemMessageManager;
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import com.tiedup.remake.state.IBondageState;
|
||||
import com.tiedup.remake.util.BondageItemLoaderUtility;
|
||||
import com.tiedup.remake.util.KidnappedHelper;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
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.EntityBlock;
|
||||
import net.minecraft.world.level.block.RenderShape;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.storage.loot.LootParams;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
/**
|
||||
* Rope Trap Block - Trap that ties up entities when they walk on it.
|
||||
*
|
||||
* Phase 16: Blocks
|
||||
*
|
||||
* Features:
|
||||
* - Flat block (1 pixel tall) placed on solid surfaces
|
||||
* - Can be loaded with bondage items by right-clicking
|
||||
* - When armed and entity walks on it, applies all stored items
|
||||
* - Destroys itself after triggering
|
||||
* - Preserves NBT data when broken
|
||||
*
|
||||
* Based on original BlockRopesTrap from 1.12.2
|
||||
*/
|
||||
public class BlockRopeTrap extends Block implements EntityBlock, ICanBeLoaded {
|
||||
|
||||
// Shape: 1 pixel tall carpet-like block
|
||||
protected static final VoxelShape TRAP_SHAPE = Block.box(
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
16.0,
|
||||
1.0,
|
||||
16.0
|
||||
);
|
||||
|
||||
public BlockRopeTrap() {
|
||||
super(
|
||||
BlockBehaviour.Properties.of()
|
||||
.strength(1.0f, 0.5f)
|
||||
.sound(SoundType.WOOL)
|
||||
.noOcclusion()
|
||||
.noCollission() // Entities can walk through/on it
|
||||
);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// SHAPE AND RENDERING
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(
|
||||
BlockState state,
|
||||
BlockGetter level,
|
||||
BlockPos pos,
|
||||
CollisionContext context
|
||||
) {
|
||||
return TRAP_SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(
|
||||
BlockState state,
|
||||
BlockGetter level,
|
||||
BlockPos pos,
|
||||
CollisionContext context
|
||||
) {
|
||||
return Shapes.empty(); // No collision - entities walk through
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderShape getRenderShape(BlockState state) {
|
||||
return RenderShape.MODEL;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// PLACEMENT RULES
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(
|
||||
BlockState state,
|
||||
LevelReader level,
|
||||
BlockPos pos
|
||||
) {
|
||||
BlockPos below = pos.below();
|
||||
BlockState belowState = level.getBlockState(below);
|
||||
// Can only be placed on full solid blocks
|
||||
return belowState.isFaceSturdy(level, below, Direction.UP);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
if (
|
||||
!canSurvive(
|
||||
defaultBlockState(),
|
||||
context.getLevel(),
|
||||
context.getClickedPos()
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return defaultBlockState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(
|
||||
BlockState state,
|
||||
Direction facing,
|
||||
BlockState facingState,
|
||||
LevelAccessor level,
|
||||
BlockPos pos,
|
||||
BlockPos facingPos
|
||||
) {
|
||||
// Break if support block is removed
|
||||
if (facing == Direction.DOWN && !canSurvive(state, level, pos)) {
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
}
|
||||
return super.updateShape(
|
||||
state,
|
||||
facing,
|
||||
facingState,
|
||||
level,
|
||||
pos,
|
||||
facingPos
|
||||
);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// BLOCK ENTITY
|
||||
// ========================================
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new TrapBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TrapBlockEntity getTrapEntity(BlockGetter level, BlockPos pos) {
|
||||
BlockEntity be = level.getBlockEntity(pos);
|
||||
return be instanceof TrapBlockEntity ? (TrapBlockEntity) be : null;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// TRAP TRIGGER
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public void entityInside(
|
||||
BlockState state,
|
||||
Level level,
|
||||
BlockPos pos,
|
||||
Entity entity
|
||||
) {
|
||||
if (level.isClientSide) return;
|
||||
|
||||
// Only affect living entities
|
||||
if (!(entity instanceof LivingEntity living)) return;
|
||||
|
||||
// Get target's kidnapped state
|
||||
IBondageState targetState = KidnappedHelper.getKidnappedState(living);
|
||||
if (targetState == null) return;
|
||||
|
||||
// Don't trigger if already tied
|
||||
if (targetState.isTiedUp()) return;
|
||||
|
||||
// Get trap data
|
||||
TrapBlockEntity trap = getTrapEntity(level, pos);
|
||||
if (trap == null || !trap.isArmed()) return;
|
||||
|
||||
// Apply all bondage items
|
||||
ItemStack bind = trap.getBind();
|
||||
ItemStack gag = trap.getGag();
|
||||
ItemStack blindfold = trap.getBlindfold();
|
||||
ItemStack earplugs = trap.getEarplugs();
|
||||
ItemStack collar = trap.getCollar();
|
||||
ItemStack clothes = trap.getClothes();
|
||||
|
||||
targetState.applyBondage(
|
||||
bind,
|
||||
gag,
|
||||
blindfold,
|
||||
earplugs,
|
||||
collar,
|
||||
clothes
|
||||
);
|
||||
|
||||
// Destroy the trap
|
||||
level.destroyBlock(pos, false);
|
||||
|
||||
// Notify target
|
||||
if (entity instanceof Player player) {
|
||||
player.displayClientMessage(
|
||||
Component.translatable("tiedup.trap.triggered").withStyle(
|
||||
ChatFormatting.RED
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[BlockRopeTrap] Trap triggered at {} on {}",
|
||||
pos,
|
||||
entity.getName().getString()
|
||||
);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// LOADING ITEMS
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public InteractionResult use(
|
||||
BlockState state,
|
||||
Level level,
|
||||
BlockPos pos,
|
||||
Player player,
|
||||
InteractionHand hand,
|
||||
BlockHitResult hit
|
||||
) {
|
||||
if (hand != InteractionHand.MAIN_HAND) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
ItemStack heldItem = player.getItemInHand(hand);
|
||||
|
||||
// Empty hand = do nothing
|
||||
if (heldItem.isEmpty()) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
// Check if it's a bondage item
|
||||
if (!BondageItemLoaderUtility.isLoadableBondageItem(heldItem)) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
// Server-side only
|
||||
if (level.isClientSide) {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
TrapBlockEntity trap = getTrapEntity(level, pos);
|
||||
if (trap == null) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
// Try to load the held item into the appropriate slot
|
||||
if (
|
||||
BondageItemLoaderUtility.loadItemIntoHolder(trap, heldItem, player)
|
||||
) {
|
||||
SystemMessageManager.sendToPlayer(
|
||||
player,
|
||||
"Item loaded into trap",
|
||||
ChatFormatting.YELLOW
|
||||
);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// DROPS WITH NBT
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getDrops(
|
||||
BlockState state,
|
||||
LootParams.Builder params
|
||||
) {
|
||||
BlockEntity be = params.getOptionalParameter(
|
||||
LootContextParams.BLOCK_ENTITY
|
||||
);
|
||||
ItemStack stack = new ItemStack(this);
|
||||
|
||||
if (be instanceof TrapBlockEntity trap) {
|
||||
CompoundTag beTag = new CompoundTag();
|
||||
trap.writeBondageData(beTag);
|
||||
|
||||
if (!beTag.isEmpty()) {
|
||||
stack.addTagElement("BlockEntityTag", beTag);
|
||||
}
|
||||
}
|
||||
|
||||
return List.of(stack);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// TOOLTIP
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public void appendHoverText(
|
||||
ItemStack stack,
|
||||
@Nullable BlockGetter level,
|
||||
List<Component> tooltip,
|
||||
TooltipFlag flag
|
||||
) {
|
||||
tooltip.add(
|
||||
Component.translatable("block.tiedup.rope_trap.desc").withStyle(
|
||||
ChatFormatting.GRAY
|
||||
)
|
||||
);
|
||||
|
||||
CompoundTag nbt = stack.getTag();
|
||||
if (nbt != null && nbt.contains("BlockEntityTag")) {
|
||||
CompoundTag beTag = nbt.getCompound("BlockEntityTag");
|
||||
|
||||
// Check if armed
|
||||
if (beTag.contains("bind")) {
|
||||
tooltip.add(
|
||||
Component.literal("Armed").withStyle(
|
||||
ChatFormatting.DARK_RED
|
||||
)
|
||||
);
|
||||
|
||||
// List loaded items
|
||||
BondageItemLoaderUtility.addItemToTooltip(
|
||||
tooltip,
|
||||
beTag,
|
||||
"bind"
|
||||
);
|
||||
BondageItemLoaderUtility.addItemToTooltip(
|
||||
tooltip,
|
||||
beTag,
|
||||
"gag"
|
||||
);
|
||||
BondageItemLoaderUtility.addItemToTooltip(
|
||||
tooltip,
|
||||
beTag,
|
||||
"blindfold"
|
||||
);
|
||||
BondageItemLoaderUtility.addItemToTooltip(
|
||||
tooltip,
|
||||
beTag,
|
||||
"earplugs"
|
||||
);
|
||||
BondageItemLoaderUtility.addItemToTooltip(
|
||||
tooltip,
|
||||
beTag,
|
||||
"collar"
|
||||
);
|
||||
BondageItemLoaderUtility.addItemToTooltip(
|
||||
tooltip,
|
||||
beTag,
|
||||
"clothes"
|
||||
);
|
||||
} else {
|
||||
tooltip.add(
|
||||
Component.literal("Disarmed").withStyle(
|
||||
ChatFormatting.GREEN
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
tooltip.add(
|
||||
Component.literal("Disarmed").withStyle(ChatFormatting.GREEN)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user