net.dmulloy2.ultimatearena.types.ArenaConfig.java Source code

Java tutorial

Introduction

Here is the source code for net.dmulloy2.ultimatearena.types.ArenaConfig.java

Source

/**
 * UltimateArena - fully customizable PvP arenas
 * Copyright (C) 2012 - 2015 MineSworn
 * Copyright (C) 2013 - 2015 dmulloy2
 *
 * 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 net.dmulloy2.ultimatearena.types;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;

import lombok.Getter;
import lombok.Setter;
import net.dmulloy2.ultimatearena.UltimateArena;
import net.dmulloy2.util.FormatUtil;
import net.dmulloy2.util.ItemUtil;
import net.dmulloy2.util.MaterialUtil;
import net.dmulloy2.util.NumberUtil;
import net.dmulloy2.util.Util;

import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;

/**
 * @author dmulloy2
 */

@Getter
@Setter
public class ArenaConfig extends Configuration {
    // ---- Generic
    protected boolean allowTeamKilling, countMobKills, canModifyWorld, unlimitedAmmo, rewardBasedOnXp, giveRewards,
            forceBalance, joinInProgress, preserveMobs;
    protected int gameTime, lobbyTime, maxDeaths, maxPlayers, minPlayers;
    protected String defaultClass;
    protected double cashReward;

    protected List<String> blacklistedClasses, whitelistedClasses;
    protected List<Material> clearMaterials;

    protected transient List<ItemStack> rewards;
    protected transient WinCondition winCondition;
    protected transient List<ScaledReward> scaledRewards;
    protected transient Map<Team, List<String>> mandatedClasses;
    protected transient Map<Integer, List<KillStreak>> killStreaks;

    // ---- Transient
    protected transient File file;
    protected transient String type;
    protected transient boolean loaded;

    protected transient final UltimateArena plugin;

    public ArenaConfig(UltimateArena plugin, String type, File file) {
        Validate.notNull(plugin, "plugin cannot be null!");
        Validate.notNull(type, "type cannot be null!");
        Validate.notNull(file, "file cannot be null!");

        this.type = type;
        this.file = file;
        this.plugin = plugin;

        // Set defaults
        this.setDefaults();

        // Load
        this.loaded = load();
    }

    public ArenaConfig(ArenaZone az) {
        Validate.notNull(az, "az cannot be null!");

        this.type = az.getName() + " - Config";
        this.plugin = az.getPlugin();
        this.file = az.getFile();
    }

    private final void setDefaults() {
        this.rewards = new ArrayList<>();
        this.scaledRewards = new ArrayList<>();
        this.mandatedClasses = new HashMap<>();
        this.clearMaterials = new ArrayList<>();
        this.blacklistedClasses = new ArrayList<>();
        this.whitelistedClasses = new ArrayList<>();
        this.killStreaks = getDefaultKillStreak();
        this.winCondition = WinCondition.LAST_MAN_STANDING;

        this.maxDeaths = 1;
        this.maxPlayers = 24;
        this.minPlayers = 1;
        this.unlimitedAmmo = true;
        this.rewardBasedOnXp = true;
        this.giveRewards = true;

        if (!plugin.getClasses().isEmpty())
            this.defaultClass = plugin.getClasses().get(0).getName();

        setCustomDefaults();
    }

    /**
     * Sets any custom defaults. Called after {@link #setDefaults()}.
     */
    protected void setCustomDefaults() {
    }

    /**
     * Loads this config.
     *
     * @return True if loading was successful, false if not
     */
    public final boolean load() {
        return load(file, this);
    }

    /**
     * Loads this config from a given file.
     *
     * @param file File to load from
     * @param def Parent config
     * @return True if loading was successful, false if not
     */
    public final boolean load(File file, ArenaConfig def) {
        Validate.isTrue(!loaded, "This config has already been loaded!");
        Validate.notNull(file, "file cannot be null!");
        Validate.notNull(def, "def cannot be null!");

        try {
            YamlConfiguration config = new YamlConfiguration();
            config.load(file);

            Map<String, Object> values = config.getValues(false);
            this.allowTeamKilling = getBoolean(values, "allowTeamKilling", def.isAllowTeamKilling());
            this.countMobKills = getBoolean(values, "countMobKills", def.isCountMobKills());
            this.canModifyWorld = getBoolean(values, "canModifyWorld", def.isCanModifyWorld());
            this.unlimitedAmmo = getBoolean(values, "unlimitedAmmo", def.isUnlimitedAmmo());
            this.rewardBasedOnXp = getBoolean(values, "rewardBasedOnXp", def.isRewardBasedOnXp());
            this.giveRewards = getBoolean(values, "giveRewards", def.isGiveRewards());
            this.forceBalance = getBoolean(values, "forceBalance", def.isForceBalance());
            this.joinInProgress = getBoolean(values, "joinInProgress", def.isJoinInProgress());

            if (this.preserveMobs = getBoolean(values, "preserveMobs", def.isPreserveMobs()))
                Global.mobPreservation = true;

            this.gameTime = getInt(values, "gameTime", def.getGameTime());
            this.lobbyTime = getInt(values, "lobbyTime", def.getLobbyTime());
            this.maxDeaths = Math.max(1, getInt(values, "maxDeaths", def.getMaxDeaths()));
            this.maxPlayers = getInt(values, "maxPlayers", def.getMaxPlayers());
            this.minPlayers = Math.max(1, getInt(values, "minPlayers", def.getMinPlayers()));

            this.defaultClass = getString(values, "defaultClass", def.getDefaultClass());

            this.cashReward = getDouble(values, "cashReward", def.getCashReward());

            WinCondition condition = WinCondition.fromConfig(getString(values, "winCondition", "default"));
            if (condition != null)
                this.winCondition = condition;

            if (giveRewards) {
                if (isSet(values, "rewards")) {
                    this.rewards = ItemUtil.readItems(getStringList(values, "rewards"), plugin);
                } else {
                    this.rewards = def.getRewards();
                }

                this.scaledRewards = new ArrayList<>();
                if (isSet(values, "scaledRewards")) {
                    for (String string : getStringList(values, "scaledRewards")) {
                        ScaledReward reward = ScaledReward.fromString(string);
                        if (reward != null)
                            scaledRewards.add(reward);
                    }
                } else {
                    if (rewardBasedOnXp) {
                        for (ItemStack item : rewards) {
                            ScaledReward reward = new ScaledReward(item, 200.0D);
                            scaledRewards.add(reward);
                        }
                    } else {
                        this.scaledRewards = def.getScaledRewards();
                    }
                }
            }

            if (isSet(values, "clearMaterials")) {
                this.clearMaterials = MaterialUtil.fromStrings(getStringList(values, "clearMaterials"));
            } else {
                this.clearMaterials = def.getClearMaterials();
            }

            this.blacklistedClasses = getList(values, "blacklistedClasses", def.getBlacklistedClasses());
            this.whitelistedClasses = getList(values, "whitelistedClasses", def.getWhitelistedClasses());

            this.killStreaks = def.getKillStreaks();
            if (isSet(values, "killStreaks")) {
                this.killStreaks = new LinkedHashMap<>();

                for (Entry<String, Object> entry : getSection(values, "killStreaks").entrySet()) {
                    int kills = NumberUtil.toInt(entry.getKey());
                    if (kills < 0)
                        continue;

                    List<KillStreak> streaks = new ArrayList<>();

                    @SuppressWarnings("unchecked")
                    List<String> list = (List<String>) entry.getValue();
                    for (String string : list) {
                        string = string.replaceAll("  ", " ");
                        String[] split = string.split(",");

                        // Determine type
                        KillStreak.Type type = split[0].equalsIgnoreCase("mob") ? KillStreak.Type.MOB
                                : KillStreak.Type.ITEM;

                        // Load settings
                        String message = split[1].trim();

                        // Load specific settings
                        if (type == KillStreak.Type.MOB) {
                            EntityType entityType = EntityType.valueOf(split[2].toUpperCase());
                            int amount = NumberUtil.toInt(split[3]);

                            streaks.add(new KillStreak(kills, message, entityType, amount));
                        } else {
                            String item = FormatUtil.join(",", Arrays.copyOfRange(split, 2, split.length));
                            ItemStack stack = ItemUtil.readItem(item, plugin);
                            if (stack != null)
                                streaks.add(new KillStreak(kills, message, stack));
                        }
                    }

                    killStreaks.put(kills, streaks);
                }
            }

            this.mandatedClasses = def.getMandatedClasses();
            if (isSet(values, "mandatedClasses")) {
                this.mandatedClasses = new HashMap<>();

                for (Entry<String, Object> entry : getSection(values, "mandatedClasses").entrySet()) {
                    Team team = Team.get(entry.getKey());
                    if (team == null)
                        continue;

                    @SuppressWarnings("unchecked")
                    List<String> classes = (List<String>) entry.getValue();
                    mandatedClasses.put(team, classes);
                }
            }

            // Load custom options
            loadCustomOptions(config, def);
        } catch (Throwable ex) {
            plugin.getLogHandler().log(Level.SEVERE,
                    Util.getUsefulStack(ex, "loading config for \"" + type + "\""));
            return false;
        }

        plugin.getLogHandler().debug("Successfully loaded config for {0}!", type);
        return true;
    }

    /**
     * Loads any custom options. Called after {@link #load(File, ArenaConfig)}
     *
     * @param fc FileConfiguration to load options from
     * @param def Parent config
     */
    protected void loadCustomOptions(YamlConfiguration fc, ArenaConfig def) {
    }

    /**
     * Gets this config's default kill streak.
     *
     * @return Default kill streak
     */
    public Map<Integer, List<KillStreak>> getDefaultKillStreak() {
        Map<Integer, List<KillStreak>> ret = new LinkedHashMap<>();

        ret.put(2, Arrays.asList(new KillStreak[] { new KillStreak(2, "&e2 &3kills! Unlocked strength potion!",
                ItemUtil.readPotion("strength, 1, 1, false")) }));

        ret.put(4, Arrays.asList(new KillStreak[] {
                new KillStreak(4, "&e4 &3kills! Unlocked health potion!", ItemUtil.readPotion("heal, 1, 1, false")),
                new KillStreak(4, "&e4 &3kills! Unlocked food!", new ItemStack(Material.GRILLED_PORK, 2)) }));

        ret.put(5, Arrays.asList(
                new KillStreak[] { new KillStreak(5, "&e5 &3kills! Unlocked Zombies!", EntityType.ZOMBIE, 4) }));

        ret.put(8, Arrays.asList(
                new KillStreak[] { new KillStreak(8, "&e8 &3kills! Unlocked attack dogs!", EntityType.WOLF, 2) }));

        ret.put(12, Arrays.asList(new KillStreak[] {
                new KillStreak(12, "&e12 &3kills! Unlocked regen potion!",
                        ItemUtil.readPotion("regen, 1, 1, false")),
                new KillStreak(12, "&e12 &3kills! Unlocked food!", new ItemStack(Material.GRILLED_PORK, 2)) }));

        return ret;
    }

    /**
     * Saves this config.
     */
    public final void save() {
        save(file);
    }

    /**
     * Saves this config to a given file.
     *
     * @param file File to save to
     */
    public final void save(File file) {
        try {
            if (!file.exists())
                file.createNewFile();

            YamlConfiguration config = new YamlConfiguration();
            config.load(file);

            for (Entry<String, Object> entry : serialize().entrySet()) {
                config.set(entry.getKey(), entry.getValue());
            }

            config.save(file);
        } catch (Throwable ex) {
            plugin.getLogHandler().log(Level.WARNING, Util.getUsefulStack(ex, "saving config " + type));
        }
    }

    @Override
    public Map<String, Object> serialize() {
        Map<String, Object> data = new LinkedHashMap<>();

        for (Field field : ArenaConfig.class.getDeclaredFields()) {
            try {
                if (Modifier.isTransient(field.getModifiers()))
                    continue;

                boolean accessible = field.isAccessible();

                field.setAccessible(true);

                if (field.getType().equals(Integer.TYPE)) {
                    if (field.getInt(this) != 0)
                        data.put(field.getName(), field.getInt(this));
                } else if (field.getType().equals(Long.TYPE)) {
                    if (field.getLong(this) != 0)
                        data.put(field.getName(), field.getLong(this));
                } else if (field.getType().equals(Boolean.TYPE)) {
                    if (field.getBoolean(this))
                        data.put(field.getName(), field.getBoolean(this));
                } else if (field.getType().isAssignableFrom(Collection.class)) {
                    if (!((Collection<?>) field.get(this)).isEmpty())
                        data.put(field.getName(), field.get(this));
                } else if (field.getType().isAssignableFrom(String.class)) {
                    if ((String) field.get(this) != null)
                        data.put(field.getName(), field.get(this));
                } else if (field.getType().isAssignableFrom(Map.class)) {
                    if (!((Map<?, ?>) field.get(this)).isEmpty())
                        data.put(field.getName(), field.get(this));
                } else {
                    if (field.get(this) != null)
                        data.put(field.getName(), field.get(this));
                }

                field.setAccessible(accessible);
            } catch (Throwable ex) {
            }
        }

        serializeCustomOptions(data);
        return data;
    }

    /**
     * Serializes custom options. This should be overriden by subclasses.
     *
     * @param data Serialized data map
     */
    protected void serializeCustomOptions(Map<String, Object> data) {
    }

    @Override
    public void reload() {
        // Just... don't delete and reload.
        if (!file.exists())
            return;

        // Reset defaults
        this.setDefaults();

        // Reload
        this.loaded = false;
        this.loaded = load();
    }

    /**
     * Global registry of enabled config values. If a config value is never
     * enabled, it isn't checked elsewhere and there's no performance hit.
     * <p>
     * <i>To be expanded</i>
     * 
     * @author dmulloy2
     */
    public static class Global {
        public static boolean mobPreservation = false;
    }
}