<commit_before>package desutine.kismet.target;

import com.google.common.collect.ImmutableList;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import desutine.kismet.Kismet;
import desutine.kismet.ModLogger;
import desutine.kismet.server.WSDTargetDatabase;
import desutine.kismet.util.StackHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEmptyDrops;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.loot.*;
import net.minecraft.world.storage.loot.conditions.LootCondition;
import net.minecraft.world.storage.loot.conditions.LootConditionManager;
import net.minecraft.world.storage.loot.functions.LootFunction;
import net.minecraft.world.storage.loot.functions.LootFunctionManager;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.FakePlayerFactory;
import net.minecraftforge.oredict.OreDictionary;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class TargetDatabaseBuilder {
    // "based" on LootTableManager's Gson
    // note: using custom Serializer for LootEntry because of vanilla bug
    private static final Gson gson = (new GsonBuilder())
            .registerTypeAdapter(RandomValueRange.class, new RandomValueRange.Serializer())
            .registerTypeAdapter(LootPool.class, new LootPool.Serializer())
            .registerTypeAdapter(LootTable.class, new LootTable.Serializer())
            .registerTypeHierarchyAdapter(LootEntry.class, new LootEntrySerializerFix())
            .registerTypeHierarchyAdapter(LootFunction.class, new LootFunctionManager.Serializer())
            .registerTypeHierarchyAdapter(LootCondition.class, new LootConditionManager.Serializer())
            .registerTypeHierarchyAdapter(LootContext.EntityTarget.class, new LootContext.EntityTarget.Serializer())
            .create();
    private WSDTargetDatabase WSDTargetDatabase;

    private Queue<List<InformedStack>> remainingPackets = new ArrayDeque<>();

    public TargetDatabaseBuilder(WorldServer world) {
        this.WSDTargetDatabase = desutine.kismet.server.WSDTargetDatabase.get(world);
    }

    /**
     * Generates the target lists within the game.
     *
     * @param player The player entity to use to enrich the state
     */
    public void generateStacks(EntityPlayerMP player) {
        player.addChatMessage(new TextComponentString("[Kismet] Starting target library reset..."));

        this.WSDTargetDatabase = desutine.kismet.server.WSDTargetDatabase.get(player.worldObj);
        this.WSDTargetDatabase.setStacks(new HashMap<>());

        Map<String, InformedStack> stacks = getRegisteredItems();
        identifyLoot(player.getServerWorld(), stacks);
        identifyBlockDrops(player.getServerWorld(), stacks);

        // separate the stacks per mod, for smaller packets
        final HashMap<String, List<InformedStack>> modSortedStacks = new HashMap<>();
        for (InformedStack wrapper : stacks.values()) {
            String mod = StackHelper.getMod(wrapper);
            if (!modSortedStacks.containsKey(mod)) {
                final ArrayList<InformedStack> wrappers = new ArrayList<>();
                wrappers.add(wrapper);
                modSortedStacks.put(mod, wrappers);
            } else {
                modSortedStacks.get(mod).add(wrapper);
            }
        }

        this.remainingPackets.addAll(modSortedStacks.values());
        sendNextPacket(player);
    }

    private static void identifyBlockDrops(World world, Map<String, InformedStack> stacks) {
        // let's now try to get worldGen in this VERY hackish way:
        final Set<String> drops = new HashSet<>();
        final Set<String> silkDrops = new HashSet<>();
        final FakePlayer fakePlayer = FakePlayerFactory.getMinecraft((WorldServer) world);

        Block.REGISTRY.forEach(block -> {
            // only deals with the bedrock edge case but alas
            if (block instanceof BlockEmptyDrops) return;

            final ImmutableList<IBlockState> validStates = block.getBlockState().getValidStates();

            for (IBlockState state : validStates) {
                // check their drops (including if it is silk harvested)
                drops.addAll(getDropsFromState(world, fakePlayer, block, state));
                // test for silk touch
                if (block.canSilkHarvest(world, BlockPos.ORIGIN, state, fakePlayer)) {
                    silkDrops.addAll(getSilkDrops(block, state));
                }
            }
        });

        // set all of these as obtainable
        drops.forEach(addToStackMap(stacks, InformedStack.ObtainableTypes.Mineable));

        silkDrops.forEach(addToStackMap(stacks, InformedStack.ObtainableTypes.Silkable));
    }

    private static Set<String> getDropsFromState(World world, FakePlayer fakePlayer, Block block, IBlockState state) {
        Set<String> drops = new HashSet<>();
        // if the block is unbreakable in this state, don't even bother
        if (block.getBlockHardness(state, world, BlockPos.ORIGIN) < 0) return drops;

        // a state machine that loops around while it adds new items to the drops
        int size = drops.size();
        int chances = 20;
        do {
            // assuming fortune 5 to get the best drops
            // hoping the block doesn't do stuff diff with lesser fortunes...
            // fixme assume the worse described above and test for diff fortunes
            try {
                drops.addAll(block.getDrops(world, BlockPos.ORIGIN, state, 5).stream()
                        .map(StackHelper::toUniqueKey)
                        .collect(Collectors.toList()));
            } catch (Exception e) {
                ModLogger.error("Error while gathering blocks for " +
                        StackHelper.toUniqueKey(new ItemStack(block)) + state, e);
                continue;
            }
            if (size != drops.size()) {
                size = drops.size();
                chances = 20;
            }
        } while (--chances > 0);<commit_msg>Fix #4<commit_after>package desutine.kismet.target;

import com.google.common.collect.ImmutableList;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import desutine.kismet.Kismet;
import desutine.kismet.ModLogger;
import desutine.kismet.server.WSDTargetDatabase;
import desutine.kismet.util.StackHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEmptyDrops;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.loot.*;
import net.minecraft.world.storage.loot.conditions.LootCondition;
import net.minecraft.world.storage.loot.conditions.LootConditionManager;
import net.minecraft.world.storage.loot.functions.LootFunction;
import net.minecraft.world.storage.loot.functions.LootFunctionManager;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.FakePlayerFactory;
import net.minecraftforge.oredict.OreDictionary;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class TargetDatabaseBuilder {
    // "based" on LootTableManager's Gson
    // note: using custom Serializer for LootEntry because of vanilla bug
    private static final Gson gson = (new GsonBuilder())
            .registerTypeAdapter(RandomValueRange.class, new RandomValueRange.Serializer())
            .registerTypeAdapter(LootPool.class, new LootPool.Serializer())
            .registerTypeAdapter(LootTable.class, new LootTable.Serializer())
            .registerTypeHierarchyAdapter(LootEntry.class, new LootEntrySerializerFix())
            .registerTypeHierarchyAdapter(LootFunction.class, new LootFunctionManager.Serializer())
            .registerTypeHierarchyAdapter(LootCondition.class, new LootConditionManager.Serializer())
            .registerTypeHierarchyAdapter(LootContext.EntityTarget.class, new LootContext.EntityTarget.Serializer())
            .create();
    private WSDTargetDatabase WSDTargetDatabase;

    private Queue<List<InformedStack>> remainingPackets = new ArrayDeque<>();

    public TargetDatabaseBuilder(WorldServer world) {
        this.WSDTargetDatabase = desutine.kismet.server.WSDTargetDatabase.get(world);
    }

    /**
     * Generates the target lists within the game.
     *
     * @param player The player entity to use to enrich the state
     */
    public void generateStacks(EntityPlayerMP player) {
        player.addChatMessage(new TextComponentString("[Kismet] Starting target library reset..."));

        this.WSDTargetDatabase = desutine.kismet.server.WSDTargetDatabase.get(player.worldObj);
        this.WSDTargetDatabase.setStacks(new HashMap<>());

        Map<String, InformedStack> stacks = getRegisteredItems();
        identifyLoot(player.getServerWorld(), stacks);
        identifyBlockDrops(player.getServerWorld(), stacks);

        // separate the stacks per mod, for smaller packets
        final HashMap<String, List<InformedStack>> modSortedStacks = new HashMap<>();
        for (InformedStack wrapper : stacks.values()) {
            String mod = StackHelper.getMod(wrapper);
            if (!modSortedStacks.containsKey(mod)) {
                final ArrayList<InformedStack> wrappers = new ArrayList<>();
                wrappers.add(wrapper);
                modSortedStacks.put(mod, wrappers);
            } else {
                modSortedStacks.get(mod).add(wrapper);
            }
        }

        this.remainingPackets.addAll(modSortedStacks.values());
        sendNextPacket(player);
    }

    private static void identifyBlockDrops(World world, Map<String, InformedStack> stacks) {
        // let's now try to get worldGen in this VERY hackish way:
        final Set<String> drops = new HashSet<>();
        final Set<String> silkDrops = new HashSet<>();
        final FakePlayer fakePlayer = FakePlayerFactory.getMinecraft((WorldServer) world);

        Block.REGISTRY.forEach(block -> {
            // only deals with the bedrock edge case but alas
            if (block instanceof BlockEmptyDrops) return;

            final ImmutableList<IBlockState> validStates = block.getBlockState().getValidStates();

            for (IBlockState state : validStates) {
                // if the block is unbreakable in this state, don't even bother
                if (block.getBlockHardness(state, world, BlockPos.ORIGIN) < 0) continue;

                // check their drops (including if it is silk harvested)
                drops.addAll(getDropsFromState(world, fakePlayer, block, state));
                // test for silk touch
                if (block.canSilkHarvest(world, BlockPos.ORIGIN, state, fakePlayer)) {
                    silkDrops.addAll(getSilkDrops(block, state));
                }
            }
        });

        // set all of these as obtainable
        drops.forEach(addToStackMap(stacks, InformedStack.ObtainableTypes.Mineable));

        silkDrops.forEach(addToStackMap(stacks, InformedStack.ObtainableTypes.Silkable));
    }

    private static Set<String> getDropsFromState(World world, FakePlayer fakePlayer, Block block, IBlockState state) {
        Set<String> drops = new HashSet<>();

        // a state machine that loops around while it adds new items to the drops
        int size = drops.size();
        int chances = 20;
        do {
            // assuming fortune 5 to get the best drops
            // hoping the block doesn't do stuff diff with lesser fortunes...
            // fixme assume the worse described above and test for diff fortunes
            try {
                drops.addAll(block.getDrops(world, BlockPos.ORIGIN, state, 5).stream()
                        .map(StackHelper::toUniqueKey)
                        .collect(Collectors.toList()));
            } catch (Exception e) {
                ModLogger.error("Error while gathering blocks for " +
                        StackHelper.toUniqueKey(new ItemStack(block)) + state, e);
                continue;
            }
            if (size != drops.size()) {
                size = drops.size();
                chances = 20;
            }
        } while (--chances > 0);
{'fraction_non_alphanumeric': 0.09661580299138843, 'fraction_numerical': 0.001284181900589213, 'mean_word_length': 2.954301075268817, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4263505', 'n_tokens_mistral': 3683, 'n_tokens_neox': 3603, 'n_words': 815}