// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.corecomponents.world;

import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider;
import com.hypixel.hytale.server.core.universe.world.chunk.section.blockpositions.IBlockPositionData;
import com.hypixel.hytale.server.npc.blackboard.view.blocktype.BlockTypeView;
import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.npc.corecomponents.BlockTarget;
import com.hypixel.hytale.server.core.universe.world.World;
import java.util.logging.Level;
import com.hypixel.hytale.server.npc.blackboard.view.BlockRegionView;
import com.hypixel.hytale.server.npc.blackboard.Blackboard;
import com.hypixel.hytale.server.npc.blackboard.view.resource.ResourceView;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.npc.corecomponents.builders.BuilderSensorBase;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.corecomponents.world.builders.BuilderSensorBlock;
import com.hypixel.hytale.server.npc.sensorinfo.PositionProvider;
import com.hypixel.hytale.server.npc.corecomponents.SensorBase;

public class SensorBlock extends SensorBase
{
    protected final double range;
    protected final double yRange;
    protected final int blockSet;
    protected final boolean pickRandom;
    protected final boolean reserveBlock;
    protected final PositionProvider positionProvider;
    
    public SensorBlock(@Nonnull final BuilderSensorBlock builder, @Nonnull final BuilderSupport support) {
        super(builder);
        this.positionProvider = new PositionProvider();
        this.range = builder.getRange(support);
        this.yRange = builder.getYRange(support);
        this.blockSet = builder.getBlockSet(support);
        this.pickRandom = builder.isPickRandom(support);
        this.reserveBlock = builder.isReserveBlock(support);
        support.requireBlockTypeBlackboard(this.blockSet);
    }
    
    @Override
    public boolean matches(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final double dt, @Nonnull final Store<EntityStore> store) {
        if (!super.matches(ref, role, dt, store)) {
            this.positionProvider.clear();
            return false;
        }
        final World world = store.getExternalData().getWorld();
        final TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType());
        assert transformComponent != null;
        final Vector3d entityPos = transformComponent.getPosition();
        final NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType());
        assert npcComponent != null;
        final BlockTarget target = role.getWorldSupport().getCachedBlockTarget(this.blockSet);
        final Vector3d position = target.getPosition();
        if (!position.equals(Vector3d.MIN)) {
            final WorldChunk targetChunk = world.getChunkIfInMemory(ChunkUtil.indexChunkFromBlock(position.x, position.z));
            if (targetChunk != null) {
                final BlockSection section = targetChunk.getBlockChunk().getSectionAtBlockY(MathUtil.floor(position.y));
                if (section.getLocalChangeCounter() == target.getChunkChangeRevision() || section.get(MathUtil.floor(position.x), MathUtil.floor(position.y), MathUtil.floor(position.z)) == target.getFoundBlockType()) {
                    if (Math.abs(entityPos.y - position.y) > this.yRange || entityPos.distanceSquaredTo(position) > this.range * this.range) {
                        this.positionProvider.clear();
                        return false;
                    }
                    this.positionProvider.setTarget(position);
                    return true;
                }
            }
        }
        if (target.isActive()) {
            target.reset(npcComponent);
        }
        final BlockTypeView blackboard = npcComponent.getBlockTypeBlackboardView(ref, store);
        final IBlockPositionData blockData = blackboard.findBlock(this.blockSet, this.range, this.yRange, this.pickRandom, ref, store);
        if (blockData == null) {
            this.positionProvider.clear();
            return false;
        }
        position.assign(blockData.getXCentre(), blockData.getYCentre(), blockData.getZCentre());
        final int blockTypeId = blockData.getBlockType();
        target.setFoundBlockType(blockTypeId);
        target.setChunkChangeRevision(blockData.getChunkSection().getLocalChangeCounter());
        final BlockType blockType = BlockType.getAssetMap().getAsset(blockTypeId);
        if (this.reserveBlock || !blockType.isAllowsMultipleUsers()) {
            final ResourceView resourceView = store.getResource(Blackboard.getResourceType()).getView(ResourceView.class, BlockRegionView.indexViewFromWorldPosition(position));
            resourceView.reserveBlock(npcComponent, blockData.getX(), blockData.getY(), blockData.getZ());
            target.setReservationHolder(resourceView);
            Blackboard.LOGGER.at(Level.FINE).log("Entity %s reserved block from set %s at %s", npcComponent.getRoleName(), this.blockSet, position);
        }
        Blackboard.LOGGER.at(Level.FINE).log("Entity %s found block from set %s at %s", npcComponent.getRoleName(), this.blockSet, position);
        this.positionProvider.setTarget(position);
        return true;
    }
    
    @Override
    public InfoProvider getSensorInfo() {
        return this.positionProvider;
    }
}
