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

package com.hypixel.hytale.server.npc.role.support;

import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap;
import com.hypixel.hytale.server.npc.asset.builder.BuilderManager;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.builtin.tagset.TagSetPlugin;
import com.hypixel.hytale.builtin.tagset.config.NPCGroup;
import com.hypixel.hytale.builtin.weather.resources.WeatherResource;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.npc.blackboard.view.attitude.ItemAttitudeMap;
import com.hypixel.hytale.server.npc.NPCPlugin;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.role.builders.BuilderRole;
import com.hypixel.hytale.server.npc.util.AttitudeMemoryEntry;
import com.hypixel.hytale.server.npc.blackboard.view.attitude.AttitudeView;
import com.hypixel.hytale.server.core.asset.type.attitude.Attitude;
import javax.annotation.Nullable;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.npc.corecomponents.BlockTarget;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.npc.blackboard.Blackboard;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ResourceType;

public class WorldSupport
{
    public static final double ATTITUDE_CACHE_CLEAR_FREQUENCY = 0.1;
    protected static final ResourceType<EntityStore, Blackboard> BLACKBOARD_RESOURCE_TYPE;
    protected final NPCEntity parent;
    protected Int2ObjectMap<BlockTarget> blockSensorCachedTargets;
    @Nullable
    protected Vector3d[] searchRayCachedPositions;
    protected String blockToPlace;
    protected final Attitude defaultPlayerAttitude;
    protected final Attitude defaultNPCAttitude;
    protected final int attitudeGroup;
    protected final int itemAttitudeGroup;
    protected AttitudeView attitudeView;
    protected Int2ObjectMap<Attitude> attitudeCache;
    protected Int2ObjectMap<AttitudeMemoryEntry> attitudeOverrideMemory;
    protected double nextAttitudeCacheClear;
    protected boolean newPathRequested;
    protected int changeCount;
    protected int environmentIdChangeCount;
    protected int cachedEnvironmentId;
    protected int weatherChangeCount;
    protected int cachedWeatherIndex;
    
    public WorldSupport(final NPCEntity parent, @Nonnull final BuilderRole builder, @Nonnull final BuilderSupport support) {
        this.nextAttitudeCacheClear = 0.1;
        this.cachedEnvironmentId = Integer.MIN_VALUE;
        this.parent = parent;
        this.defaultPlayerAttitude = builder.getDefaultPlayerAttitude(support);
        this.defaultNPCAttitude = builder.getDefaultNPCAttitude(support);
        this.attitudeGroup = builder.getAttitudeGroup(support);
        this.itemAttitudeGroup = builder.getItemAttitudeGroup(support);
    }
    
    public void tick(final float dt) {
        if (this.attitudeOverrideMemory != null && !this.attitudeOverrideMemory.isEmpty()) {
            final ObjectIterator<AttitudeMemoryEntry> iterator = this.attitudeOverrideMemory.values().iterator();
            while (iterator.hasNext()) {
                final AttitudeMemoryEntry entry = iterator.next();
                entry.tick(dt);
                if (entry.isExpired()) {
                    iterator.remove();
                }
            }
        }
        if (this.attitudeCache != null) {
            final double nextAttitudeCacheClear = this.nextAttitudeCacheClear - dt;
            this.nextAttitudeCacheClear = nextAttitudeCacheClear;
            if (nextAttitudeCacheClear <= 0.0) {
                this.attitudeCache.clear();
                this.nextAttitudeCacheClear = 0.1;
            }
        }
        ++this.changeCount;
    }
    
    public void postRoleBuilt(@Nonnull final BuilderSupport support) {
        if (support.requiresBlockTypeBlackboard()) {
            final IntList blackboardBlockSets = support.getBlockTypeBlackboardBlockSets();
            final Int2ObjectOpenHashMap<BlockTarget> cachedTargets = new Int2ObjectOpenHashMap<BlockTarget>(blackboardBlockSets.size());
            for (int i = 0; i < blackboardBlockSets.size(); ++i) {
                cachedTargets.put(blackboardBlockSets.getInt(i), new BlockTarget());
            }
            cachedTargets.trim();
            this.blockSensorCachedTargets = Int2ObjectMaps.unmodifiable((Int2ObjectMap<? extends BlockTarget>)cachedTargets);
            this.parent.addBlackboardBlockTypeSets(blackboardBlockSets);
        }
        if (support.requiresAttitudeOverrideMemory()) {
            this.attitudeOverrideMemory = new Int2ObjectOpenHashMap<AttitudeMemoryEntry>();
        }
        this.searchRayCachedPositions = support.allocateSearchRayPositionSlots();
    }
    
    public BlockTarget getCachedBlockTarget(final int blockSet) {
        return this.blockSensorCachedTargets.get(blockSet);
    }
    
    public void resetBlockSensorFoundBlock(final int blockSet) {
        this.blockSensorCachedTargets.get(blockSet).reset(this.parent);
    }
    
    public void resetAllBlockSensors() {
        if (this.blockSensorCachedTargets == null) {
            return;
        }
        final ObjectIterator<Int2ObjectMap.Entry<BlockTarget>> it = Int2ObjectMaps.fastIterator(this.blockSensorCachedTargets);
        while (it.hasNext()) {
            final Int2ObjectMap.Entry<BlockTarget> next = it.next();
            next.getValue().reset(this.parent);
        }
    }
    
    public Vector3d getCachedSearchRayPosition(final int id) {
        return this.searchRayCachedPositions[id];
    }
    
    public void resetCachedSearchRayPosition(final int id) {
        this.searchRayCachedPositions[id].assign(Vector3d.MIN);
    }
    
    public void resetAllCachedSearchRayPositions() {
        for (final Vector3d cachedPosition : this.searchRayCachedPositions) {
            cachedPosition.assign(Vector3d.MIN);
        }
    }
    
    public void setBlockToPlace(final String block) {
        this.blockToPlace = block;
    }
    
    public String getBlockToPlace() {
        return this.blockToPlace;
    }
    
    public Attitude getDefaultPlayerAttitude() {
        return this.defaultPlayerAttitude;
    }
    
    public Attitude getDefaultNPCAttitude() {
        return this.defaultNPCAttitude;
    }
    
    public int getAttitudeGroup() {
        return this.attitudeGroup;
    }
    
    public int getItemAttitudeGroup() {
        return this.itemAttitudeGroup;
    }
    
    @Nonnull
    public Attitude getAttitude(@Nonnull final Ref<EntityStore> ref, @Nonnull final Ref<EntityStore> targetRef, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        Attitude attitude = this.attitudeCache.getOrDefault(targetRef.getIndex(), null);
        if (attitude != null) {
            return attitude;
        }
        if (this.attitudeView == null) {
            this.attitudeView = componentAccessor.getResource(WorldSupport.BLACKBOARD_RESOURCE_TYPE).getView(AttitudeView.class, this.parent.getReference(), componentAccessor);
        }
        else {
            this.attitudeView = this.attitudeView.getUpdatedView(this.parent.getReference(), componentAccessor);
        }
        attitude = this.attitudeView.getAttitude(ref, this.parent.getRole(), targetRef, componentAccessor);
        this.attitudeCache.put(targetRef.getIndex(), attitude);
        return attitude;
    }
    
    @Nullable
    public Attitude getItemAttitude(@Nullable final ItemStack item) {
        final ItemAttitudeMap attitudeMap = NPCPlugin.get().getItemAttitudeMap();
        return attitudeMap.getAttitude(this.parent, item);
    }
    
    public void overrideAttitude(final Ref<EntityStore> target, final Attitude attitude, final double duration) {
        this.attitudeOverrideMemory.put(target.getIndex(), new AttitudeMemoryEntry(attitude, duration));
        if (this.attitudeCache != null) {
            this.attitudeCache.remove(target.getIndex());
        }
    }
    
    @Nullable
    public Attitude getOverriddenAttitude(final Ref<EntityStore> target) {
        if (this.attitudeOverrideMemory == null) {
            return null;
        }
        final AttitudeMemoryEntry entry = this.attitudeOverrideMemory.get(target.getIndex());
        if (entry == null) {
            return null;
        }
        return entry.getAttitudeOverride();
    }
    
    public void requireAttitudeCache() {
        if (this.attitudeCache == null) {
            this.attitudeCache = new Int2ObjectOpenHashMap<Attitude>();
        }
    }
    
    public void requestNewPath() {
        this.newPathRequested = true;
    }
    
    public boolean hasRequestedNewPath() {
        return this.newPathRequested;
    }
    
    public boolean consumeNewPathRequested() {
        final boolean requested = this.newPathRequested;
        this.newPathRequested = false;
        return requested;
    }
    
    public int getEnvironmentId(@Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (this.environmentIdChangeCount != this.changeCount) {
            this.environmentIdChangeCount = this.changeCount;
            final TransformComponent transformComponent = componentAccessor.getComponent(this.parent.getReference(), TransformComponent.getComponentType());
            assert transformComponent != null;
            final Ref<ChunkStore> chunkRef = transformComponent.getChunkRef();
            if (chunkRef == null || !chunkRef.isValid()) {
                return Integer.MIN_VALUE;
            }
            final World world = componentAccessor.getExternalData().getWorld();
            final Store<ChunkStore> chunkStore = world.getChunkStore().getStore();
            final BlockChunk blockChunkComponent = chunkStore.getComponent(chunkRef, BlockChunk.getComponentType());
            assert blockChunkComponent != null;
            this.cachedEnvironmentId = blockChunkComponent.getEnvironment(transformComponent.getPosition());
        }
        return this.cachedEnvironmentId;
    }
    
    public int getCurrentWeatherIndex(@Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (this.weatherChangeCount != this.changeCount) {
            this.weatherChangeCount = this.changeCount;
            final WeatherResource weatherResource = componentAccessor.getResource(WeatherResource.getResourceType());
            this.cachedWeatherIndex = weatherResource.getForcedWeatherIndex();
            if (this.cachedWeatherIndex != 0) {
                return this.cachedWeatherIndex;
            }
            final int environmentId = this.getEnvironmentId(componentAccessor);
            if (environmentId == Integer.MIN_VALUE) {
                return this.cachedWeatherIndex = 0;
            }
            this.cachedWeatherIndex = weatherResource.getWeatherIndexForEnvironment(environmentId);
        }
        return this.cachedWeatherIndex;
    }
    
    public static boolean hasTagInGroup(final int group, final int tag) {
        return TagSetPlugin.get(NPCGroup.class).tagInSet(group, tag);
    }
    
    public static boolean isGroupMember(final int parentRoleIndex, @Nonnull final Ref<EntityStore> ref, @Nullable final int[] groups, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (groups == null) {
            return false;
        }
        for (final int group : groups) {
            if (isGroupMember(parentRoleIndex, ref, group, componentAccessor)) {
                return true;
            }
        }
        return false;
    }
    
    public static boolean isGroupMember(final int parentRoleIndex, @Nullable final Ref<EntityStore> ref, final int group, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        if (ref == null || !ref.isValid()) {
            return false;
        }
        final NPCEntity npcComponent = componentAccessor.getComponent(ref, NPCEntity.getComponentType());
        int targetId;
        if (npcComponent != null) {
            targetId = npcComponent.getRoleIndex();
        }
        else {
            if (!componentAccessor.getArchetype(ref).contains(Player.getComponentType())) {
                return false;
            }
            targetId = BuilderManager.getPlayerGroupID();
        }
        return (targetId == parentRoleIndex && hasTagInGroup(group, BuilderManager.getSelfGroupID())) || hasTagInGroup(group, targetId);
    }
    
    public static int[] createTagSetIndexArray(@Nullable final String[] tagSets) {
        if (tagSets == null) {
            return null;
        }
        final int[] groups = new int[tagSets.length];
        final IndexedLookupTableAssetMap<String, NPCGroup> npcGroups = NPCGroup.getAssetMap();
        for (int i = 0; i < tagSets.length; ++i) {
            final String tagSet = tagSets[i];
            final int index = npcGroups.getIndex(tagSet);
            if (index == Integer.MIN_VALUE) {
                throw new IllegalArgumentException("Unknown npc group! " + tagSet);
            }
            groups[i] = index;
        }
        return groups;
    }
    
    public void unloaded() {
        this.resetAllBlockSensors();
        if (this.searchRayCachedPositions != null) {
            for (int i = 0; i < this.searchRayCachedPositions.length; ++i) {
                this.resetCachedSearchRayPosition(i);
            }
        }
        if (this.attitudeOverrideMemory != null) {
            this.attitudeOverrideMemory.clear();
        }
    }
    
    static {
        BLACKBOARD_RESOURCE_TYPE = Blackboard.getResourceType();
    }
}
