mirror of
https://github.com/Theta-Dev/ConstructionWand.git
synced 2025-08-05 02:15:27 +02:00
233 lines
8.9 KiB
Java
233 lines
8.9 KiB
Java
package thetadev.constructionwand.basics;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.stats.Stats;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.BlockItem;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.phys.BlockHitResult;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.common.util.BlockSnapshot;
|
|
import net.minecraftforge.event.world.BlockEvent;
|
|
import thetadev.constructionwand.ConstructionWand;
|
|
import thetadev.constructionwand.containers.ContainerManager;
|
|
import thetadev.constructionwand.items.wand.ItemWand;
|
|
import thetadev.constructionwand.wand.WandItemUseContext;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.function.Predicate;
|
|
|
|
public class WandUtil
|
|
{
|
|
public static boolean stackEquals(ItemStack stackA, ItemStack stackB) {
|
|
return ItemStack.isSameItemSameTags(stackA, stackB);
|
|
}
|
|
|
|
public static boolean stackEquals(ItemStack stackA, Item item) {
|
|
ItemStack stackB = new ItemStack(item);
|
|
return stackEquals(stackA, stackB);
|
|
}
|
|
|
|
public static ItemStack holdingWand(Player player) {
|
|
if(player.getItemInHand(InteractionHand.MAIN_HAND) != ItemStack.EMPTY && player.getItemInHand(InteractionHand.MAIN_HAND).getItem() instanceof ItemWand) {
|
|
return player.getItemInHand(InteractionHand.MAIN_HAND);
|
|
}
|
|
else if(player.getItemInHand(InteractionHand.OFF_HAND) != ItemStack.EMPTY && player.getItemInHand(InteractionHand.OFF_HAND).getItem() instanceof ItemWand) {
|
|
return player.getItemInHand(InteractionHand.OFF_HAND);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static BlockPos playerPos(Player player) {
|
|
return new BlockPos(player.position());
|
|
}
|
|
|
|
public static Vec3 entityPositionVec(Entity entity) {
|
|
return new Vec3(entity.getX(), entity.getY() - entity.getMyRidingOffset() + entity.getBbHeight() / 2, entity.getZ());
|
|
}
|
|
|
|
public static Vec3 blockPosVec(BlockPos pos) {
|
|
return new Vec3(pos.getX(), pos.getY(), pos.getZ());
|
|
}
|
|
|
|
public static List<ItemStack> getHotbar(Player player) {
|
|
return player.getInventory().items.subList(0, 9);
|
|
}
|
|
|
|
public static List<ItemStack> getHotbarWithOffhand(Player player) {
|
|
ArrayList<ItemStack> inventory = new ArrayList<>(player.getInventory().items.subList(0, 9));
|
|
inventory.addAll(player.getInventory().offhand);
|
|
return inventory;
|
|
}
|
|
|
|
public static List<ItemStack> getMainInv(Player player) {
|
|
return player.getInventory().items.subList(9, player.getInventory().items.size());
|
|
}
|
|
|
|
public static List<ItemStack> getFullInv(Player player) {
|
|
ArrayList<ItemStack> inventory = new ArrayList<>(player.getInventory().offhand);
|
|
inventory.addAll(player.getInventory().items);
|
|
return inventory;
|
|
}
|
|
|
|
public static int blockDistance(BlockPos p1, BlockPos p2) {
|
|
return Math.max(Math.abs(p1.getX() - p2.getX()), Math.abs(p1.getZ() - p2.getZ()));
|
|
}
|
|
|
|
public static boolean isTEAllowed(BlockState state) {
|
|
if(!state.hasBlockEntity()) return true;
|
|
|
|
ResourceLocation name = state.getBlock().getRegistryName();
|
|
if(name == null) return false;
|
|
|
|
String fullId = name.toString();
|
|
String modId = name.getNamespace();
|
|
|
|
boolean inList = ConfigServer.TE_LIST.get().contains(fullId) || ConfigServer.TE_LIST.get().contains(modId);
|
|
boolean isWhitelist = ConfigServer.TE_WHITELIST.get();
|
|
|
|
return isWhitelist == inList;
|
|
}
|
|
|
|
public static boolean placeBlock(Level world, Player player, BlockState block, BlockPos pos, @Nullable BlockItem item) {
|
|
if(!world.setBlockAndUpdate(pos, block)) {
|
|
ConstructionWand.LOGGER.info("Block could not be placed");
|
|
return false;
|
|
}
|
|
|
|
// Remove block if placeEvent is canceled
|
|
BlockSnapshot snapshot = BlockSnapshot.create(world.dimension(), world, pos);
|
|
BlockEvent.EntityPlaceEvent placeEvent = new BlockEvent.EntityPlaceEvent(snapshot, block, player);
|
|
MinecraftForge.EVENT_BUS.post(placeEvent);
|
|
if(placeEvent.isCanceled()) {
|
|
world.removeBlock(pos, false);
|
|
return false;
|
|
}
|
|
|
|
ItemStack stack;
|
|
if(item == null) stack = new ItemStack(block.getBlock().asItem());
|
|
else {
|
|
stack = new ItemStack(item);
|
|
player.awardStat(Stats.ITEM_USED.get(item));
|
|
}
|
|
|
|
// Call OnBlockPlaced method
|
|
block.getBlock().setPlacedBy(world, pos, block, player, stack);
|
|
|
|
return true;
|
|
}
|
|
|
|
public static boolean removeBlock(Level world, Player player, @Nullable BlockState block, BlockPos pos) {
|
|
BlockState currentBlock = world.getBlockState(pos);
|
|
|
|
if(!world.mayInteract(player, pos)) return false;
|
|
|
|
if(!player.isCreative()) {
|
|
if(currentBlock.getDestroySpeed(world, pos) <= -1 || world.getBlockEntity(pos) != null) return false;
|
|
|
|
if(block != null)
|
|
if(!ReplacementRegistry.matchBlocks(currentBlock.getBlock(), block.getBlock())) return false;
|
|
}
|
|
|
|
BlockEvent.BreakEvent breakEvent = new BlockEvent.BreakEvent(world, pos, currentBlock, player);
|
|
MinecraftForge.EVENT_BUS.post(breakEvent);
|
|
if(breakEvent.isCanceled()) return false;
|
|
|
|
world.removeBlock(pos, false);
|
|
return true;
|
|
}
|
|
|
|
public static int countItem(Player player, Item item) {
|
|
if(player.getInventory().items == null) return 0;
|
|
if(player.isCreative()) return Integer.MAX_VALUE;
|
|
|
|
int total = 0;
|
|
ContainerManager containerManager = ConstructionWand.instance.containerManager;
|
|
List<ItemStack> inventory = WandUtil.getFullInv(player);
|
|
|
|
for(ItemStack stack : inventory) {
|
|
if(stack == null) continue;
|
|
|
|
if(WandUtil.stackEquals(stack, item)) {
|
|
total += stack.getCount();
|
|
}
|
|
else {
|
|
int amount = containerManager.countItems(player, new ItemStack(item), stack);
|
|
if(amount == Integer.MAX_VALUE) return Integer.MAX_VALUE;
|
|
total += amount;
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
private static boolean isPositionModifiable(Level world, Player player, BlockPos pos) {
|
|
// Is position out of world?
|
|
if(!world.isInWorldBounds(pos)) return false;
|
|
|
|
// Is block modifiable?
|
|
if(!world.mayInteract(player, pos)) return false;
|
|
|
|
// Limit range
|
|
if(ConfigServer.MAX_RANGE.get() > 0 &&
|
|
WandUtil.blockDistance(player.blockPosition(), pos) > ConfigServer.MAX_RANGE.get()) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Tests if a wand can place a block at a certain position.
|
|
* This check is independent of the used block.
|
|
*/
|
|
public static boolean isPositionPlaceable(Level world, Player player, BlockPos pos, boolean replace) {
|
|
if(!isPositionModifiable(world, player, pos)) return false;
|
|
|
|
// If replace mode is off, target has to be air
|
|
if(world.isEmptyBlock(pos)) return true;
|
|
|
|
// Otherwise, check if the block can be replaced by a generic block
|
|
return replace && world.getBlockState(pos).canBeReplaced(
|
|
new WandItemUseContext(world, player,
|
|
new BlockHitResult(new Vec3(0, 0, 0), Direction.DOWN, pos, false),
|
|
pos, (BlockItem) Items.STONE));
|
|
}
|
|
|
|
public static boolean isBlockRemovable(Level world, Player player, BlockPos pos) {
|
|
if(!isPositionModifiable(world, player, pos)) return false;
|
|
|
|
if(!player.isCreative()) {
|
|
return !(world.getBlockState(pos).getDestroySpeed(world, pos) <= -1) && world.getBlockEntity(pos) == null;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static boolean isBlockPermeable(Level world, BlockPos pos) {
|
|
return world.isEmptyBlock(pos) || world.getBlockState(pos).getCollisionShape(world, pos).isEmpty();
|
|
}
|
|
|
|
public static boolean entitiesCollidingWithBlock(Level world, BlockState blockState, BlockPos pos) {
|
|
VoxelShape shape = blockState.getCollisionShape(world, pos);
|
|
if(!shape.isEmpty()) {
|
|
AABB blockBB = shape.bounds().move(pos);
|
|
return !world.getEntitiesOfClass(LivingEntity.class, blockBB, Predicate.not(Entity::isSpectator)).isEmpty();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static Direction fromVector(Vec3 vector) {
|
|
return Direction.getNearest(vector.x, vector.y, vector.z);
|
|
}
|
|
}
|