com.sk89q.craftbook.mech.drops.legacy.LegacyCustomDropManager.java Source code

Java tutorial

Introduction

Here is the source code for com.sk89q.craftbook.mech.drops.legacy.LegacyCustomDropManager.java

Source

// $Id$
/*
 * Copyright (C) 2012 Lymia <https://lymiahugs.com>
 * 
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program. If not,
 * see <http://www.gnu.org/licenses/>.
 */

package com.sk89q.craftbook.mech.drops.legacy;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Level;

import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;

import com.sk89q.craftbook.bukkit.CraftBookPlugin;
import com.sk89q.craftbook.mech.drops.BlockCustomDropDefinition;
import com.sk89q.craftbook.mech.drops.CustomDrops;
import com.sk89q.craftbook.mech.drops.DropItemStack;
import com.sk89q.craftbook.mech.drops.EntityCustomDropDefinition;
import com.sk89q.craftbook.util.ItemInfo;
import com.sk89q.craftbook.util.ItemSyntax;
import com.sk89q.craftbook.util.ItemUtil;
import com.sk89q.craftbook.util.RegexUtil;

/**
 * Storage class for custom drop definitions.
 *
 * @author Lymia
 */
public final class LegacyCustomDropManager {

    public static final int BLOCK_ID_COUNT = 256;
    public static final int DATA_VALUE_COUNT = 127;

    private CustomItemDrop[] blockDropDefinitions = new CustomItemDrop[BLOCK_ID_COUNT];
    private Map<String, DropDefinition[]> mobDropDefinitions = new TreeMap<String, DropDefinition[]>();

    public LegacyCustomDropManager(File source) {

        //CraftBookPlugin.inst().createDefaultConfiguration(new File(CraftBookPlugin.inst().getDataFolder(), "custom-block-drops.txt"), "custom-block-drops.txt");
        //CraftBookPlugin.inst().createDefaultConfiguration(new File(CraftBookPlugin.inst().getDataFolder(), "custom-mob-drops.txt"), "custom-mob-drops.txt");

        File blockDefinitions = new File(source, "custom-block-drops.txt");
        File mobDefinitions = new File(source, "custom-mob-drops.txt");

        if (blockDefinitions.exists()) {
            try {
                loadDropDefinitions(blockDefinitions, false);
            } catch (CustomDropParseException e) {
                CraftBookPlugin.logger().log(Level.WARNING, "Custom block drop definitions failed to parse", e);
            } catch (IOException e) {
                CraftBookPlugin.logger().log(Level.SEVERE,
                        "Unknown IO error while loading custom block drop definitions", e);
            } catch (Exception e) {
                CraftBookPlugin.logger().log(Level.SEVERE,
                        "Unknown exception while loading custom block drop definitions", e);
            }
        }

        if (mobDefinitions.exists()) {
            try {
                loadDropDefinitions(mobDefinitions, true);
            } catch (CustomDropParseException e) {
                CraftBookPlugin.logger().log(Level.WARNING, "Custom mob drop definitions failed to parse", e);
            } catch (IOException e) {
                CraftBookPlugin.logger().log(Level.SEVERE,
                        "Unknown IO error while loading custom mob drop definitions", e);
            } catch (Exception e) {
                CraftBookPlugin.logger().log(Level.SEVERE,
                        "Unknown exception while loading custom mob drop definitions", e);
            }
        }
    }

    public CustomItemDrop getBlockDrops(int block) {

        if (block < 0 || block >= BLOCK_ID_COUNT)
            return null;
        else
            return blockDropDefinitions[block];
    }

    public DropDefinition[] getMobDrop(LivingEntity mob) {

        if (mob.getCustomName() != null
                && mobDropDefinitions.containsKey(ChatColor.translateAlternateColorCodes('&',
                        (mob.getType().name() + "|" + mob.getCustomName()).toLowerCase(Locale.ENGLISH))))
            return mobDropDefinitions.get(ChatColor.translateAlternateColorCodes('&',
                    (mob.getType().name() + "|" + mob.getCustomName()).toLowerCase(Locale.ENGLISH)));
        return mobDropDefinitions.get(mob.getType().name().toLowerCase(Locale.ENGLISH));
    }

    int converted = 0;

    public void loadDropDefinitions(File file, boolean isMobDrop) throws IOException {

        String prelude = "on unknown line";
        try {
            CustomItemDrop[] blockDropDefinitions = isMobDrop ? null : new CustomItemDrop[BLOCK_ID_COUNT];
            Map<String, DropDefinition[]> mobDropDefinitions = isMobDrop ? new TreeMap<String, DropDefinition[]>()
                    : null;
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
            String line;
            int currentLine = 0;
            while ((line = reader.readLine()) != null) {
                if (line.length() == 0 || line.trim().startsWith("#"))
                    continue;
                currentLine++;
                prelude = "Error on line " + currentLine + " of drop definition file " + file.getAbsolutePath()
                        + ": " + "" + line + "\n"; // Error prelude
                // used for
                // parse
                // messages.

                try {
                    if (line.contains("#"))
                        line = RegexUtil.COMMENT_PATTERN.split(line)[0]; // Remove comments
                } catch (Exception ignored) {
                }

                line = line.trim(); // Remove excess whitespace

                if (line.length() == 0) {
                    continue; // Don't try to parse empty lines
                }

                String[] split = RegexUtil.FIELD_SEPARATOR_PATTERN.split(line, 2); // Split primary field separator

                if (split.length != 2) {
                    reader.close();
                    throw new CustomDropParseException(prelude + "-> not found");
                }

                String itemsSource = StringUtils.replace(split[0], "+", "").trim();
                String targetDrops = split[1].trim();
                if (itemsSource.length() == 0 || targetDrops.length() == 0) {
                    reader.close();
                    throw new CustomDropParseException(prelude + "unexpected empty field");
                }

                DropDefinition[] drops = readDrops(targetDrops, prelude, split[0].contains("+"));

                if (!isMobDrop) {
                    split = RegexUtil.COLON_PATTERN.split(itemsSource);
                    if (split.length > 2) {
                        reader.close();
                        throw new CustomDropParseException(prelude + "too many source block fields");
                    }

                    int sourceId = Integer.parseInt(split[0]);
                    if (sourceId >= BLOCK_ID_COUNT || sourceId < 0) {
                        reader.close();
                        throw new CustomDropParseException(prelude + "block id out of range");
                    }
                    if (blockDropDefinitions[sourceId] == null) {
                        blockDropDefinitions[sourceId] = new CustomItemDrop();
                    }
                    CustomItemDrop drop = blockDropDefinitions[sourceId];

                    int data = 0;

                    if (split.length == 1) {
                        if (drop.defaultDrop != null) {
                            reader.close();
                            throw new CustomDropParseException(prelude + "double drop definition");
                        }
                        drop.defaultDrop = drops;
                    } else {
                        data = Integer.parseInt(split[1]);
                        if (data >= DATA_VALUE_COUNT || data < 0) {
                            reader.close();
                            throw new CustomDropParseException(prelude + "block data value out of range");
                        }
                        if (drop.drops[data] != null) {
                            reader.close();
                            throw new CustomDropParseException(prelude + "double drop definition");
                        }
                        drop.drops[data] = drops;
                    }

                    List<DropItemStack> stacks = new ArrayList<DropItemStack>();

                    boolean append = false;

                    for (DropDefinition dd : drops) {
                        DropItemStack nstack = new DropItemStack(dd.stack);
                        nstack.setChance(dd.chance);
                        nstack.setMaximum(dd.countMax);
                        nstack.setMinimum(dd.countMin);
                        stacks.add(nstack);
                        if (dd.append)
                            append = true;
                    }

                    BlockCustomDropDefinition converted = new BlockCustomDropDefinition(
                            sourceId + "" + data + "" + this.converted++, stacks, new ItemInfo(sourceId, data));
                    converted.setAppend(append);

                    ((CustomDrops) CraftBookPlugin.inst().getMechanic(CustomDrops.class)).addDefinition(converted);
                } else {
                    itemsSource = ChatColor.translateAlternateColorCodes('&',
                            itemsSource.toLowerCase(Locale.ENGLISH));
                    if (mobDropDefinitions.containsKey(itemsSource)) {
                        reader.close();
                        throw new CustomDropParseException(prelude + "double drop definition");
                    }
                    mobDropDefinitions.put(itemsSource, drops);
                }
            }

            reader.close();

            if (isMobDrop) {
                this.mobDropDefinitions = mobDropDefinitions;

                for (Entry<String, DropDefinition[]> def : mobDropDefinitions.entrySet()) {

                    List<DropItemStack> stacks = new ArrayList<DropItemStack>();

                    boolean append = false;

                    for (DropDefinition dd : def.getValue()) {
                        DropItemStack nstack = new DropItemStack(dd.stack);
                        nstack.setChance(dd.chance);
                        nstack.setMaximum(dd.countMax);
                        nstack.setMinimum(dd.countMin);
                        stacks.add(nstack);
                        if (dd.append)
                            append = true;
                    }

                    EntityCustomDropDefinition converted = new EntityCustomDropDefinition(
                            def.getKey().toUpperCase() + "" + this.converted++, stacks,
                            EntityType.valueOf(def.getKey().toUpperCase()));
                    converted.setAppend(append);

                    ((CustomDrops) CraftBookPlugin.inst().getMechanic(CustomDrops.class)).addDefinition(converted);
                }
            } else {
                this.blockDropDefinitions = blockDropDefinitions;
            }
        } catch (NumberFormatException e) {
            throw new CustomDropParseException(prelude + "number field failed to parse", e);
        }
    }

    private static DropDefinition[] readDrops(String s, String prelude, boolean append) throws IOException {

        String[] split = RegexUtil.COMMA_PATTERN.split(s);
        DropDefinition[] drops = new DropDefinition[split.length]; // Java really needs a map function...
        for (int i = 0; i < split.length; i++) {
            drops[i] = readDrop(split[i].trim(), prelude, append); // Strip excess whitespace and parse
        }
        return drops;
    }

    private static DropDefinition readDrop(String s, String prelude, boolean append) throws IOException {

        String[] split = RegexUtil.X_PATTERN.split(RegexUtil.PERCENT_PATTERN.split(s)[0]);
        if (split.length > 2) {
            List<String> temp = new ArrayList<String>();
            for (int i = 0; i < split.length; i++) {
                if (temp.isEmpty())
                    temp.add(split[i]);
                else if (i < split.length - 1)
                    temp.set(0, temp.get(0) + "x" + split[i]);
                else
                    temp.add(split[i]);
            }
            split = temp.toArray(new String[temp.size()]);
        }
        if (split.length > 2)
            throw new CustomDropParseException(prelude + ": too many drop item fields");
        ItemStack stack = ItemUtil.makeItemValid(ItemSyntax.getItem(split[0]));
        String[] split3 = RegexUtil.MINUS_PATTERN.split(split[1].trim());
        if (split3.length > 2)
            throw new CustomDropParseException(prelude + ": invalid number drops range");
        int countMin = Integer.parseInt(split3[0]);
        int countMax = split3.length == 1 ? countMin : Integer.parseInt(split3[1]);
        double chance = 100;
        try {
            chance = Double.parseDouble(RegexUtil.PERCENT_PATTERN.split(s)[1]);
        } catch (Exception ignored) {
        }

        return new DropDefinition(stack, countMin, countMax, chance, append);
    }

    public static class CustomDropParseException extends IOException {

        private static final long serialVersionUID = -1147409575702887124L;

        public CustomDropParseException(String message) {

            super(message);
        }

        public CustomDropParseException(String message, Throwable cause) {

            super(message);
        }
    }

    public static class CustomItemDrop {

        public final DropDefinition[][] drops = new DropDefinition[DATA_VALUE_COUNT][];
        public DropDefinition[] defaultDrop;

        public DropDefinition[] getDrop(int data) {

            if (data < 0 || data >= DATA_VALUE_COUNT)
                return defaultDrop;
            DropDefinition[] drop = drops[data];
            if (drop == null)
                return defaultDrop;
            else
                return drop;
        }
    }

    public static class DropDefinition {

        public final ItemStack stack;
        public final int countMin;
        public final int countMax;
        public final boolean append;
        public final double chance;

        public DropDefinition(ItemStack stack, int countMin, int countMax, double chance, boolean append) {

            if (countMax < countMin) {
                int temp = countMin;
                countMin = countMax;
                countMax = temp;
            }

            this.chance = Math.min(100, Math.max(0, chance));

            this.stack = stack;
            this.countMin = countMin;
            this.countMax = countMax;
            this.append = append;
        }

        public ItemStack getItemStack() {

            if (CraftBookPlugin.inst().getRandom().nextInt(100) > chance)
                return null;
            ItemStack stack = this.stack.clone();
            stack.setAmount(countMin == countMax ? countMin
                    : countMin + CraftBookPlugin.inst().getRandom().nextInt(countMax - countMin + 1));
            return stack;
        }
    }
}