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

package com.hypixel.hytale.server.npc.commands;

import com.hypixel.hytale.server.npc.blackboard.view.event.EventView;
import com.hypixel.hytale.server.npc.blackboard.view.interaction.ReservationStatus;
import com.hypixel.hytale.server.npc.blackboard.view.interaction.InteractionView;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.util.TargetUtil;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgumentType;
import com.hypixel.hytale.server.core.command.system.arguments.types.EntityWrappedArg;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import com.hypixel.hytale.server.npc.blackboard.view.resource.ResourceView;
import com.hypixel.hytale.server.npc.blackboard.view.event.entity.EntityEventType;
import com.hypixel.hytale.builtin.tagset.config.NPCGroup;
import com.hypixel.hytale.server.npc.blackboard.view.event.entity.EntityEventView;
import com.hypixel.hytale.server.npc.blackboard.view.event.block.BlockEventType;
import java.util.UUID;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.server.npc.blackboard.view.event.block.BlockEventView;
import it.unimi.dsi.fastutil.ints.IntList;
import java.util.Set;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import com.hypixel.hytale.math.vector.Vector2i;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.core.command.system.arguments.types.RelativeChunkPosition;
import com.hypixel.hytale.server.npc.blackboard.view.blocktype.BlockTypeView;
import com.hypixel.hytale.server.npc.blackboard.Blackboard;
import com.hypixel.hytale.server.core.universe.world.chunk.section.blockpositions.IBlockPositionData;
import java.util.BitSet;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.asset.type.blockset.config.BlockSet;
import com.hypixel.hytale.server.npc.blackboard.view.BlockRegionView;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
import com.hypixel.hytale.server.core.command.system.arguments.types.RelativeIntPosition;
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
import java.util.List;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.query.AndQuery;
import java.util.logging.Level;
import com.hypixel.hytale.server.npc.NPCPlugin;
import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkSection;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.server.core.universe.world.chunk.section.blockpositions.BlockPositionProvider;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.World;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractWorldCommand;
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection;

public class NPCBlackboardCommand extends AbstractCommandCollection
{
    public NPCBlackboardCommand() {
        super("blackboard", "server.commands.npc.blackboard.desc");
        this.addSubCommand(new ChunksCommand());
        this.addSubCommand(new ChunkCommand());
        this.addSubCommand(new DropCommand());
        this.addSubCommand(new ViewsCommand());
        this.addSubCommand(new ViewCommand());
        this.addSubCommand(new BlockEventsCommand());
        this.addSubCommand(new EntityEventsCommand());
        this.addSubCommand(new ResourceViewsCommand());
        this.addSubCommand(new ResourceViewCommand());
        this.addSubCommand(new ReserveCommand());
        this.addSubCommand(new ReservationCommand());
    }
    
    public static class ChunksCommand extends AbstractWorldCommand
    {
        static final /* synthetic */ boolean $assertionsDisabled;
        
        public ChunksCommand() {
            super("chunks", "server.commands.npc.blackboard.chunks.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final Store<ChunkStore> chunkStore = world.getChunkStore().getStore();
            final StringBuilder sb = new StringBuilder("Blackboard chunk info:\n");
            final int[] count = { 0 };
            chunkStore.forEachChunk(BlockPositionProvider.getComponentType(), (archetypeChunk, commandBuffer) -> {
                final int n;
                count[n] += archetypeChunk.size();
                return;
            });
            sb.append(" Total sections: ").append(count[0]).append('\n');
            sb.append(" Chunk sections:\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.chunks.chunkInfo").param("nb", count[0]);
            final AndQuery<ChunkStore> query = Query.and(ChunkSection.getComponentType(), BlockPositionProvider.getComponentType());
            chunkStore.forEachChunk(query, (archetypeChunk, commandBuffer) -> {
                int index = 0;
                while (index < archetypeChunk.size()) {
                    final BlockPositionProvider blockPositionProviderComponent = archetypeChunk.getComponent(index, BlockPositionProvider.getComponentType());
                    if (!ChunksCommand.$assertionsDisabled && blockPositionProviderComponent == null) {
                        throw new AssertionError();
                    }
                    else {
                        final ChunkSection chunkSectionComponent = archetypeChunk.getComponent(index, ChunkSection.getComponentType());
                        if (!ChunksCommand.$assertionsDisabled && chunkSectionComponent == null) {
                            throw new AssertionError();
                        }
                        else {
                            final int x = chunkSectionComponent.getX();
                            final int z = chunkSectionComponent.getZ();
                            sb.append(' ').append(x).append(", ").append(chunkSectionComponent.getY()).append(", ").append(z);
                            final int[] entryCount = { 0 };
                            blockPositionProviderComponent.forEachBlockSet((set, data) -> {
                                final int n3;
                                entryCount[n3] += data.size();
                                return;
                            });
                            sb.append(" (").append(entryCount[0]).append(" entries, ").append(blockPositionProviderComponent.getSearchedBlockSets().cardinality()).append(" BlockSets)\n");
                            msg.insert(Message.translation("server.commands.npc.blackboard.chunks.detailed_entry").param("x", x).param("y", chunkSectionComponent.getY()).param("z", z).param("count", entryCount[0]).param("blockSets", blockPositionProviderComponent.getSearchedBlockSets().cardinality()));
                            ++index;
                        }
                    }
                }
                return;
            });
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class ChunkCommand extends AbstractWorldCommand
    {
        @Nonnull
        private final RequiredArg<RelativeIntPosition> positionArg;
        
        public ChunkCommand() {
            super("chunk", "server.commands.npc.blackboard.chunk.desc");
            this.positionArg = this.withRequiredArg("position", "server.commands.npc.blackboard.chunk.position.desc", ArgTypes.RELATIVE_BLOCK_POSITION);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final Vector3i blockPosition = this.positionArg.get(context).getBlockPosition(context, store);
            final Vector3i position = new Vector3i(ChunkUtil.chunkCoordinate(blockPosition.x), ChunkUtil.chunkCoordinate(blockPosition.y), ChunkUtil.chunkCoordinate(blockPosition.z));
            final long chunkIndex = ChunkUtil.indexChunk(position.x, position.z);
            final StringBuilder sb = new StringBuilder("Blackboard chunk entry " + chunkIndex);
            sb.append(" (").append(position.x).append(", ").append(position.y).append(", ").append(position.z).append("):\n");
            sb.append(" Partial blackboard grid coordinates: ");
            sb.append(BlockRegionView.chunkToRegionalBlackboardCoordinate(position.x)).append(", ");
            sb.append(BlockRegionView.chunkToRegionalBlackboardCoordinate(position.z)).append('\n');
            final Message msg = Message.translation("server.commands.npc.blackboard.chunk.entry").param("index", chunkIndex).param("chunkX", position.x).param("chunkY", position.y).param("chunkZ", position.z).param("regionChunkX", BlockRegionView.chunkToRegionalBlackboardCoordinate(position.x)).param("regionChunkZ", BlockRegionView.chunkToRegionalBlackboardCoordinate(position.z)).insert("\n");
            final ChunkStore chunkStore = world.getChunkStore();
            final Store<ChunkStore> chunkStoreStore = chunkStore.getStore();
            final Ref<ChunkStore> chunkSection = chunkStore.getChunkSectionReference(position.x, position.y, position.z);
            if (chunkSection == null) {
                sb.append(" Chunk not loaded");
                msg.insert(Message.translation("server.commands.npc.blackboard.chunk.notLoaded"));
            }
            else {
                final BlockPositionProvider entry = chunkStoreStore.getComponent(chunkSection, BlockPositionProvider.getComponentType());
                if (entry == null) {
                    sb.append(" No entry exists");
                    msg.insert(Message.translation("server.commands.npc.blackboard.chunk.noEntry"));
                }
                else {
                    sb.append(" Searched BlockSets: [ ");
                    msg.insert(Message.translation("server.commands.npc.blockSetsSearched"));
                    final BitSet searchedBlockSets = entry.getSearchedBlockSets();
                    boolean subsequent = false;
                    for (int i = searchedBlockSets.nextSetBit(0); i >= 0; i = searchedBlockSets.nextSetBit(i + 1)) {
                        if (subsequent) {
                            sb.append(", ");
                            msg.insert(", ");
                        }
                        sb.append(BlockSet.getAssetMap().getAsset(i).getId());
                        msg.insert(BlockSet.getAssetMap().getAsset(i).getId());
                        subsequent = true;
                        if (i == Integer.MAX_VALUE) {
                            break;
                        }
                    }
                    sb.append("""
                               ]
                               Entries:
                              """);
                    msg.insert(Message.translation("server.commands.npc.blackboard.chunk.entries"));
                    entry.forEachBlockSet((blockSet, list) -> {
                        sb.append("  BlockSet: ").append(BlockSet.getAssetMap().getAsset(blockSet).getId()).append("\n   Blocks:\n");
                        msg.insert(Message.translation("server.commands.npc.blackboard.chunk.blockSet").param("id", BlockSet.getAssetMap().getAsset(blockSet).getId()));
                        msg.insert("\n");
                        list.forEach(dataEntry -> {
                            sb.append("    [ ").append(BlockType.getAssetMap().getAsset(dataEntry.getBlockType()).getId());
                            sb.append(" (").append(dataEntry.getX()).append(", ").append(dataEntry.getY()).append(", ").append(dataEntry.getZ()).append(") ]\n");
                            msg.insert("    [ " + BlockType.getAssetMap().getAsset(dataEntry.getBlockType()).getId() + " (" + dataEntry.getX() + ", " + dataEntry.getY() + ", " + dataEntry.getZ() + ") ]");
                        });
                        return;
                    });
                }
            }
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class DropCommand extends AbstractWorldCommand
    {
        public DropCommand() {
            super("drop", "server.commands.npc.blackboard.drop.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            store.getResource(Blackboard.getResourceType()).clear();
            context.sendMessage(Message.translation("server.commands.npc.blackboard.cleared"));
        }
    }
    
    public static class ViewsCommand extends AbstractWorldCommand
    {
        public ViewsCommand() {
            super("views", "server.commands.npc.blackboard.views.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final StringBuilder sb = new StringBuilder("Blackboard views:\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.views.title");
            final Blackboard blackboard = store.getResource(Blackboard.getResourceType());
            final int[] count = { 0 };
            blackboard.forEachView(BlockTypeView.class, entry -> {
                final int n;
                ++count[n];
                return;
            });
            sb.append(" Total partial views: ").append(count[0]).append('\n').append(" Views:\n");
            msg.insert(Message.translation("server.commands.npc.blackboard.views.partialViews").param("count", count[0]));
            msg.insert("\n");
            blackboard.forEachView(BlockTypeView.class, entry -> {
                sb.append("  View (").append(BlockRegionView.xOfViewIndex(entry.getIndex())).append(", ").append(BlockRegionView.zOfViewIndex(entry.getIndex()));
                sb.append(") Entities: ").append(entry.getEntities().size()).append(", BlockSets: ").append(entry.getAllBlockSets().cardinality()).append('\n');
                msg.insert(Message.translation("server.commands.npc.blackboard.views.view").param("x", BlockRegionView.xOfViewIndex(entry.getIndex())).param("z", BlockRegionView.zOfViewIndex(entry.getIndex())).param("size", entry.getEntities().size()).param("cardinal", entry.getAllBlockSets().cardinality()));
                msg.insert("\n");
                return;
            });
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class ViewCommand extends AbstractWorldCommand
    {
        @Nonnull
        private final RequiredArg<RelativeChunkPosition> chunkArg;
        
        public ViewCommand() {
            super("view", "server.commands.npc.blackboard.view.desc");
            this.chunkArg = this.withRequiredArg("chunk", "server.commands.npc.blackboard.view.chunk.desc", ArgTypes.RELATIVE_CHUNK_POSITION);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final Vector2i chunkPosition = this.chunkArg.get(context).getChunkPosition(context, store);
            final long viewIndex = BlockRegionView.indexView(chunkPosition.x, chunkPosition.y);
            final Blackboard blackboard = store.getResource(Blackboard.getResourceType());
            final BlockTypeView view = blackboard.getView(BlockTypeView.class, viewIndex);
            final int viewX = BlockRegionView.xOfViewIndex(viewIndex);
            final int viewZ = BlockRegionView.zOfViewIndex(viewIndex);
            final StringBuilder sb = new StringBuilder("View (");
            sb.append(viewX).append(", ").append(viewZ).append(")\n");
            sb.append(" Spans world coordinates: (").append(BlockRegionView.toWorldCoordinate(viewX)).append(", ").append(BlockRegionView.toWorldCoordinate(viewZ));
            sb.append(") to (").append(BlockRegionView.toWorldCoordinate(viewX + 1)).append(", ").append(BlockRegionView.toWorldCoordinate(viewZ + 1)).append(")\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.view.title").param("x", viewX).param("z", viewZ);
            msg.insert(Message.translation("server.commands.npc.blackboard.view.coordinates").param("x1", BlockRegionView.toWorldCoordinate(viewX)).param("z1", BlockRegionView.toWorldCoordinate(viewZ)).param("x2", BlockRegionView.toWorldCoordinate(viewX + 1)).param("z2", BlockRegionView.toWorldCoordinate(viewZ + 1)));
            msg.insert("\n");
            if (view == null) {
                sb.append(" No partial view exists");
                msg.insert(Message.translation("server.commands.npc.blackboard.view.noPartialViews"));
            }
            else {
                sb.append(" Searched BlockSets: [ ");
                msg.insert(Message.translation("server.commands.npc.blockSetsSearched"));
                final BitSet searchedBlockSets = view.getAllBlockSets();
                final Int2IntMap counts = view.getBlockSetCounts();
                boolean subsequent = false;
                for (int i = searchedBlockSets.nextSetBit(0); i >= 0; i = searchedBlockSets.nextSetBit(i + 1)) {
                    if (subsequent) {
                        sb.append(", ");
                        msg.insert(", ");
                    }
                    sb.append(BlockSet.getAssetMap().getAsset(i).getId()).append(" (").append(counts.getOrDefault(i, 0)).append(')');
                    msg.insert(BlockSet.getAssetMap().getAsset(i).getId() + " (" + counts.getOrDefault(i, 0));
                    subsequent = true;
                    if (i == Integer.MAX_VALUE) {
                        break;
                    }
                }
                final Set<Ref<EntityStore>> entities = view.getEntities();
                sb.append(" ]\n Entities (").append(entities.size()).append("):\n");
                msg.insert(Message.translation("server.commands.npc.blackboard.view.entities").param("count", entities.size()));
                entities.forEach(ref -> {
                    sb.append("  [").append(ref.getIndex()).append("] ");
                    msg.insert("  [" + ref.getIndex() + "] ");
                    if (!ref.isValid()) {
                        sb.append("!!!INVALID ENTITY!!!");
                        msg.insert(Message.translation("server.commands.npc.blackboard.view.invalidEntity"));
                        return;
                    }
                    else {
                        final NPCEntity npc = store.getComponent(ref, NPCEntity.getComponentType());
                        if (npc == null) {
                            sb.append("!!!NON-NPC ENTITY!!!\n");
                            msg.insert(Message.translation("server.commands.npc.blackboard.view.nonNpcEntity"));
                            return;
                        }
                        else {
                            sb.append(npc.getRoleName()).append("\n    BlockSets: [ ");
                            msg.insert(Message.translation("server.commands.npc.blackboard.view.blockSets"));
                            final IntList blockSets = npc.getBlackboardBlockTypeSets();
                            for (int j = 0; j < blockSets.size(); ++j) {
                                if (j > 0) {
                                    sb.append(", ");
                                    msg.insert(", ");
                                }
                                final String blockSetId = BlockSet.getAssetMap().getAsset(blockSets.getInt(j)).getId();
                                sb.append(blockSetId);
                                msg.insert(blockSetId);
                            }
                            sb.append(" ]\n");
                            msg.insert(" ]\n");
                            return;
                        }
                    }
                });
            }
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class BlockEventsCommand extends AbstractWorldCommand
    {
        static final /* synthetic */ boolean $assertionsDisabled;
        
        public BlockEventsCommand() {
            super("blockevents", "server.commands.npc.blackboard.blockevents.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final BlockEventView blockEventView = store.getResource(Blackboard.getResourceType()).getView(BlockEventView.class, 0L);
            final StringBuilder sb = new StringBuilder("Block Event View:\n");
            sb.append(" Total BlockSets: ").append(blockEventView.getSetCount());
            sb.append("\n BlockSets:\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.blockevents.title").param("count", blockEventView.getSetCount());
            ((EventView<ViewType, BlockEventType, NotificationType>)blockEventView).forEach((b, t) -> {
                sb.append("  ").append(BlockSet.getAssetMap().getAsset(b).getId()).append(" (").append(t.get()).append("):\n");
                msg.insert("  " + BlockSet.getAssetMap().getAsset(b).getId() + " (" + t.get() + "):\n");
                return;
            }, e -> {
                final UUIDComponent uuidComponent = store.getComponent(e, UUIDComponent.getComponentType());
                if (!BlockEventsCommand.$assertionsDisabled && uuidComponent == null) {
                    throw new AssertionError();
                }
                else {
                    final UUID uuid = uuidComponent.getUuid();
                    final NPCEntity npcComponent = store.getComponent(e, NPCEntity.getComponentType());
                    if (!BlockEventsCommand.$assertionsDisabled && npcComponent == null) {
                        throw new AssertionError();
                    }
                    else {
                        final String roleName = npcComponent.getRoleName();
                        sb.append("   ").append(uuid).append(": ").append(roleName).append("\n");
                        msg.insert("   " + String.valueOf(uuid) + ": " + roleName);
                        return;
                    }
                }
            });
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class EntityEventsCommand extends AbstractWorldCommand
    {
        static final /* synthetic */ boolean $assertionsDisabled;
        
        public EntityEventsCommand() {
            super("entityevents", "server.commands.npc.blackboard.entityevents.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final EntityEventView view = store.getResource(Blackboard.getResourceType()).getView(EntityEventView.class, 0L);
            final StringBuilder sb = new StringBuilder("Entity Event View:\n");
            sb.append(" Total NPCGroups: ").append(view.getSetCount());
            sb.append("\n NPCGroups:\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.entityevents.title").param("count", view.getSetCount());
            ((EventView<ViewType, EntityEventType, NotificationType>)view).forEach((b, t) -> {
                sb.append("  ").append(NPCGroup.getAssetMap().getAsset(b).getId()).append(" (").append(t.get()).append("):\n");
                msg.insert("  " + NPCGroup.getAssetMap().getAsset(b).getId() + " (" + t.get() + "):\n");
                return;
            }, e -> {
                final UUIDComponent uuidComponent = store.getComponent(e, UUIDComponent.getComponentType());
                if (!EntityEventsCommand.$assertionsDisabled && uuidComponent == null) {
                    throw new AssertionError();
                }
                else {
                    final UUID uuid = uuidComponent.getUuid();
                    final NPCEntity npcComponent = store.getComponent(e, NPCEntity.getComponentType());
                    if (!EntityEventsCommand.$assertionsDisabled && npcComponent == null) {
                        throw new AssertionError();
                    }
                    else {
                        final String roleName = npcComponent.getRoleName();
                        sb.append("   ").append(uuid).append(": ").append(roleName).append("\n");
                        msg.insert("   " + String.valueOf(uuid) + ": " + roleName);
                        return;
                    }
                }
            });
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class ResourceViewsCommand extends AbstractWorldCommand
    {
        public ResourceViewsCommand() {
            super("resourceviews", "server.commands.npc.blackboard.resourceviews.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final StringBuilder sb = new StringBuilder("Resource views:\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.resourceviews.title");
            final Blackboard blackboard = store.getResource(Blackboard.getResourceType());
            final int[] count = { 0 };
            blackboard.forEachView(ResourceView.class, entry -> {
                final int n;
                ++count[n];
                return;
            });
            sb.append(" Total resource views: ").append(count[0]).append('\n').append(" Views:\n");
            msg.insert(Message.translation("server.commands.npc.blackboard.resourceviews.totalViews").param("count", count[0]));
            blackboard.forEachView(ResourceView.class, entry -> {
                sb.append("  View (").append(BlockRegionView.xOfViewIndex(entry.getIndex())).append(", ").append(BlockRegionView.zOfViewIndex(entry.getIndex()));
                sb.append(") Reservations: ").append(entry.getReservationsByEntity().size()).append('\n');
                msg.insert(Message.translation("server.commands.npc.blackboard.resourceviews.view").param("x", BlockRegionView.xOfViewIndex(entry.getIndex())).param("z", BlockRegionView.zOfViewIndex(entry.getIndex())).param("count", entry.getReservationsByEntity().size()));
                return;
            });
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class ResourceViewCommand extends AbstractWorldCommand
    {
        @Nonnull
        private final RequiredArg<RelativeChunkPosition> chunkArg;
        static final /* synthetic */ boolean $assertionsDisabled;
        
        public ResourceViewCommand() {
            super("resourceview", "server.commands.npc.blackboard.resourceview.desc");
            this.chunkArg = this.withRequiredArg("chunk", "server.commands.npc.blackboard.resourceview.chunk.desc", ArgTypes.RELATIVE_CHUNK_POSITION);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
            final Vector2i chunkPosition = this.chunkArg.get(context).getChunkPosition(context, store);
            final long viewIndex = BlockRegionView.indexView(chunkPosition.x, chunkPosition.y);
            final Blackboard blackboard = store.getResource(Blackboard.getResourceType());
            final ResourceView view = blackboard.getView(ResourceView.class, viewIndex);
            final int viewX = BlockRegionView.xOfViewIndex(viewIndex);
            final int viewZ = BlockRegionView.zOfViewIndex(viewIndex);
            final StringBuilder sb = new StringBuilder("View (");
            sb.append(viewX).append(", ").append(viewZ).append(")\n");
            sb.append(" Spans world coordinates: (").append(BlockRegionView.toWorldCoordinate(viewX)).append(", ").append(BlockRegionView.toWorldCoordinate(viewZ));
            sb.append(") to (").append(BlockRegionView.toWorldCoordinate(viewX + 1)).append(", ").append(BlockRegionView.toWorldCoordinate(viewZ + 1)).append(")\n");
            final Message msg = Message.translation("server.commands.npc.blackboard.view.title").param("x", viewX).param("z", viewZ);
            msg.insert(Message.translation("server.commands.npc.blackboard.view.coordinates").param("x1", BlockRegionView.toWorldCoordinate(viewX)).param("z1", BlockRegionView.toWorldCoordinate(viewZ)).param("x2", BlockRegionView.toWorldCoordinate(viewX + 1)).param("z2", BlockRegionView.toWorldCoordinate(viewZ + 1)));
            msg.insert("\n");
            if (view == null) {
                sb.append(" No resource view exists");
                msg.insert(Message.translation("server.commands.npc.blackboard.resourceview.noResourceView"));
            }
            else {
                sb.append(" Reservations: [ ").append('\n');
                msg.insert(Message.translation("server.commands.npc.blackboard.resourceview.reservations"));
                view.getReservationsByEntity().forEach((ref, reservation) -> {
                    if (!ref.isValid()) {
                        sb.append("!!!INVALID ENTITY!!!");
                        msg.insert(Message.translation("server.commands.npc.blackboard.view.invalidEntity"));
                        return;
                    }
                    else {
                        final UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType());
                        if (!ResourceViewCommand.$assertionsDisabled && uuidComponent == null) {
                            throw new AssertionError();
                        }
                        else {
                            final UUID uuid = uuidComponent.getUuid();
                            sb.append("  ").append(uuid).append(": ");
                            msg.insert("  " + String.valueOf(uuid) + ": ");
                            final NPCEntity npc = store.getComponent(ref, NPCEntity.getComponentType());
                            if (npc == null) {
                                sb.append("!!!NON-NPC ENTITY!!!");
                                msg.insert(Message.translation("server.commands.npc.blackboard.view.nonNpcEntity"));
                            }
                            else {
                                sb.append(npc.getRoleName());
                                msg.insert(npc.getRoleName());
                            }
                            final int blockIndex = reservation.getBlockIndex();
                            final int blockX = BlockRegionView.xFromIndex(blockIndex) + (viewX << 7);
                            final int blockY = BlockRegionView.yFromIndex(blockIndex) + (reservation.getSectionIndex() << 5);
                            final int blockZ = BlockRegionView.zFromIndex(blockIndex) + (viewZ << 7);
                            final BlockType blockType = BlockType.getAssetMap().getAsset(world.getBlock(blockX, blockY, blockZ));
                            sb.append(" reserved block ").append(blockType.getId()).append(" at ").append(blockX).append(", ").append(blockY).append(", ").append(blockZ).append('\n');
                            msg.insert(Message.translation("server.commands.npc.blackboard.resourceview.reservedBlock").param("name", blockType.getId()).param("x", blockX).param("y", blockY).param("z", blockZ));
                            return;
                        }
                    }
                });
                sb.append(" ]");
                msg.insert(" ]");
            }
            context.sendMessage(msg);
            NPCPlugin.get().getLogger().at(Level.INFO).log(sb.toString());
        }
    }
    
    public static class ReserveCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private final RequiredArg<Boolean> reserveArg;
        @Nonnull
        private final EntityWrappedArg entityArg;
        
        public ReserveCommand() {
            super("reserve", "server.commands.npc.blackboard.reserve.desc");
            this.reserveArg = this.withRequiredArg("reserve", "server.commands.npc.blackboard.reserve.reserve.desc", ArgTypes.BOOLEAN);
            this.entityArg = this.withOptionalArg("entity", "server.commands.entity.entity.desc", ArgTypes.ENTITY_ID);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final Player playerComponent = store.getComponent(ref, Player.getComponentType());
            assert playerComponent != null;
            final UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType());
            assert uuidComponent != null;
            final UUID playerUUID = uuidComponent.getUuid();
            final Ref<EntityStore> npcRef = this.getNPCRef(context, store);
            if (npcRef == null) {
                return;
            }
            final NPCEntity npcEntity = store.getComponent(npcRef, NPCEntity.getComponentType());
            assert npcEntity != null;
            if (this.reserveArg.get(context)) {
                npcEntity.addReservation(playerUUID);
                context.sendMessage(Message.translation("server.commands.npc.blackboard.roleReserved").param("role", npcEntity.getRoleName()));
            }
            else {
                npcEntity.removeReservation(playerUUID);
                context.sendMessage(Message.translation("server.commands.npc.blackboard.roleReleased").param("role", npcEntity.getRoleName()));
            }
        }
        
        @Nullable
        private Ref<EntityStore> getNPCRef(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store) {
            Ref<EntityStore> ref;
            if (this.entityArg.provided(context)) {
                ref = this.entityArg.get(store, context);
            }
            else {
                final Ref<EntityStore> playerRef = context.senderAsPlayerRef();
                if (playerRef == null || !playerRef.isValid()) {
                    context.sendMessage(Message.translation("server.commands.errors.playerOrArg").param("option", "entity"));
                    return null;
                }
                ref = TargetUtil.getTargetEntity(playerRef, store);
                if (ref == null) {
                    context.sendMessage(Message.translation("server.commands.errors.no_entity_in_view").param("option", "entity"));
                    return null;
                }
            }
            if (ref == null) {
                return null;
            }
            final NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType());
            if (npcComponent != null) {
                return ref;
            }
            final UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType());
            assert uuidComponent != null;
            final UUID uuid = uuidComponent.getUuid();
            context.sendMessage(Message.translation("server.commands.errors.not_npc").param("uuid", uuid.toString()));
            return null;
        }
    }
    
    public static class ReservationCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private final EntityWrappedArg entityArg;
        
        public ReservationCommand() {
            super("reservation", "server.commands.npc.blackboard.reservation.desc");
            this.entityArg = this.withOptionalArg("entity", "server.commands.entity.entity.desc", ArgTypes.ENTITY_ID);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final Ref<EntityStore> npcRef = this.getNPCRef(context, store);
            if (npcRef == null) {
                return;
            }
            final NPCEntity npcEntity = store.getComponent(npcRef, NPCEntity.getComponentType());
            assert npcEntity != null;
            final Blackboard blackBoardResource = store.getResource(Blackboard.getResourceType());
            final InteractionView reservationView = blackBoardResource.getView(InteractionView.class, 0L);
            final ReservationStatus reservationStatus = reservationView.getReservationStatus(npcRef, ref, store);
            context.sendMessage(Message.translation("server.commands.npc.blackboard.reservationStatus").param("status", reservationStatus.toString()));
        }
        
        @Nullable
        private Ref<EntityStore> getNPCRef(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store) {
            Ref<EntityStore> ref;
            if (this.entityArg.provided(context)) {
                ref = this.entityArg.get(store, context);
            }
            else {
                final Ref<EntityStore> playerRef = context.senderAsPlayerRef();
                if (playerRef == null || !playerRef.isValid()) {
                    context.sendMessage(Message.translation("server.commands.errors.playerOrArg").param("option", "entity"));
                    return null;
                }
                ref = TargetUtil.getTargetEntity(playerRef, store);
                if (ref == null) {
                    context.sendMessage(Message.translation("server.commands.errors.no_entity_in_view").param("option", "entity"));
                    return null;
                }
            }
            if (ref == null) {
                return null;
            }
            final NPCEntity npcComponent = store.getComponent(ref, NPCEntity.getComponentType());
            if (npcComponent != null) {
                return ref;
            }
            final UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType());
            assert uuidComponent != null;
            final UUID uuid = uuidComponent.getUuid();
            context.sendMessage(Message.translation("server.commands.errors.not_npc").param("uuid", uuid.toString()));
            return null;
        }
    }
}
