package com.gulgdev.mechanism.block.custom;
import com.gulgdev.mechanism.block.ModBlocks;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.items.ItemStackHandler;
import oshi.util.tuples.Pair;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import static java.lang.Math.abs;
public class MotorBlockEntity extends BlockEntity {
public static final int movingLimit = 8;
public static final List<Block> nonMovable = Arrays.asList(
Blocks.BEDROCK,
Blocks.OBSIDIAN
);
public final ItemStackHandler items;
public MotorBlockEntity(BlockPos pos, BlockState state) {
super(ModBlocks.MOTOR_BLOCK_ENTITY.get(), pos, state);
items = new ItemStackHandler(4) {
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
return super.extractItem(slot, amount, simulate);
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
return super.insertItem(slot, stack, simulate);
}
};
}
public static <T extends BlockEntity> void tick(Level level, BlockPos pos, BlockState state, T be) {
if (level.isClientSide()) return;
new Thread(() -> {
MotorBlockEntity entity = (MotorBlockEntity) be;
Map<BlockPos, Pair<BlockState, BlockEntity>> blocks = FindStructureBlocks(level, pos, movingLimit);
Map<BlockPos, BlockPos> moving = GetMovingMap(level, blocks, Direction.UP);//state.getValue(BlockStateProperties.FACING));
if (moving == null) return;
MoveStructure(level, pos, movingLimit, blocks, moving, true);
}).start();
}
private static Map<BlockPos, Pair<BlockState, BlockEntity>> FindStructureBlocks(Level level, BlockPos start, int limit) {
Map<BlockPos, Pair<BlockState, BlockEntity>> blocks = new HashMap<BlockPos, Pair<BlockState, BlockEntity>>();
blocks.put(start, new Pair<BlockState, BlockEntity>(level.getBlockState(start), level.getBlockEntity(start)));
for (Direction direction : Direction.values()) {
FindingBranch(level, blocks, start, start, direction, limit);
}
return blocks;
}
private static void FindingBranch(Level level, Map<BlockPos, Pair<BlockState, BlockEntity>> blocks, BlockPos center, BlockPos start, Direction direction, int limit) {
BlockPos pos = start.relative(direction);
if (!(level.getBlockState(pos).isAir() || nonMovable.contains(level.getBlockState(pos).getBlock()) ||
abs(center.getX() - pos.getX()) >= limit ||
abs(center.getY() - pos.getY()) >= limit ||
abs(center.getZ() - pos.getZ()) >= limit)) {
try {
Minecraft.getInstance().player.chat(level.getBlockEntity(pos).serializeNBT().toString());
} catch (NullPointerException e) {
Minecraft.getInstance().player.chat("no nbt at " + pos.toString());
}
blocks.put(pos, new Pair<BlockState, BlockEntity>(level.getBlockState(pos), level.getBlockEntity(pos)));
for (Direction dir : Direction.values()) {
if (!blocks.containsKey(pos.relative(dir))) {
FindingBranch(level, blocks, center, pos, dir, limit);
}
}
}
}
private static Map<BlockPos, BlockPos> GetMovingMap(Level level, Map<BlockPos, Pair<BlockState, BlockEntity>> blocks, Direction direction) {
Map<BlockPos, BlockPos> moving = new HashMap<BlockPos, BlockPos>();
for (BlockPos position : blocks.keySet()) {
BlockPos target = position.relative(direction);
if (!level.getBlockState(target).isAir() && !blocks.containsKey(target)) return null;
moving.put(position, target);
}
return moving;
}
private static void UpdateBlocks(Level level, BlockPos[] blocks) {
for (BlockPos block : blocks) {
BlockState state = level.getBlockState(block);
if (state.getMaterial().isSolid())
level.sendBlockUpdated(block, state, state, 0);
}
for (BlockPos block : blocks) {
BlockState state = level.getBlockState(block);
if (!state.getMaterial().isSolid())
level.sendBlockUpdated(block, state, state, 0);
}
}
private static void ClearStructure(Level level, Map<BlockPos, Pair<BlockState, BlockEntity>> blocks) {
for (BlockPos pos : blocks.keySet()) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 0);
}
UpdateBlocks(level, blocks.keySet().toArray(new BlockPos[0]));
}
private static void MoveStructure(Level level, BlockPos center, int limit, Map<BlockPos, Pair<BlockState, BlockEntity>> blocks, Map<BlockPos, BlockPos> moving, boolean moveEntities) {
ClearStructure(level, blocks);
List<Entity> entities = null;
if (moveEntities) {
entities = level.getEntities(null, AABB.ofSize(new Vec3(center.getX(), center.getY(), center.getZ()), limit * 2 + 1, limit * 2 + 1, limit * 2 + 1));
}
for (Map.Entry<BlockPos, Pair<BlockState, BlockEntity>> entry : blocks.entrySet()) {
BlockPos from = entry.getKey();
BlockPos to = moving.get(from);
BlockState blockState = entry.getValue().getA();
BlockEntity blockEntity = entry.getValue().getB();
if (moveEntities) {
for (Entity entity : entities) {
if (to.getX() == entity.getBlockX() && from.getY() + 1 == entity.getBlockY() && to.getZ() == entity.getBlockZ()) {
entity.moveTo(new Vec3(to.getX(), to.getY() + 1, to.getZ()));
}
}
}
if (blockState.getMaterial().isSolid()) {
level.setBlock(to, blockState, 0);
try {
BlockEntity be = blockEntity.getClass().getConstructor().newInstance(new Object[] { to, blockState });
be.deserializeNBT(blockEntity.serializeNBT());
level.setBlockEntity(be);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | NullPointerException e) {
e.printStackTrace();
}
}
}
for (Map.Entry<BlockPos, Pair<BlockState, BlockEntity>> entry : blocks.entrySet()) {
BlockPos from = entry.getKey();
BlockPos to = moving.get(from);
BlockState blockState = entry.getValue().getA();
BlockEntity blockEntity = entry.getValue().getB();
if (!blockState.getMaterial().isSolid()) {
level.setBlock(to, blockState, 0);
try {
BlockEntity be = blockEntity.getClass().getConstructor().newInstance(new Object[] { to, blockState });
Minecraft.getInstance().player.chat(blockEntity.serializeNBT().toString());
be.deserializeNBT(blockEntity.serializeNBT());
level.setBlockEntity(be);
} catch (NullPointerException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}
}
UpdateBlocks(level, moving.values().toArray(new BlockPos[0]));
}
}