mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-06-28 11:44:42 +02:00
Moving stuff into the core package and fleshing out some more abstractions
This commit is contained in:
@ -1,5 +0,0 @@
|
||||
package com.gmail.nossr50;
|
||||
|
||||
public class McmmoCore {
|
||||
|
||||
}
|
5
core/src/main/java/com/gmail/nossr50/core/McmmoCore.java
Normal file
5
core/src/main/java/com/gmail/nossr50/core/McmmoCore.java
Normal file
@ -0,0 +1,5 @@
|
||||
package com.gmail.nossr50.core;
|
||||
|
||||
public class McmmoCore {
|
||||
|
||||
}
|
@ -0,0 +1,328 @@
|
||||
package com.gmail.nossr50.core.config.experience;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.AutoUpdateConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.experience.FormulaType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.MaterialType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.alchemy.PotionStage;
|
||||
import com.gmail.nossr50.util.StringUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ExperienceConfig extends AutoUpdateConfigLoader {
|
||||
private static ExperienceConfig instance;
|
||||
|
||||
private ExperienceConfig() {
|
||||
super("experience.yml");
|
||||
validate();
|
||||
}
|
||||
|
||||
public static ExperienceConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ExperienceConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
/*
|
||||
* FORMULA SETTINGS
|
||||
*/
|
||||
|
||||
/* Curve values */
|
||||
if (getMultiplier(FormulaType.EXPONENTIAL) <= 0) {
|
||||
reason.add("Experience_Formula.Exponential_Values.multiplier should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getMultiplier(FormulaType.LINEAR) <= 0) {
|
||||
reason.add("Experience_Formula.Linear_Values.multiplier should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getExponent(FormulaType.EXPONENTIAL) <= 0) {
|
||||
reason.add("Experience_Formula.Exponential_Values.exponent should be greater than 0!");
|
||||
}
|
||||
|
||||
/* Global modifier */
|
||||
if (getExperienceGainsGlobalMultiplier() <= 0) {
|
||||
reason.add("Experience_Formula.Multiplier.Global should be greater than 0!");
|
||||
}
|
||||
|
||||
/* PVP modifier */
|
||||
if (getPlayerVersusPlayerXP() < 0) {
|
||||
reason.add("Experience_Formula.Multiplier.PVP should be at least 0!");
|
||||
}
|
||||
|
||||
/* Spawned Mob modifier */
|
||||
if (getSpawnedMobXpMultiplier() < 0) {
|
||||
reason.add("Experience_Formula.Mobspawners.Multiplier should be at least 0!");
|
||||
}
|
||||
|
||||
/* Bred Mob modifier */
|
||||
if (getBredMobXpMultiplier() < 0) {
|
||||
reason.add("Experience_Formula.Breeding.Multiplier should be at least 0!");
|
||||
}
|
||||
|
||||
/* Conversion */
|
||||
if (getExpModifier() <= 0) {
|
||||
reason.add("Conversion.Exp_Modifier should be greater than 0!");
|
||||
}
|
||||
|
||||
/*
|
||||
* XP SETTINGS
|
||||
*/
|
||||
|
||||
/* Alchemy */
|
||||
for (PotionStage potionStage : PotionStage.values()) {
|
||||
if (getPotionXP(potionStage) < 0) {
|
||||
reason.add("Experience.Alchemy.Potion_Stage_" + potionStage.toNumerical() + " should be at least 0!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Archery */
|
||||
if (getArcheryDistanceMultiplier() < 0) {
|
||||
reason.add("Experience.Archery.Distance_Multiplier should be at least 0!");
|
||||
}
|
||||
|
||||
/* Combat XP Multipliers */
|
||||
if (getAnimalsXP() < 0) {
|
||||
reason.add("Experience.Combat.Multiplier.Animals should be at least 0!");
|
||||
}
|
||||
|
||||
if (getDodgeXPModifier() < 0) {
|
||||
reason.add("Skills.Acrobatics.Dodge_XP_Modifier should be at least 0!");
|
||||
}
|
||||
|
||||
if (getRollXPModifier() < 0) {
|
||||
reason.add("Skills.Acrobatics.Roll_XP_Modifier should be at least 0!");
|
||||
}
|
||||
|
||||
if (getFallXPModifier() < 0) {
|
||||
reason.add("Skills.Acrobatics.Fall_XP_Modifier should be at least 0!");
|
||||
}
|
||||
|
||||
/* Fishing */
|
||||
// TODO: Add validation for each fish type once enum is available.
|
||||
|
||||
if (getFishingShakeXP() <= 0) {
|
||||
reason.add("Experience.Fishing.Shake should be greater than 0!");
|
||||
}
|
||||
|
||||
/* Repair */
|
||||
if (getRepairXPBase() <= 0) {
|
||||
reason.add("Experience.Repair.Base should be greater than 0!");
|
||||
}
|
||||
|
||||
/* Taming */
|
||||
if (getTamingXP(EntityType.WOLF) <= 0) {
|
||||
reason.add("Experience.Taming.Animal_Taming.Wolf should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingXP(EntityType.OCELOT) <= 0) {
|
||||
reason.add("Experience.Taming.Animal_Taming.Ocelot should be greater than 0!");
|
||||
}
|
||||
|
||||
return noErrorsInConfig(reason);
|
||||
}
|
||||
|
||||
/*
|
||||
* FORMULA SETTINGS
|
||||
*/
|
||||
|
||||
/* EXPLOIT TOGGLES */
|
||||
public boolean isEndermanEndermiteFarmingPrevented() { return config.getBoolean("ExploitFix.EndermanEndermiteFarms", true); }
|
||||
|
||||
/* Curve settings */
|
||||
public FormulaType getFormulaType() { return FormulaType.getFormulaType(config.getString("Experience_Formula.Curve")); }
|
||||
public boolean getCumulativeCurveEnabled() { return config.getBoolean("Experience_Formula.Cumulative_Curve", false); }
|
||||
|
||||
/* Curve values */
|
||||
public double getMultiplier(FormulaType type) { return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.multiplier"); }
|
||||
public int getBase(FormulaType type) { return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.base"); }
|
||||
public double getExponent(FormulaType type) { return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.exponent"); }
|
||||
|
||||
/* Global modifier */
|
||||
public double getExperienceGainsGlobalMultiplier() { return config.getDouble("Experience_Formula.Multiplier.Global", 1.0); }
|
||||
public void setExperienceGainsGlobalMultiplier(double value) { config.set("Experience_Formula.Multiplier.Global", value); }
|
||||
|
||||
/* PVP modifier */
|
||||
public double getPlayerVersusPlayerXP() { return config.getDouble("Experience_Formula.Multiplier.PVP", 1.0); }
|
||||
|
||||
/* Spawned Mob modifier */
|
||||
public double getSpawnedMobXpMultiplier() { return config.getDouble("Experience_Formula.Mobspawners.Multiplier", 0.0); }
|
||||
public double getBredMobXpMultiplier() { return config.getDouble("Experience_Formula.Breeding.Multiplier", 1.0); }
|
||||
|
||||
/* Skill modifiers */
|
||||
public double getFormulaSkillModifier(PrimarySkillType skill) { return config.getDouble("Experience_Formula.Modifier." + StringUtils.getCapitalized(skill.toString())); }
|
||||
|
||||
/* Custom XP perk */
|
||||
public double getCustomXpPerkBoost() { return config.getDouble("Experience_Formula.Custom_XP_Perk.Boost", 1.25); }
|
||||
|
||||
/* Diminished Returns */
|
||||
public float getDiminishedReturnsCap() { return (float) config.getDouble("Dimished_Returns.Guaranteed_Minimum_Percentage", 0.05D); }
|
||||
public boolean getDiminishedReturnsEnabled() { return config.getBoolean("Diminished_Returns.Enabled", false); }
|
||||
public int getDiminishedReturnsThreshold(PrimarySkillType skill) { return config.getInt("Diminished_Returns.Threshold." + StringUtils.getCapitalized(skill.toString()), 20000); }
|
||||
public int getDiminishedReturnsTimeInterval() { return config.getInt("Diminished_Returns.Time_Interval", 10); }
|
||||
|
||||
/* Conversion */
|
||||
public double getExpModifier() { return config.getDouble("Conversion.Exp_Modifier", 1); }
|
||||
|
||||
/*
|
||||
* XP SETTINGS
|
||||
*/
|
||||
|
||||
/* General Settings */
|
||||
public boolean getExperienceGainsPlayerVersusPlayerEnabled() { return config.getBoolean("Experience.PVP.Rewards", true); }
|
||||
|
||||
/* Combat XP Multipliers */
|
||||
public double getCombatXP(EntityType entity) { return config.getDouble("Experience.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); }
|
||||
public double getAnimalsXP(EntityType entity) { return config.getDouble("Experience.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_"), getAnimalsXP()); }
|
||||
public double getAnimalsXP() { return config.getDouble("Experience.Combat.Multiplier.Animals", 1.0); }
|
||||
public boolean hasCombatXP(EntityType entity) {return config.contains("Experience.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); }
|
||||
|
||||
/* Materials */
|
||||
public int getXp(PrimarySkillType skill, Material data)
|
||||
{
|
||||
String baseString = "Experience." + StringUtils.getCapitalized(skill.toString()) + ".";
|
||||
String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data);
|
||||
if (config.contains(explicitString))
|
||||
return config.getInt(explicitString);
|
||||
String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data);
|
||||
if (config.contains(friendlyString))
|
||||
return config.getInt(friendlyString);
|
||||
String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data);
|
||||
if (config.contains(wildcardString))
|
||||
return config.getInt(wildcardString);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Materials */
|
||||
public int getXp(PrimarySkillType skill, BlockData data)
|
||||
{
|
||||
String baseString = "Experience." + StringUtils.getCapitalized(skill.toString()) + ".";
|
||||
String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data);
|
||||
if (config.contains(explicitString))
|
||||
return config.getInt(explicitString);
|
||||
String friendlyString = baseString + StringUtils.getFriendlyConfigBlockDataString(data);
|
||||
if (config.contains(friendlyString))
|
||||
return config.getInt(friendlyString);
|
||||
String wildcardString = baseString + StringUtils.getWildcardConfigBlockDataString(data);
|
||||
if (config.contains(wildcardString))
|
||||
return config.getInt(wildcardString);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material data)
|
||||
{
|
||||
String baseString = "Experience." + StringUtils.getCapitalized(skill.toString()) + ".";
|
||||
String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data);
|
||||
if (config.contains(explicitString))
|
||||
return true;
|
||||
String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data);
|
||||
if (config.contains(friendlyString))
|
||||
return true;
|
||||
String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data);
|
||||
return config.contains(wildcardString);
|
||||
}
|
||||
|
||||
public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockData data)
|
||||
{
|
||||
String baseString = "Experience." + StringUtils.getCapitalized(skill.toString()) + ".";
|
||||
String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data);
|
||||
if (config.contains(explicitString))
|
||||
return true;
|
||||
String friendlyString = baseString + StringUtils.getFriendlyConfigBlockDataString(data);
|
||||
if (config.contains(friendlyString))
|
||||
return true;
|
||||
String wildcardString = baseString + StringUtils.getWildcardConfigBlockDataString(data);
|
||||
return config.contains(wildcardString);
|
||||
}
|
||||
|
||||
/*
|
||||
* Experience Bar Stuff
|
||||
*/
|
||||
|
||||
public boolean isPartyExperienceBarsEnabled()
|
||||
{
|
||||
return config.getBoolean("Experience_Bars.Update.Party", true);
|
||||
}
|
||||
|
||||
public boolean isPassiveGainsExperienceBarsEnabled()
|
||||
{
|
||||
return config.getBoolean("Experience_Bars.Update.Passive", true);
|
||||
}
|
||||
|
||||
public boolean getDoExperienceBarsAlwaysUpdateTitle()
|
||||
{
|
||||
return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.Enable", false) || getAddExtraDetails();
|
||||
}
|
||||
|
||||
public boolean getAddExtraDetails() { return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.ExtraDetails", false);}
|
||||
public boolean isExperienceBarsEnabled() { return config.getBoolean("Experience_Bars.Enable", true); }
|
||||
public boolean isExperienceBarEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".Enable", true);}
|
||||
|
||||
public BarColor getExperienceBarColor(PrimarySkillType primarySkillType)
|
||||
{
|
||||
String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".Color");
|
||||
|
||||
for(BarColor barColor : BarColor.values())
|
||||
{
|
||||
if(barColor.toString().equalsIgnoreCase(colorValueFromConfig))
|
||||
return barColor;
|
||||
}
|
||||
|
||||
//In case the value is invalid
|
||||
return BarColor.WHITE;
|
||||
}
|
||||
|
||||
public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType)
|
||||
{
|
||||
String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".BarStyle");
|
||||
|
||||
for(BarStyle barStyle : BarStyle.values())
|
||||
{
|
||||
if(barStyle.toString().equalsIgnoreCase(colorValueFromConfig))
|
||||
return barStyle;
|
||||
}
|
||||
|
||||
//In case the value is invalid
|
||||
return BarStyle.SOLID;
|
||||
}
|
||||
|
||||
/* Acrobatics */
|
||||
public int getDodgeXPModifier() { return config.getInt("Experience.Acrobatics.Dodge", 120); }
|
||||
public int getRollXPModifier() { return config.getInt("Experience.Acrobatics.Roll", 80); }
|
||||
public int getFallXPModifier() { return config.getInt("Experience.Acrobatics.Fall", 120); }
|
||||
|
||||
public double getFeatherFallXPModifier() { return config.getDouble("Experience.Acrobatics.FeatherFall_Multiplier", 2.0); }
|
||||
|
||||
/* Alchemy */
|
||||
public double getPotionXP(PotionStage stage) { return config.getDouble("Experience.Alchemy.Potion_Stage_" + stage.toNumerical(), 10D); }
|
||||
|
||||
/* Archery */
|
||||
public double getArcheryDistanceMultiplier() { return config.getDouble("Experience.Archery.Distance_Multiplier", 0.025); }
|
||||
|
||||
public int getFishingShakeXP() { return config.getInt("Experience.Fishing.Shake", 50); }
|
||||
|
||||
/* Repair */
|
||||
public double getRepairXPBase() { return config.getDouble("Experience.Repair.Base", 1000.0); }
|
||||
public double getRepairXP(MaterialType repairMaterialType) { return config.getDouble("Experience.Repair." + StringUtils.getCapitalized(repairMaterialType.toString())); }
|
||||
|
||||
/* Taming */
|
||||
public int getTamingXP(EntityType type)
|
||||
{
|
||||
return config.getInt("Experience.Taming.Animal_Taming." + StringUtils.getPrettyEntityTypeString(type));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ArmorConfigManager {
|
||||
public ArmorConfigManager(mcMMO plugin) {
|
||||
Pattern middlePattern = Pattern.compile("armor\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.armor\\.yml");
|
||||
File dataFolder = new File(mcMMO.getModDirectory());
|
||||
File vanilla = new File(dataFolder, "armor.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "armor.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomArmor(new CustomArmorConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BlockConfigManager {
|
||||
public BlockConfigManager(mcMMO plugin) {
|
||||
Pattern middlePattern = Pattern.compile("blocks\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.blocks\\.yml");
|
||||
File dataFolder = new File(mcMMO.getModDirectory());
|
||||
File vanilla = new File(dataFolder, "blocks.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "blocks.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomBlocks(new CustomBlockConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.skills.ItemType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.MaterialType;
|
||||
import com.gmail.nossr50.skills.repair.repairables.Repairable;
|
||||
import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
|
||||
import com.gmail.nossr50.util.skills.SkillUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CustomArmorConfig extends ConfigLoader {
|
||||
private boolean needsUpdate = false;
|
||||
|
||||
public List<Material> customBoots = new ArrayList<Material>();
|
||||
public List<Material> customChestplates = new ArrayList<Material>();
|
||||
public List<Material> customHelmets = new ArrayList<Material>();
|
||||
public List<Material> customLeggings = new ArrayList<Material>();
|
||||
|
||||
public List<Repairable> repairables = new ArrayList<Repairable>();
|
||||
|
||||
protected CustomArmorConfig(String fileName) {
|
||||
super("mods", fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadArmor("Boots", customBoots);
|
||||
loadArmor("Chestplates", customChestplates);
|
||||
loadArmor("Helmets", customHelmets);
|
||||
loadArmor("Leggings", customLeggings);
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
backup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadArmor(String armorType, List<Material> materialList) {
|
||||
if (needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationSection armorSection = config.getConfigurationSection(armorType);
|
||||
|
||||
if (armorSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> armorConfigSet = armorSection.getKeys(false);
|
||||
|
||||
for (String armorName : armorConfigSet) {
|
||||
if (config.contains(armorType + "." + armorName + "." + ".ID")) {
|
||||
needsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Material armorMaterial = Material.matchMaterial(armorName);
|
||||
|
||||
if (armorMaterial == null) {
|
||||
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean repairable = config.getBoolean(armorType + "." + armorName + ".Repairable");
|
||||
Material repairMaterial = Material.matchMaterial(config.getString(armorType + "." + armorName + ".Repair_Material", ""));
|
||||
|
||||
if (repairable && (repairMaterial == null)) {
|
||||
plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName);
|
||||
repairable = false;
|
||||
}
|
||||
|
||||
if (repairable) {
|
||||
byte repairData = (byte) config.getInt(armorType + "." + armorName + ".Repair_Material_Data_Value", -1);
|
||||
int repairQuantity = SkillUtils.getRepairAndSalvageQuantities(new ItemStack(armorMaterial), repairMaterial, repairData);
|
||||
|
||||
if (repairQuantity == 0) {
|
||||
repairQuantity = config.getInt(armorType + "." + armorName + ".Repair_Material_Quantity", 2);
|
||||
}
|
||||
|
||||
String repairItemName = config.getString(armorType + "." + armorName + ".Repair_Material_Pretty_Name");
|
||||
int repairMinimumLevel = config.getInt(armorType + "." + armorName + ".Repair_MinimumLevel", 0);
|
||||
double repairXpMultiplier = config.getDouble(armorType + "." + armorName + ".Repair_XpMultiplier", 1);
|
||||
|
||||
short durability = armorMaterial.getMaxDurability();
|
||||
|
||||
if (durability == 0) {
|
||||
durability = (short) config.getInt(armorType + "." + armorName + ".Durability", 70);
|
||||
}
|
||||
|
||||
repairables.add(RepairableFactory.getRepairable(armorMaterial, repairMaterial, repairData, repairItemName, repairMinimumLevel, repairQuantity, durability, ItemType.ARMOR, MaterialType.OTHER, repairXpMultiplier));
|
||||
}
|
||||
|
||||
materialList.add(armorMaterial);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomBlock;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CustomBlockConfig extends ConfigLoader {
|
||||
private boolean needsUpdate = false;
|
||||
|
||||
public List<Material> customExcavationBlocks = new ArrayList<>();
|
||||
public List<Material> customHerbalismBlocks = new ArrayList<>();
|
||||
public List<Material> customMiningBlocks = new ArrayList<>();
|
||||
public List<Material> customOres = new ArrayList<>();
|
||||
public List<Material> customLogs = new ArrayList<>();
|
||||
public List<Material> customLeaves = new ArrayList<>();
|
||||
public List<Material> customAbilityBlocks = new ArrayList<>();
|
||||
|
||||
public HashMap<Material, CustomBlock> customBlockMap = new HashMap<>();
|
||||
|
||||
protected CustomBlockConfig(String fileName) {
|
||||
super("mods", fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadBlocks("Excavation", customExcavationBlocks);
|
||||
loadBlocks("Herbalism", customHerbalismBlocks);
|
||||
loadBlocks("Mining", customMiningBlocks);
|
||||
loadBlocks("Woodcutting", null);
|
||||
loadBlocks("Ability_Blocks", customAbilityBlocks);
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
backup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadBlocks(String skillType, List<Material> blockList) {
|
||||
if (needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationSection skillSection = config.getConfigurationSection(skillType);
|
||||
|
||||
if (skillSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> skillConfigSet = skillSection.getKeys(false);
|
||||
|
||||
for (String blockName : skillConfigSet) {
|
||||
if (config.contains(skillType + "." + blockName + ".Drop_Item")) {
|
||||
needsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
String[] blockInfo = blockName.split("[|]");
|
||||
|
||||
Material blockMaterial = Material.matchMaterial(blockInfo[0]);
|
||||
|
||||
if (blockMaterial == null) {
|
||||
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blockList != null) {
|
||||
blockList.add(blockMaterial);
|
||||
}
|
||||
|
||||
if (skillType.equals("Ability_Blocks")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int xp = config.getInt(skillType + "." + blockName + ".XP_Gain");
|
||||
int smeltingXp = 0;
|
||||
|
||||
if (skillType.equals("Mining") && config.getBoolean(skillType + "." + blockName + ".Is_Ore")) {
|
||||
customOres.add(blockMaterial);
|
||||
smeltingXp = config.getInt(skillType + "." + blockName + ".Smelting_XP_Gain", xp / 10);
|
||||
}
|
||||
else if (skillType.equals("Woodcutting")) {
|
||||
if (config.getBoolean(skillType + "." + blockName + ".Is_Log")) {
|
||||
customLogs.add(blockMaterial);
|
||||
}
|
||||
else {
|
||||
customLeaves.add(blockMaterial);
|
||||
xp = 0; // Leaves don't grant XP
|
||||
}
|
||||
}
|
||||
|
||||
customBlockMap.put(blockMaterial, new CustomBlock(xp, config.getBoolean(skillType + "." + blockName + ".Double_Drops_Enabled"), smeltingXp));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomEntity;
|
||||
import org.apache.commons.lang.ClassUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CustomEntityConfig extends ConfigLoader {
|
||||
public HashMap<String, CustomEntity> customEntityClassMap = new HashMap<String, CustomEntity>();
|
||||
public HashMap<String, CustomEntity> customEntityTypeMap = new HashMap<String, CustomEntity>();
|
||||
|
||||
protected CustomEntityConfig(String fileName) {
|
||||
super("mods", fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
if (config.getConfigurationSection("Hostile") != null) {
|
||||
backup();
|
||||
return;
|
||||
}
|
||||
|
||||
for (String entityName : config.getKeys(false)) {
|
||||
Class<?> clazz = null;
|
||||
String className = config.getString(entityName + ".Class", "");
|
||||
|
||||
try {
|
||||
clazz = ClassUtils.getClass(className);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
plugin.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + ".");
|
||||
plugin.getLogger().warning("This custom entity may not function properly.");
|
||||
}
|
||||
|
||||
String entityTypeName = entityName.replace("_", ".");
|
||||
double xpMultiplier = config.getDouble(entityName + ".XP_Multiplier", 1.0D);
|
||||
|
||||
boolean canBeTamed = config.getBoolean(entityName + ".Tameable");
|
||||
int tamingXp = config.getInt(entityName + ".Taming_XP");
|
||||
|
||||
boolean canBeSummoned = config.getBoolean(entityName + ".CanBeSummoned");
|
||||
Material callOfTheWildMaterial = Material.matchMaterial(config.getString(entityName + ".COTW_Material", ""));
|
||||
byte callOfTheWildData = (byte) config.getInt(entityName + ".COTW_Material_Data");
|
||||
int callOfTheWildAmount = config.getInt(entityName + ".COTW_Material_Amount");
|
||||
|
||||
if (canBeSummoned && (callOfTheWildMaterial == null || callOfTheWildAmount == 0)) {
|
||||
plugin.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild.");
|
||||
canBeSummoned = false;
|
||||
}
|
||||
|
||||
CustomEntity entity = new CustomEntity(xpMultiplier, canBeTamed, tamingXp, canBeSummoned, (canBeSummoned ? new ItemStack(callOfTheWildMaterial) : null), callOfTheWildAmount);
|
||||
|
||||
customEntityTypeMap.put(entityTypeName, entity);
|
||||
customEntityClassMap.put(clazz == null ? null : clazz.getName(), entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomTool;
|
||||
import com.gmail.nossr50.core.datatypes.skills.ItemType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.MaterialType;
|
||||
import com.gmail.nossr50.skills.repair.repairables.Repairable;
|
||||
import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
|
||||
import com.gmail.nossr50.util.skills.SkillUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CustomToolConfig extends ConfigLoader {
|
||||
private boolean needsUpdate = false;
|
||||
|
||||
public List<Material> customAxes = new ArrayList<Material>();
|
||||
public List<Material> customBows = new ArrayList<Material>();
|
||||
public List<Material> customHoes = new ArrayList<Material>();
|
||||
public List<Material> customPickaxes = new ArrayList<Material>();
|
||||
public List<Material> customShovels = new ArrayList<Material>();
|
||||
public List<Material> customSwords = new ArrayList<Material>();
|
||||
|
||||
public HashMap<Material, CustomTool> customToolMap = new HashMap<Material, CustomTool>();
|
||||
|
||||
public List<Repairable> repairables = new ArrayList<Repairable>();
|
||||
|
||||
protected CustomToolConfig(String fileName) {
|
||||
super("mods", fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadTool("Axes", customAxes);
|
||||
loadTool("Bows", customBows);
|
||||
loadTool("Hoes", customHoes);
|
||||
loadTool("Pickaxes", customPickaxes);
|
||||
loadTool("Shovels", customShovels);
|
||||
loadTool("Swords", customSwords);
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
backup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTool(String toolType, List<Material> materialList) {
|
||||
if (needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationSection toolSection = config.getConfigurationSection(toolType);
|
||||
|
||||
if (toolSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> toolConfigSet = toolSection.getKeys(false);
|
||||
|
||||
for (String toolName : toolConfigSet) {
|
||||
if (config.contains(toolType + "." + toolName + "." + ".ID")) {
|
||||
needsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Material toolMaterial = Material.matchMaterial(toolName);
|
||||
|
||||
if (toolMaterial == null) {
|
||||
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean repairable = config.getBoolean(toolType + "." + toolName + ".Repairable");
|
||||
Material repairMaterial = Material.matchMaterial(config.getString(toolType + "." + toolName + ".Repair_Material", ""));
|
||||
|
||||
if (repairable && (repairMaterial == null)) {
|
||||
plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName);
|
||||
repairable = false;
|
||||
}
|
||||
|
||||
if (repairable) {
|
||||
byte repairData = (byte) config.getInt(toolType + "." + toolName + ".Repair_Material_Data_Value", -1);
|
||||
int repairQuantity = SkillUtils.getRepairAndSalvageQuantities(new ItemStack(toolMaterial), repairMaterial, repairData);
|
||||
|
||||
if (repairQuantity == 0) {
|
||||
repairQuantity = config.getInt(toolType + "." + toolName + ".Repair_Material_Quantity", 2);
|
||||
}
|
||||
|
||||
String repairItemName = config.getString(toolType + "." + toolName + ".Repair_Material_Pretty_Name");
|
||||
int repairMinimumLevel = config.getInt(toolType + "." + toolName + ".Repair_MinimumLevel", 0);
|
||||
double repairXpMultiplier = config.getDouble(toolType + "." + toolName + ".Repair_XpMultiplier", 1);
|
||||
|
||||
short durability = toolMaterial.getMaxDurability();
|
||||
|
||||
if (durability == 0) {
|
||||
durability = (short) config.getInt(toolType + "." + toolName + ".Durability", 60);
|
||||
}
|
||||
|
||||
repairables.add(RepairableFactory.getRepairable(toolMaterial, repairMaterial, repairData, repairItemName, repairMinimumLevel, repairQuantity, durability, ItemType.TOOL, MaterialType.OTHER, repairXpMultiplier));
|
||||
}
|
||||
|
||||
double multiplier = config.getDouble(toolType + "." + toolName + ".XP_Modifier", 1.0);
|
||||
boolean abilityEnabled = config.getBoolean(toolType + "." + toolName + ".Ability_Enabled", true);
|
||||
int tier = config.getInt(toolType + "." + toolName + ".Tier", 1);
|
||||
|
||||
CustomTool tool = new CustomTool(tier, abilityEnabled, multiplier);
|
||||
|
||||
materialList.add(toolMaterial);
|
||||
customToolMap.put(toolMaterial, tool);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class EntityConfigManager {
|
||||
public EntityConfigManager(mcMMO plugin) {
|
||||
Pattern middlePattern = Pattern.compile("entities\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.entities\\.yml");
|
||||
File dataFolder = new File(mcMMO.getModDirectory());
|
||||
File vanilla = new File(dataFolder, "entities.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "entities.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomEntities(new CustomEntityConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ToolConfigManager {
|
||||
public ToolConfigManager(mcMMO plugin) {
|
||||
Pattern middlePattern = Pattern.compile("tools\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.tools\\.yml");
|
||||
File dataFolder = new File(mcMMO.getModDirectory());
|
||||
File vanilla = new File(dataFolder, "tools.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "tools.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomTools(new CustomToolConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.gmail.nossr50.core.config.party;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.ConfigLoader;
|
||||
import com.gmail.nossr50.util.StringUtils;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class ItemWeightConfig extends ConfigLoader {
|
||||
private static ItemWeightConfig instance;
|
||||
|
||||
private ItemWeightConfig() {
|
||||
super("itemweights.yml");
|
||||
}
|
||||
|
||||
public static ItemWeightConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ItemWeightConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getItemWeight(Material material) {
|
||||
return config.getInt("Item_Weights." + StringUtils.getPrettyItemString(material).replace(" ", "_"), config.getInt("Item_Weights.Default"));
|
||||
}
|
||||
|
||||
public HashSet<Material> getMiscItems() {
|
||||
HashSet<Material> miscItems = new HashSet<Material>();
|
||||
|
||||
for (String item : config.getStringList("Party_Shareables.Misc_Items")) {
|
||||
Material material = Material.getMaterial(item.toUpperCase());
|
||||
|
||||
if (material != null) {
|
||||
miscItems.add(material);
|
||||
}
|
||||
}
|
||||
return miscItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,135 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AutoUpdateConfigLoader extends ConfigLoader {
|
||||
public AutoUpdateConfigLoader(String relativePath, String fileName) {
|
||||
super(relativePath, fileName);
|
||||
}
|
||||
|
||||
public AutoUpdateConfigLoader(String fileName) {
|
||||
super(fileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadFile() {
|
||||
super.loadFile();
|
||||
FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName));
|
||||
|
||||
Set<String> configKeys = config.getKeys(true);
|
||||
Set<String> internalConfigKeys = internalConfig.getKeys(true);
|
||||
|
||||
boolean needSave = false;
|
||||
|
||||
Set<String> oldKeys = new HashSet<String>(configKeys);
|
||||
oldKeys.removeAll(internalConfigKeys);
|
||||
|
||||
Set<String> newKeys = new HashSet<String>(internalConfigKeys);
|
||||
newKeys.removeAll(configKeys);
|
||||
|
||||
// Don't need a re-save if we have old keys sticking around?
|
||||
// Would be less saving, but less... correct?
|
||||
if (!newKeys.isEmpty() || !oldKeys.isEmpty()) {
|
||||
needSave = true;
|
||||
}
|
||||
|
||||
for (String key : oldKeys) {
|
||||
plugin.debug("Detected potentially unused key: " + key);
|
||||
//config.set(key, null);
|
||||
}
|
||||
|
||||
for (String key : newKeys) {
|
||||
plugin.debug("Adding new key: " + key + " = " + internalConfig.get(key));
|
||||
config.set(key, internalConfig.get(key));
|
||||
}
|
||||
|
||||
if (needSave) {
|
||||
// Get Bukkit's version of an acceptable config with new keys, and no old keys
|
||||
String output = config.saveToString();
|
||||
|
||||
// Convert to the superior 4 space indentation
|
||||
output = output.replace(" ", " ");
|
||||
|
||||
// Rip out Bukkit's attempt to save comments at the top of the file
|
||||
while (output.replaceAll("[//s]", "").startsWith("#")) {
|
||||
output = output.substring(output.indexOf('\n', output.indexOf('#')) + 1);
|
||||
}
|
||||
|
||||
// Read the internal config to get comments, then put them in the new one
|
||||
try {
|
||||
// Read internal
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(plugin.getResource(fileName)));
|
||||
LinkedHashMap<String, String> comments = new LinkedHashMap<String, String>();
|
||||
String temp = "";
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains("#")) {
|
||||
temp += line + "\n";
|
||||
}
|
||||
else if (line.contains(":")) {
|
||||
line = line.substring(0, line.indexOf(":") + 1);
|
||||
if (!temp.isEmpty()) {
|
||||
if(comments.containsKey(line)) {
|
||||
int index = 0;
|
||||
while(comments.containsKey(line + index)) {
|
||||
index++;
|
||||
}
|
||||
|
||||
line = line + index;
|
||||
}
|
||||
|
||||
comments.put(line, temp);
|
||||
temp = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dump to the new one
|
||||
HashMap<String, Integer> indexed = new HashMap<String, Integer>();
|
||||
for (String key : comments.keySet()) {
|
||||
String actualkey = key.substring(0, key.indexOf(":") + 1);
|
||||
|
||||
int index = 0;
|
||||
if(indexed.containsKey(actualkey)) {
|
||||
index = indexed.get(actualkey);
|
||||
}
|
||||
boolean isAtTop = !output.contains("\n" + actualkey);
|
||||
index = output.indexOf((isAtTop ? "" : "\n") + actualkey, index);
|
||||
|
||||
if (index >= 0) {
|
||||
output = output.substring(0, index) + "\n" + comments.get(key) + output.substring(isAtTop ? index : index + 1);
|
||||
indexed.put(actualkey, index + comments.get(key).length() + actualkey.length() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Save it
|
||||
try {
|
||||
String saveName = fileName;
|
||||
// At this stage we cannot guarantee that Config has been loaded, so we do the check directly here
|
||||
if (!plugin.getConfig().getBoolean("General.Config_Update_Overwrite", true)) {
|
||||
saveName += ".new";
|
||||
}
|
||||
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(plugin.getDataFolder(), saveName)));
|
||||
writer.write(output);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,575 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.core.data.database.SQLDatabaseManager;
|
||||
import com.gmail.nossr50.core.datatypes.MobHealthbarType;
|
||||
import com.gmail.nossr50.core.datatypes.party.PartyFeature;
|
||||
import com.gmail.nossr50.core.datatypes.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.SuperAbilityType;
|
||||
import com.gmail.nossr50.util.StringUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Config extends AutoUpdateConfigLoader {
|
||||
private static Config instance;
|
||||
|
||||
private Config() {
|
||||
super("config.yml");
|
||||
validate();
|
||||
}
|
||||
|
||||
public static Config getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Config();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
// Validate all the settings!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
/* General Settings */
|
||||
if (getSaveInterval() <= 0) {
|
||||
reason.add("General.Save_Interval should be greater than 0!");
|
||||
}
|
||||
|
||||
/* MySQL Settings */
|
||||
for (SQLDatabaseManager.PoolIdentifier identifier : SQLDatabaseManager.PoolIdentifier.values()) {
|
||||
if (getMySQLMaxConnections(identifier) <= 0) {
|
||||
reason.add("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()) + " should be greater than 0!");
|
||||
}
|
||||
if (getMySQLMaxPoolSize(identifier) <= 0) {
|
||||
reason.add("MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()) + " should be greater than 0!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Mob Healthbar */
|
||||
if (getMobHealthbarTime() == 0) {
|
||||
reason.add("Mob_Healthbar.Display_Time cannot be 0! Set to -1 to disable or set a valid value.");
|
||||
}
|
||||
|
||||
/* Scoreboards */
|
||||
/*if (getRankScoreboardTime() != -1 && getRankScoreboardTime() <= 0) {
|
||||
reason.add("Scoreboard.Types.Rank.Display_Time should be greater than 0, or -1!");
|
||||
}
|
||||
|
||||
if (getStatsScoreboardTime() != -1 && getStatsScoreboardTime() <= 0) {
|
||||
reason.add("Scoreboard.Types.Stats.Display_Time should be greater than 0, or -1!");
|
||||
}
|
||||
|
||||
if (getTopScoreboardTime() != -1 && getTopScoreboardTime() <= 0) {
|
||||
reason.add("Scoreboard.Types.Top.Display_Time should be greater than 0, or -1!");
|
||||
}
|
||||
|
||||
if (getInspectScoreboardTime() != -1 && getInspectScoreboardTime() <= 0) {
|
||||
reason.add("Scoreboard.Types.Inspect.Display_Time should be greater than 0, or -1!");
|
||||
}
|
||||
|
||||
if (getSkillScoreboardTime() != -1 && getSkillScoreboardTime() <= 0) {
|
||||
reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!");
|
||||
}
|
||||
|
||||
if (getSkillLevelUpTime() != -1 && getSkillScoreboardTime() <= 0) {
|
||||
reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!");
|
||||
}
|
||||
|
||||
if (!(getRankUseChat() || getRankUseBoard())) {
|
||||
reason.add("Either Board or Print in Scoreboard.Types.Rank must be true!");
|
||||
}
|
||||
|
||||
if (!(getTopUseChat() || getTopUseBoard())) {
|
||||
reason.add("Either Board or Print in Scoreboard.Types.Top must be true!");
|
||||
}
|
||||
|
||||
if (!(getStatsUseChat() || getStatsUseBoard())) {
|
||||
reason.add("Either Board or Print in Scoreboard.Types.Stats must be true!");
|
||||
}
|
||||
|
||||
if (!(getInspectUseChat() || getInspectUseBoard())) {
|
||||
reason.add("Either Board or Print in Scoreboard.Types.Inspect must be true!");
|
||||
}*/
|
||||
|
||||
/* Database Purging */
|
||||
if (getPurgeInterval() < -1) {
|
||||
reason.add("Database_Purging.Purge_Interval should be greater than, or equal to -1!");
|
||||
}
|
||||
|
||||
if (getOldUsersCutoff() != -1 && getOldUsersCutoff() <= 0) {
|
||||
reason.add("Database_Purging.Old_User_Cutoff should be greater than 0 or -1!");
|
||||
}
|
||||
|
||||
/* Hardcore Mode */
|
||||
if (getHardcoreDeathStatPenaltyPercentage() < 0.01 || getHardcoreDeathStatPenaltyPercentage() > 100) {
|
||||
reason.add("Hardcore.Death_Stat_Loss.Penalty_Percentage only accepts values from 0.01 to 100!");
|
||||
}
|
||||
|
||||
if (getHardcoreVampirismStatLeechPercentage() < 0.01 || getHardcoreVampirismStatLeechPercentage() > 100) {
|
||||
reason.add("Hardcore.Vampirism.Leech_Percentage only accepts values from 0.01 to 100!");
|
||||
}
|
||||
|
||||
/* Items */
|
||||
if (getChimaeraUseCost() < 1 || getChimaeraUseCost() > 64) {
|
||||
reason.add("Items.Chimaera_Wing.Use_Cost only accepts values from 1 to 64!");
|
||||
}
|
||||
|
||||
if (getChimaeraRecipeCost() < 1 || getChimaeraRecipeCost() > 9) {
|
||||
reason.add("Items.Chimaera_Wing.Recipe_Cost only accepts values from 1 to 9!");
|
||||
}
|
||||
|
||||
if (getChimaeraItem() == null) {
|
||||
reason.add("Items.Chimaera_Wing.Item_Name is invalid!");
|
||||
}
|
||||
|
||||
/* Particles */
|
||||
if (getLevelUpEffectsTier() < 1) {
|
||||
reason.add("Particles.LevelUp_Tier should be at least 1!");
|
||||
}
|
||||
|
||||
/* PARTY SETTINGS */
|
||||
if (getAutoPartyKickInterval() < -1) {
|
||||
reason.add("Party.AutoKick_Interval should be at least -1!");
|
||||
}
|
||||
|
||||
if (getAutoPartyKickTime() < 0) {
|
||||
reason.add("Party.Old_Party_Member_Cutoff should be at least 0!");
|
||||
}
|
||||
|
||||
if (getPartyShareBonusBase() <= 0) {
|
||||
reason.add("Party.Sharing.ExpShare_bonus_base should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getPartyShareBonusIncrease() < 0) {
|
||||
reason.add("Party.Sharing.ExpShare_bonus_increase should be at least 0!");
|
||||
}
|
||||
|
||||
if (getPartyShareBonusCap() <= 0) {
|
||||
reason.add("Party.Sharing.ExpShare_bonus_cap should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getPartyShareRange() <= 0) {
|
||||
reason.add("Party.Sharing.Range should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getPartyXpCurveMultiplier() < 1) {
|
||||
reason.add("Party.Leveling.Xp_Curve_Modifier should be at least 1!");
|
||||
}
|
||||
|
||||
for (PartyFeature partyFeature : PartyFeature.values()) {
|
||||
if (getPartyFeatureUnlockLevel(partyFeature) < 0) {
|
||||
reason.add("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel should be at least 0!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Inspect command distance */
|
||||
if (getInspectDistance() <= 0) {
|
||||
reason.add("Commands.inspect.Max_Distance should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTreeFellerThreshold() <= 0) {
|
||||
reason.add("Abilities.Limits.Tree_Feller_Threshold should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getFishingLureModifier() < 0) {
|
||||
reason.add("Abilities.Fishing.Lure_Modifier should be at least 0!");
|
||||
}
|
||||
|
||||
if (getDetonatorItem() == null) {
|
||||
reason.add("Skills.Mining.Detonator_Item is invalid!");
|
||||
}
|
||||
|
||||
if (getRepairAnvilMaterial() == null) {
|
||||
reason.add("Skills.Repair.Anvil_Type is invalid!!");
|
||||
}
|
||||
|
||||
if (getSalvageAnvilMaterial() == null) {
|
||||
reason.add("Skills.Repair.Salvage_Anvil_Type is invalid!");
|
||||
}
|
||||
|
||||
if (getRepairAnvilMaterial() == getSalvageAnvilMaterial()) {
|
||||
reason.add("Cannot use the same item for Repair and Salvage anvils!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWMaterial(EntityType.WOLF) == null) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWMaterial(EntityType.OCELOT) == null) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWMaterial(EntityType.HORSE) == null) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWCost(EntityType.WOLF) <= 0) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWCost(EntityType.OCELOT) <= 0) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWCost(EntityType.HORSE) <= 0) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWAmount(EntityType.WOLF) <= 0) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingCOTWAmount(EntityType.HORSE) <= 0) {
|
||||
reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!");
|
||||
}
|
||||
|
||||
return noErrorsInConfig(reason);
|
||||
}
|
||||
|
||||
/*
|
||||
* GENERAL SETTINGS
|
||||
*/
|
||||
|
||||
/* General Settings */
|
||||
public boolean getIsMetricsEnabled() { return config.getBoolean("Metrics.bstats", true); }
|
||||
|
||||
//Retro mode will default the value to true if the config file doesn't contain the entry (server is from a previous mcMMO install)
|
||||
public boolean getIsRetroMode() { return config.getBoolean("General.RetroMode.Enabled", true); }
|
||||
|
||||
public String getLocale() { return config.getString("General.Locale", "en_us"); }
|
||||
public boolean getMOTDEnabled() { return config.getBoolean("General.MOTD_Enabled", true); }
|
||||
public boolean getShowProfileLoadedMessage() { return config.getBoolean("General.Show_Profile_Loaded", true); }
|
||||
public boolean getDonateMessageEnabled() { return config.getBoolean("Commands.mcmmo.Donate_Message", true); }
|
||||
public int getSaveInterval() { return config.getInt("General.Save_Interval", 10); }
|
||||
public boolean getStatsTrackingEnabled() { return config.getBoolean("General.Stats_Tracking", true); }
|
||||
public boolean getUpdateCheckEnabled() { return config.getBoolean("General.Update_Check", true); }
|
||||
public boolean getPreferBeta() { return config.getBoolean("General.Prefer_Beta", false); }
|
||||
public boolean getVerboseLoggingEnabled() { return config.getBoolean("General.Verbose_Logging", false); }
|
||||
|
||||
public String getPartyChatPrefix() { return config.getString("Commands.partychat.Chat_Prefix_Format", "[[GREEN]]([[WHITE]]{0}[[GREEN]])"); }
|
||||
public boolean getPartyChatColorLeaderName() { return config.getBoolean("Commands.partychat.Gold_Leader_Name", true); }
|
||||
public boolean getPartyDisplayNames() { return config.getBoolean("Commands.partychat.Use_Display_Names", true); }
|
||||
public String getPartyChatPrefixAlly() { return config.getString("Commands.partychat.Chat_Prefix_Format_Ally", "[[GREEN]](A)[[RESET]]"); }
|
||||
|
||||
public String getAdminChatPrefix() { return config.getString("Commands.adminchat.Chat_Prefix_Format", "[[AQUA]][[[WHITE]]{0}[[AQUA]]]"); }
|
||||
public boolean getAdminDisplayNames() { return config.getBoolean("Commands.adminchat.Use_Display_Names", true); }
|
||||
|
||||
public boolean getMatchOfflinePlayers() { return config.getBoolean("Commands.Generic.Match_OfflinePlayers", false); }
|
||||
public long getDatabasePlayerCooldown() { return config.getLong("Commands.Database.Player_Cooldown", 1750); }
|
||||
|
||||
public boolean getLevelUpSoundsEnabled() { return config.getBoolean("General.LevelUp_Sounds", true); }
|
||||
public boolean getRefreshChunksEnabled() { return config.getBoolean("General.Refresh_Chunks", false); }
|
||||
|
||||
public boolean getMobHealthbarEnabled() { return config.getBoolean("Mob_Healthbar.Enabled", true); }
|
||||
|
||||
/* Mob Healthbar */
|
||||
public MobHealthbarType getMobHealthbarDefault() {
|
||||
try {
|
||||
return MobHealthbarType.valueOf(config.getString("Mob_Healthbar.Display_Type", "HEARTS").toUpperCase().trim());
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
return MobHealthbarType.HEARTS;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMobHealthbarTime() { return config.getInt("Mob_Healthbar.Display_Time", 3); }
|
||||
|
||||
/* Scoreboards */
|
||||
public boolean getScoreboardsEnabled() { return config.getBoolean("Scoreboard.UseScoreboards", true); }
|
||||
public boolean getPowerLevelTagsEnabled() { return config.getBoolean("Scoreboard.Power_Level_Tags", false); }
|
||||
public boolean getAllowKeepBoard() { return config.getBoolean("Scoreboard.Allow_Keep", true); }
|
||||
public int getTipsAmount() { return config.getInt("Scoreboard.Tips_Amount", 5); }
|
||||
public boolean getShowStatsAfterLogin() { return config.getBoolean("Scoreboard.Show_Stats_After_Login", false); }
|
||||
public boolean getScoreboardRainbows() { return config.getBoolean("Scoreboard.Rainbows", false); }
|
||||
public boolean getShowAbilityNames() { return config.getBoolean("Scoreboard.Ability_Names", true); }
|
||||
|
||||
public boolean getRankUseChat() { return config.getBoolean("Scoreboard.Types.Rank.Print", false); }
|
||||
public boolean getRankUseBoard() { return config.getBoolean("Scoreboard.Types.Rank.Board", true); }
|
||||
public int getRankScoreboardTime() { return config.getInt("Scoreboard.Types.Rank.Display_Time", 10); }
|
||||
|
||||
public boolean getTopUseChat() { return config.getBoolean("Scoreboard.Types.Top.Print", true); }
|
||||
public boolean getTopUseBoard() { return config.getBoolean("Scoreboard.Types.Top.Board", true); }
|
||||
public int getTopScoreboardTime() { return config.getInt("Scoreboard.Types.Top.Display_Time", 15); }
|
||||
|
||||
public boolean getStatsUseChat() { return config.getBoolean("Scoreboard.Types.Stats.Print", true); }
|
||||
public boolean getStatsUseBoard() { return config.getBoolean("Scoreboard.Types.Stats.Board", true); }
|
||||
public int getStatsScoreboardTime() { return config.getInt("Scoreboard.Types.Stats.Display_Time", 10); }
|
||||
|
||||
public boolean getInspectUseChat() { return config.getBoolean("Scoreboard.Types.Inspect.Print", true); }
|
||||
public boolean getInspectUseBoard() { return config.getBoolean("Scoreboard.Types.Inspect.Board", true); }
|
||||
public int getInspectScoreboardTime() { return config.getInt("Scoreboard.Types.Inspect.Display_Time", 25); }
|
||||
|
||||
public boolean getCooldownUseChat() { return config.getBoolean("Scoreboard.Types.Cooldown.Print", false); }
|
||||
public boolean getCooldownUseBoard() { return config.getBoolean("Scoreboard.Types.Cooldown.Board", true); }
|
||||
public int getCooldownScoreboardTime() { return config.getInt("Scoreboard.Types.Cooldown.Display_Time", 41); }
|
||||
|
||||
public boolean getSkillUseBoard() { return config.getBoolean("Scoreboard.Types.Skill.Board", true); }
|
||||
public int getSkillScoreboardTime() { return config.getInt("Scoreboard.Types.Skill.Display_Time", 30); }
|
||||
public boolean getSkillLevelUpBoard() { return config.getBoolean("Scoreboard.Types.Skill.LevelUp_Board", true); }
|
||||
public int getSkillLevelUpTime() { return config.getInt("Scoreboard.Types.Skill.LevelUp_Time", 5); }
|
||||
|
||||
/* Database Purging */
|
||||
public int getPurgeInterval() { return config.getInt("Database_Purging.Purge_Interval", -1); }
|
||||
public int getOldUsersCutoff() { return config.getInt("Database_Purging.Old_User_Cutoff", 6); }
|
||||
|
||||
/* Backups */
|
||||
public boolean getBackupsEnabled() { return config.getBoolean("Backups.Enabled", true); }
|
||||
public boolean getKeepLast24Hours() { return config.getBoolean("Backups.Keep.Last_24_Hours", true); }
|
||||
public boolean getKeepDailyLastWeek() { return config.getBoolean("Backups.Keep.Daily_Last_Week", true); }
|
||||
public boolean getKeepWeeklyPastMonth() { return config.getBoolean("Backups.Keep.Weekly_Past_Months", true); }
|
||||
|
||||
/* mySQL */
|
||||
public boolean getUseMySQL() { return config.getBoolean("MySQL.Enabled", false); }
|
||||
public String getMySQLTablePrefix() { return config.getString("MySQL.Database.TablePrefix", "mcmmo_"); }
|
||||
public String getMySQLDatabaseName() { return getStringIncludingInts("MySQL.Database.Name"); }
|
||||
public String getMySQLUserName() { return getStringIncludingInts("MySQL.Database.User_Name"); }
|
||||
public int getMySQLServerPort() { return config.getInt("MySQL.Server.Port", 3306); }
|
||||
public String getMySQLServerName() { return config.getString("MySQL.Server.Address", "localhost"); }
|
||||
public String getMySQLUserPassword() { return getStringIncludingInts("MySQL.Database.User_Password"); }
|
||||
public int getMySQLMaxConnections(SQLDatabaseManager.PoolIdentifier identifier) { return config.getInt("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()), 30); }
|
||||
public int getMySQLMaxPoolSize(SQLDatabaseManager.PoolIdentifier identifier) { return config.getInt("MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()), 10); }
|
||||
public boolean getMySQLSSL() { return config.getBoolean("MySQL.Server.SSL", true); }
|
||||
|
||||
private String getStringIncludingInts(String key) {
|
||||
String str = config.getString(key);
|
||||
|
||||
if (str == null) {
|
||||
str = String.valueOf(config.getInt(key));
|
||||
}
|
||||
|
||||
if (str.equals("0")) {
|
||||
str = "No value set for '" + key + "'";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Hardcore Mode */
|
||||
public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); }
|
||||
public void setHardcoreStatLossEnabled(PrimarySkillType primarySkillType, boolean enabled) { config.set("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled); }
|
||||
|
||||
public double getHardcoreDeathStatPenaltyPercentage() { return config.getDouble("Hardcore.Death_Stat_Loss.Penalty_Percentage", 75.0D); }
|
||||
public void setHardcoreDeathStatPenaltyPercentage(double value) { config.set("Hardcore.Death_Stat_Loss.Penalty_Percentage", value); }
|
||||
|
||||
public int getHardcoreDeathStatPenaltyLevelThreshold() { return config.getInt("Hardcore.Death_Stat_Loss.Level_Threshold", 0); }
|
||||
|
||||
public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); }
|
||||
public void setHardcoreVampirismEnabled(PrimarySkillType primarySkillType, boolean enabled) { config.set("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled); }
|
||||
|
||||
public double getHardcoreVampirismStatLeechPercentage() { return config.getDouble("Hardcore.Vampirism.Leech_Percentage", 5.0D); }
|
||||
public void setHardcoreVampirismStatLeechPercentage(double value) { config.set("Hardcore.Vampirism.Leech_Percentage", value); }
|
||||
|
||||
public int getHardcoreVampirismLevelThreshold() { return config.getInt("Hardcore.Vampirism.Level_Threshold", 0); }
|
||||
|
||||
/* SMP Mods */
|
||||
public boolean getToolModsEnabled() { return config.getBoolean("Mods.Tool_Mods_Enabled", false); }
|
||||
public boolean getArmorModsEnabled() { return config.getBoolean("Mods.Armor_Mods_Enabled", false); }
|
||||
public boolean getBlockModsEnabled() { return config.getBoolean("Mods.Block_Mods_Enabled", false); }
|
||||
public boolean getEntityModsEnabled() { return config.getBoolean("Mods.Entity_Mods_Enabled", false); }
|
||||
|
||||
/* Items */
|
||||
public int getChimaeraUseCost() { return config.getInt("Items.Chimaera_Wing.Use_Cost", 1); }
|
||||
public int getChimaeraRecipeCost() { return config.getInt("Items.Chimaera_Wing.Recipe_Cost", 5); }
|
||||
public Material getChimaeraItem() { return Material.matchMaterial(config.getString("Items.Chimaera_Wing.Item_Name", "Feather")); }
|
||||
public boolean getChimaeraEnabled() { return config.getBoolean("Items.Chimaera_Wing.Enabled", true); }
|
||||
public boolean getChimaeraPreventUseUnderground() { return config.getBoolean("Items.Chimaera_Wing.Prevent_Use_Underground", true); }
|
||||
public boolean getChimaeraUseBedSpawn() { return config.getBoolean("Items.Chimaera_Wing.Use_Bed_Spawn", true); }
|
||||
public int getChimaeraCooldown() { return config.getInt("Items.Chimaera_Wing.Cooldown", 240); }
|
||||
public int getChimaeraWarmup() { return config.getInt("Items.Chimaera_Wing.Warmup", 5); }
|
||||
public int getChimaeraRecentlyHurtCooldown() { return config.getInt("Items.Chimaera_Wing.RecentlyHurt_Cooldown", 60); }
|
||||
public boolean getChimaeraSoundEnabled() { return config.getBoolean("Items.Chimaera_Wing.Sound_Enabled", true); }
|
||||
|
||||
public boolean getFluxPickaxeSoundEnabled() { return config.getBoolean("Items.Flux_Pickaxe.Sound_Enabled", true); }
|
||||
|
||||
/* Particles */
|
||||
public boolean getAbilityActivationEffectEnabled() { return config.getBoolean("Particles.Ability_Activation", true); }
|
||||
public boolean getAbilityDeactivationEffectEnabled() { return config.getBoolean("Particles.Ability_Deactivation", true); }
|
||||
public boolean getBleedEffectEnabled() { return config.getBoolean("Particles.Bleed", true); }
|
||||
public boolean getDodgeEffectEnabled() { return config.getBoolean("Particles.Dodge", true); }
|
||||
public boolean getFluxEffectEnabled() { return config.getBoolean("Particles.Flux", true); }
|
||||
public boolean getGreaterImpactEffectEnabled() { return config.getBoolean("Particles.Greater_Impact", true); }
|
||||
public boolean getCallOfTheWildEffectEnabled() { return config.getBoolean("Particles.Call_of_the_Wild", true); }
|
||||
public boolean getLevelUpEffectsEnabled() { return config.getBoolean("Particles.LevelUp_Enabled", true); }
|
||||
public int getLevelUpEffectsTier() { return config.getInt("Particles.LevelUp_Tier", 100); }
|
||||
public boolean getLargeFireworks() { return config.getBoolean("Particles.LargeFireworks", true); }
|
||||
|
||||
/* PARTY SETTINGS */
|
||||
public boolean getPartyFriendlyFire() { return config.getBoolean("Party.FriendlyFire", false);}
|
||||
public int getPartyMaxSize() {return config.getInt("Party.MaxSize", -1); }
|
||||
public int getAutoPartyKickInterval() { return config.getInt("Party.AutoKick_Interval", 12); }
|
||||
public int getAutoPartyKickTime() { return config.getInt("Party.Old_Party_Member_Cutoff", 7); }
|
||||
|
||||
public double getPartyShareBonusBase() { return config.getDouble("Party.Sharing.ExpShare_bonus_base", 1.1D); }
|
||||
public double getPartyShareBonusIncrease() { return config.getDouble("Party.Sharing.ExpShare_bonus_increase", 0.05D); }
|
||||
public double getPartyShareBonusCap() { return config.getDouble("Party.Sharing.ExpShare_bonus_cap", 1.5D); }
|
||||
public double getPartyShareRange() { return config.getDouble("Party.Sharing.Range", 75.0D); }
|
||||
|
||||
public int getPartyLevelCap() {
|
||||
int cap = config.getInt("Party.Leveling.Level_Cap", 10);
|
||||
return (cap <= 0) ? Integer.MAX_VALUE : cap;
|
||||
}
|
||||
|
||||
public int getPartyXpCurveMultiplier() { return config.getInt("Party.Leveling.Xp_Curve_Modifier", 3); }
|
||||
public boolean getPartyXpNearMembersNeeded() { return config.getBoolean("Party.Leveling.Near_Members_Needed", false); }
|
||||
public boolean getPartyInformAllMembers() { return config.getBoolean("Party.Leveling.Inform_All_Party_Members_On_LevelUp", false); }
|
||||
|
||||
public int getPartyFeatureUnlockLevel(PartyFeature partyFeature) { return config.getInt("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel", 0); }
|
||||
|
||||
/* Party Teleport Settings */
|
||||
public int getPTPCommandCooldown() { return config.getInt("Commands.ptp.Cooldown", 120); }
|
||||
public int getPTPCommandWarmup() { return config.getInt("Commands.ptp.Warmup", 5); }
|
||||
public int getPTPCommandRecentlyHurtCooldown() { return config.getInt("Commands.ptp.RecentlyHurt_Cooldown", 60); }
|
||||
public int getPTPCommandTimeout() { return config.getInt("Commands.ptp.Request_Timeout", 300); }
|
||||
public boolean getPTPCommandConfirmRequired() { return config.getBoolean("Commands.ptp.Accept_Required", true); }
|
||||
public boolean getPTPCommandWorldPermissions() { return config.getBoolean("Commands.ptp.World_Based_Permissions", false); }
|
||||
|
||||
/* Inspect command distance */
|
||||
public double getInspectDistance() { return config.getDouble("Commands.inspect.Max_Distance", 30.0D); }
|
||||
|
||||
/*
|
||||
* ABILITY SETTINGS
|
||||
*/
|
||||
|
||||
/* General Settings */
|
||||
public boolean getUrlLinksEnabled() { return config.getBoolean("Commands.Skills.URL_Links"); }
|
||||
public boolean getAbilityMessagesEnabled() { return config.getBoolean("Abilities.Messages", true); }
|
||||
public boolean getAbilitiesEnabled() { return config.getBoolean("Abilities.Enabled", true); }
|
||||
public boolean getAbilitiesOnlyActivateWhenSneaking() { return config.getBoolean("Abilities.Activation.Only_Activate_When_Sneaking", false); }
|
||||
public boolean getAbilitiesGateEnabled() { return config.getBoolean("Abilities.Activation.Level_Gate_Abilities"); }
|
||||
|
||||
public int getCooldown(SuperAbilityType ability) { return config.getInt("Abilities.Cooldowns." + ability.toString()); }
|
||||
public int getMaxLength(SuperAbilityType ability) { return config.getInt("Abilities.Max_Seconds." + ability.toString()); }
|
||||
|
||||
/* Durability Settings */
|
||||
public int getAbilityToolDamage() { return config.getInt("Abilities.Tools.Durability_Loss", 1); }
|
||||
|
||||
/* Thresholds */
|
||||
public int getTreeFellerThreshold() { return config.getInt("Abilities.Limits.Tree_Feller_Threshold", 500); }
|
||||
|
||||
/*
|
||||
* SKILL SETTINGS
|
||||
*/
|
||||
public boolean getDoubleDropsEnabled(PrimarySkillType skill, Material material) { return config.getBoolean("Double_Drops." + StringUtils.getCapitalized(skill.toString()) + "." + StringUtils.getPrettyItemString(material).replace(" ", "_")); }
|
||||
|
||||
public boolean getDoubleDropsDisabled(PrimarySkillType skill) {
|
||||
String skillName = StringUtils.getCapitalized(skill.toString());
|
||||
ConfigurationSection section = config.getConfigurationSection("Double_Drops." + skillName);
|
||||
if (section == null)
|
||||
return false;
|
||||
Set<String> keys = section.getKeys(false);
|
||||
boolean disabled = true;
|
||||
|
||||
for (String key : keys) {
|
||||
if (config.getBoolean("Double_Drops." + skillName + "." + key)) {
|
||||
disabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return disabled;
|
||||
}
|
||||
|
||||
/* Axes */
|
||||
public int getAxesGate() { return config.getInt("Skills.Axes.Ability_Activation_Level_Gate", 10); }
|
||||
|
||||
/* Acrobatics */
|
||||
public boolean getDodgeLightningDisabled() { return config.getBoolean("Skills.Acrobatics.Prevent_Dodge_Lightning", false); }
|
||||
public int getXPAfterTeleportCooldown() { return config.getInt("Skills.Acrobatics.XP_After_Teleport_Cooldown", 5); }
|
||||
|
||||
/* Alchemy */
|
||||
public boolean getEnabledForHoppers() { return config.getBoolean("Skills.Alchemy.Enabled_for_Hoppers", true); }
|
||||
public boolean getPreventHopperTransferIngredients() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Ingredients", false); }
|
||||
public boolean getPreventHopperTransferBottles() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Bottles", false); }
|
||||
|
||||
/* Fishing */
|
||||
public boolean getFishingDropsEnabled() { return config.getBoolean("Skills.Fishing.Drops_Enabled", true); }
|
||||
public boolean getFishingOverrideTreasures() { return config.getBoolean("Skills.Fishing.Override_Vanilla_Treasures", true); }
|
||||
public boolean getFishingExtraFish() { return config.getBoolean("Skills.Fishing.Extra_Fish", true); }
|
||||
public double getFishingLureModifier() { return config.getDouble("Skills.Fishing.Lure_Modifier", 4.0D); }
|
||||
|
||||
/* Mining */
|
||||
public Material getDetonatorItem() { return Material.matchMaterial(config.getString("Skills.Mining.Detonator_Name", "FLINT_AND_STEEL")); }
|
||||
public int getMiningGate() { return config.getInt("Skills.Mining.Ability_Activation_Level_Gate", 10); }
|
||||
|
||||
/* Excavation */
|
||||
public int getExcavationGate() { return config.getInt("Skills.Excavation.Ability_Activation_Level_Gate", 10); }
|
||||
|
||||
/* Repair */
|
||||
public boolean getRepairAnvilMessagesEnabled() { return config.getBoolean("Skills.Repair.Anvil_Messages", true); }
|
||||
public boolean getRepairAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Repair.Anvil_Placed_Sounds", true); }
|
||||
public boolean getRepairAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Repair.Anvil_Use_Sounds", true); }
|
||||
public Material getRepairAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Repair.Anvil_Material", "IRON_BLOCK")); }
|
||||
public boolean getRepairConfirmRequired() { return config.getBoolean("Skills.Repair.Confirm_Required", true); }
|
||||
|
||||
/* Salvage */
|
||||
public boolean getSalvageAnvilMessagesEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Messages", true); }
|
||||
public boolean getSalvageAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Placed_Sounds", true); }
|
||||
public boolean getSalvageAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Use_Sounds", true); }
|
||||
public Material getSalvageAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK")); }
|
||||
public boolean getSalvageConfirmRequired() { return config.getBoolean("Skills.Salvage.Confirm_Required", true); }
|
||||
|
||||
/* Unarmed */
|
||||
public boolean getUnarmedBlockCrackerSmoothbrickToCracked() { return config.getBoolean("Skills.Unarmed.Block_Cracker.SmoothBrick_To_CrackedBrick", true); }
|
||||
public boolean getUnarmedItemPickupDisabled() { return config.getBoolean("Skills.Unarmed.Item_Pickup_Disabled_Full_Inventory", true); }
|
||||
public boolean getUnarmedItemsAsUnarmed() { return config.getBoolean("Skills.Unarmed.Items_As_Unarmed", false); }
|
||||
public int getUnarmedGate() { return config.getInt("Skills.Unarmed.Ability_Activation_Level_Gate", 10); }
|
||||
|
||||
/* Swords */
|
||||
public int getSwordsGate() { return config.getInt("Skills.Swords.Ability_Activation_Level_Gate", 10); }
|
||||
|
||||
/* Taming */
|
||||
public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); }
|
||||
public int getTamingCOTWCost(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Amount"); }
|
||||
public int getTamingCOTWAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Summon_Amount"); }
|
||||
public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); }
|
||||
public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); }
|
||||
public double getTamingCOTWRange() { return config.getDouble("Skills.Taming.Call_Of_The_Wild.Range", 40.0D); }
|
||||
|
||||
/* Woodcutting */
|
||||
public boolean getWoodcuttingDoubleDropsEnabled(BlockData material) { return config.getBoolean("Double_Drops.Woodcutting." + StringUtils.getFriendlyConfigBlockDataString(material)); }
|
||||
public boolean getTreeFellerSoundsEnabled() { return config.getBoolean("Skills.Woodcutting.Tree_Feller_Sounds", true); }
|
||||
public int getWoodcuttingGate() { return config.getInt("Skills.Woodcutting.Ability_Activation_Level_Gate", 10); }
|
||||
|
||||
/* AFK Leveling */
|
||||
public boolean getAcrobaticsPreventAFK() { return config.getBoolean("Skills.Acrobatics.Prevent_AFK_Leveling", true); }
|
||||
public int getAcrobaticsAFKMaxTries() { return config.getInt("Skills.Acrobatics.Max_Tries_At_Same_Location", 3); }
|
||||
public boolean getHerbalismPreventAFK() { return config.getBoolean("Skills.Herbalism.Prevent_AFK_Leveling", true); }
|
||||
|
||||
/* Level Caps */
|
||||
public int getPowerLevelCap() {
|
||||
int cap = config.getInt("General.Power_Level_Cap", 0);
|
||||
return (cap <= 0) ? Integer.MAX_VALUE : cap;
|
||||
}
|
||||
|
||||
public int getLevelCap(PrimarySkillType skill) {
|
||||
int cap = config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Level_Cap");
|
||||
return (cap <= 0) ? Integer.MAX_VALUE : cap;
|
||||
}
|
||||
|
||||
|
||||
/*public int isSuperAbilityUnlocked(PrimarySkillType skill) {
|
||||
return config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Ability_Activation_Level_Gate");
|
||||
}*/
|
||||
|
||||
public boolean getTruncateSkills() { return config.getBoolean("General.TruncateSkills", false); }
|
||||
|
||||
/* PVP & PVE Settings */
|
||||
public boolean getPVPEnabled(PrimarySkillType skill) { return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVP", true); }
|
||||
public boolean getPVEEnabled(PrimarySkillType skill) { return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVE", true); }
|
||||
|
||||
//public float getMasterVolume() { return (float) config.getDouble("Sounds.MasterVolume", 1.0); }
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ConfigLoader {
|
||||
protected static final mcMMO plugin = mcMMO.p;
|
||||
protected String fileName;
|
||||
private File configFile;
|
||||
protected FileConfiguration config;
|
||||
|
||||
public ConfigLoader(String relativePath, String fileName) {
|
||||
this.fileName = fileName;
|
||||
configFile = new File(plugin.getDataFolder(), relativePath + File.separator + fileName);
|
||||
loadFile();
|
||||
}
|
||||
|
||||
public ConfigLoader(String fileName) {
|
||||
this.fileName = fileName;
|
||||
configFile = new File(plugin.getDataFolder(), fileName);
|
||||
loadFile();
|
||||
}
|
||||
|
||||
protected void loadFile() {
|
||||
if (!configFile.exists()) {
|
||||
plugin.debug("Creating mcMMO " + fileName + " File...");
|
||||
|
||||
try {
|
||||
plugin.saveResource(fileName, false); // Normal files
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
plugin.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files
|
||||
}
|
||||
}
|
||||
else {
|
||||
plugin.debug("Loading mcMMO " + fileName + " File...");
|
||||
}
|
||||
|
||||
config = YamlConfiguration.loadConfiguration(configFile);
|
||||
}
|
||||
|
||||
protected abstract void loadKeys();
|
||||
|
||||
protected boolean validateKeys() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean noErrorsInConfig(List<String> issues) {
|
||||
for (String issue : issues) {
|
||||
plugin.getLogger().warning(issue);
|
||||
}
|
||||
|
||||
return issues.isEmpty();
|
||||
}
|
||||
|
||||
protected void validate() {
|
||||
if (validateKeys()) {
|
||||
plugin.debug("No errors found in " + fileName + "!");
|
||||
}
|
||||
else {
|
||||
plugin.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!");
|
||||
plugin.getServer().getPluginManager().disablePlugin(plugin);
|
||||
plugin.noErrorsInConfigFiles = false;
|
||||
}
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
public void backup() {
|
||||
plugin.getLogger().warning("You are using an old version of the " + fileName + " file.");
|
||||
plugin.getLogger().warning("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version.");
|
||||
|
||||
configFile.renameTo(new File(configFile.getPath() + ".old"));
|
||||
|
||||
if (plugin.getResource(fileName) != null) {
|
||||
plugin.saveResource(fileName, true);
|
||||
}
|
||||
|
||||
plugin.getLogger().warning("Reloading " + fileName + " with new values...");
|
||||
loadFile();
|
||||
loadKeys();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.subskills.AbstractSubSkill;
|
||||
import com.gmail.nossr50.util.StringUtils;
|
||||
|
||||
public class CoreSkillsConfig extends AutoUpdateConfigLoader {
|
||||
private static CoreSkillsConfig instance;
|
||||
|
||||
public CoreSkillsConfig()
|
||||
{
|
||||
super("coreskills.yml");
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
|
||||
}
|
||||
|
||||
public static CoreSkillsConfig getInstance()
|
||||
{
|
||||
if(instance == null)
|
||||
return new CoreSkillsConfig();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skill Settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Whether or not a skill is enabled
|
||||
* Defaults true
|
||||
* @param abstractSubSkill SubSkill definition to check
|
||||
* @return true if subskill is enabled
|
||||
*/
|
||||
public boolean isSkillEnabled(AbstractSubSkill abstractSubSkill)
|
||||
{
|
||||
return config.getBoolean(StringUtils.getCapitalized(abstractSubSkill.getPrimarySkill().toString())+"."+ abstractSubSkill.getConfigKeyName()+".Enabled", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this primary skill is enabled
|
||||
* @param primarySkillType target primary skill
|
||||
* @return true if enabled
|
||||
*/
|
||||
public boolean isPrimarySkillEnabled(PrimarySkillType primarySkillType)
|
||||
{
|
||||
return config.getBoolean(StringUtils.getCapitalized(primarySkillType.toString())+".Enabled", true);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class HiddenConfig {
|
||||
private static HiddenConfig instance;
|
||||
private String fileName;
|
||||
private YamlConfiguration config;
|
||||
private boolean chunkletsEnabled;
|
||||
private int conversionRate;
|
||||
private boolean useEnchantmentBuffs;
|
||||
private int uuidConvertAmount;
|
||||
private int mojangRateLimit;
|
||||
private long mojangLimitPeriod;
|
||||
|
||||
public HiddenConfig(String fileName) {
|
||||
this.fileName = fileName;
|
||||
load();
|
||||
}
|
||||
|
||||
public static HiddenConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new HiddenConfig("hidden.yml");
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
InputStreamReader reader = mcMMO.p.getResourceAsReader(fileName);
|
||||
if (reader != null) {
|
||||
config = YamlConfiguration.loadConfiguration(reader);
|
||||
chunkletsEnabled = config.getBoolean("Options.Chunklets", true);
|
||||
conversionRate = config.getInt("Options.ConversionRate", 1);
|
||||
useEnchantmentBuffs = config.getBoolean("Options.EnchantmentBuffs", true);
|
||||
uuidConvertAmount = config.getInt("Options.UUIDConvertAmount", 5);
|
||||
mojangRateLimit = config.getInt("Options.MojangRateLimit", 50000);
|
||||
mojangLimitPeriod = config.getLong("Options.MojangLimitPeriod", 600000);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getChunkletsEnabled() {
|
||||
return chunkletsEnabled;
|
||||
}
|
||||
|
||||
public int getConversionRate() {
|
||||
return conversionRate;
|
||||
}
|
||||
|
||||
public boolean useEnchantmentBuffs() {
|
||||
return useEnchantmentBuffs;
|
||||
}
|
||||
|
||||
public int getUUIDConvertAmount() {
|
||||
return uuidConvertAmount;
|
||||
}
|
||||
|
||||
public int getMojangRateLimit() {
|
||||
return mojangRateLimit;
|
||||
}
|
||||
|
||||
public long getMojangLimitPeriod() {
|
||||
return mojangLimitPeriod;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.skills.SubSkillType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.subskills.AbstractSubSkill;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RankConfig extends AutoUpdateConfigLoader {
|
||||
private static RankConfig instance;
|
||||
|
||||
public RankConfig()
|
||||
{
|
||||
super("skillranks.yml");
|
||||
validate();
|
||||
this.instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
|
||||
}
|
||||
|
||||
public static RankConfig getInstance()
|
||||
{
|
||||
if(instance == null)
|
||||
return new RankConfig();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
/*
|
||||
* In the future this method will check keys for all skills, but for now it only checks overhauled skills
|
||||
*/
|
||||
checkKeys(reason);
|
||||
|
||||
return noErrorsInConfig(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlock level for a subskill depending on the gamemode
|
||||
* @param subSkillType target subskill
|
||||
* @param rank the rank we are checking
|
||||
* @return the level requirement for a subskill at this particular rank
|
||||
*/
|
||||
public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank)
|
||||
{
|
||||
String key = subSkillType.getRankConfigAddress();
|
||||
|
||||
return findRankByRootAddress(rank, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlock level for a subskill depending on the gamemode
|
||||
* @param abstractSubSkill target subskill
|
||||
* @param rank the rank we are checking
|
||||
* @return the level requirement for a subskill at this particular rank
|
||||
*/
|
||||
public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank)
|
||||
{
|
||||
String key = abstractSubSkill.getPrimaryKeyName()+"."+abstractSubSkill.getConfigKeyName();
|
||||
|
||||
return findRankByRootAddress(rank, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlock level for a subskill depending on the gamemode
|
||||
* @param key root address of the subskill in the rankskills.yml file
|
||||
* @param rank the rank we are checking
|
||||
* @return the level requirement for a subskill at this particular rank
|
||||
*/
|
||||
private int findRankByRootAddress(int rank, String key) {
|
||||
String scalingKey = Config.getInstance().getIsRetroMode() ? ".RetroMode." : ".Standard.";
|
||||
|
||||
String targetRank = "Rank_" + rank;
|
||||
|
||||
key += scalingKey;
|
||||
key += targetRank;
|
||||
|
||||
return config.getInt(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for valid keys for subskill ranks
|
||||
*/
|
||||
private void checkKeys(List<String> reasons)
|
||||
{
|
||||
//For now we will only check ranks of stuff I've overhauled
|
||||
for(SubSkillType subSkillType : SubSkillType.values())
|
||||
{
|
||||
//Keeping track of the rank requirements and making sure there are no logical errors
|
||||
int curRank = 0;
|
||||
int prevRank = 0;
|
||||
|
||||
for(int x = 0; x < subSkillType.getNumRanks(); x++)
|
||||
{
|
||||
if(curRank > 0)
|
||||
prevRank = curRank;
|
||||
|
||||
curRank = getSubSkillUnlockLevel(subSkillType, x);
|
||||
|
||||
//Do we really care if its below 0? Probably not
|
||||
if(curRank < 0)
|
||||
{
|
||||
reasons.add(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_"+curRank+".LevelReq should be above or equal to 0!");
|
||||
}
|
||||
|
||||
if(prevRank > curRank)
|
||||
{
|
||||
//We're going to allow this but we're going to warn them
|
||||
plugin.getLogger().info("You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.util.sounds.SoundType;
|
||||
|
||||
public class SoundConfig extends AutoUpdateConfigLoader {
|
||||
private static SoundConfig instance;
|
||||
|
||||
public SoundConfig()
|
||||
{
|
||||
super("sounds.yml");
|
||||
validate();
|
||||
this.instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
|
||||
}
|
||||
|
||||
public static SoundConfig getInstance()
|
||||
{
|
||||
if(instance == null)
|
||||
return new SoundConfig();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
for(SoundType soundType : SoundType.values())
|
||||
{
|
||||
if(config.getDouble("Sounds."+soundType.toString()+".Volume") < 0)
|
||||
{
|
||||
plugin.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
//Sounds with custom pitching don't use pitch values
|
||||
if(!soundType.usesCustomPitch())
|
||||
{
|
||||
if(config.getDouble("Sounds."+soundType.toString()+".Pitch") < 0)
|
||||
{
|
||||
plugin.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public float getMasterVolume() { return (float) config.getDouble("Sounds.MasterVolume", 1.0); }
|
||||
|
||||
public float getVolume(SoundType soundType)
|
||||
{
|
||||
String key = "Sounds."+soundType.toString()+".Volume";
|
||||
return (float) config.getDouble(key);
|
||||
}
|
||||
|
||||
public float getPitch(SoundType soundType)
|
||||
{
|
||||
String key = "Sounds."+soundType.toString()+".Pitch";
|
||||
return (float) config.getDouble(key);
|
||||
}
|
||||
|
||||
public boolean getIsEnabled(SoundType soundType)
|
||||
{
|
||||
String key = "Sounds."+soundType.toString()+".Enabled";
|
||||
return config.getBoolean(key, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.gmail.nossr50.core.config.skills;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Blacklist certain features in certain worlds
|
||||
*/
|
||||
public class WorldBlacklist {
|
||||
private static ArrayList<String> blacklist;
|
||||
private mcMMO plugin;
|
||||
|
||||
private final String blackListFileName = "world_blacklist.txt";
|
||||
|
||||
public WorldBlacklist(mcMMO plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
blacklist = new ArrayList<>();
|
||||
init();
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
//Make the blacklist file if it doesn't exist
|
||||
File blackListFile = new File(plugin.getDataFolder() + File.separator + blackListFileName);
|
||||
|
||||
try {
|
||||
if(!blackListFile.exists())
|
||||
blackListFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//Load up the blacklist
|
||||
loadBlacklist(blackListFile);
|
||||
//registerFlags();
|
||||
}
|
||||
|
||||
private void loadBlacklist(File blackListFile) {
|
||||
try {
|
||||
FileReader fileReader = new FileReader(blackListFile);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String currentLine;
|
||||
|
||||
while((currentLine = bufferedReader.readLine()) != null)
|
||||
{
|
||||
if(currentLine.length() == 0)
|
||||
continue;
|
||||
|
||||
if(!blacklist.contains(currentLine))
|
||||
blacklist.add(currentLine);
|
||||
}
|
||||
|
||||
//Close readers
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
plugin.getLogger().info(blacklist.size()+" entries in mcMMO World Blacklist");
|
||||
}
|
||||
|
||||
public static boolean isWorldBlacklisted(World world)
|
||||
{
|
||||
|
||||
for(String s : blacklist)
|
||||
{
|
||||
if(world.getName().equalsIgnoreCase(s))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,286 @@
|
||||
package com.gmail.nossr50.config.skills.alchemy;
|
||||
|
||||
import com.gmail.nossr50.config.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.skills.alchemy.AlchemyPotion;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PotionConfig extends ConfigLoader {
|
||||
private static PotionConfig instance;
|
||||
|
||||
private List<ItemStack> concoctionsIngredientsTierOne = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierTwo = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierThree = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierFour = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierFive = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierSix = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierSeven = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierEight = new ArrayList<ItemStack>();
|
||||
|
||||
private Map<String, AlchemyPotion> potionMap = new HashMap<String, AlchemyPotion>();
|
||||
|
||||
private PotionConfig() {
|
||||
super("potions.yml");
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
public static PotionConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new PotionConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadConcoctions();
|
||||
loadPotionMap();
|
||||
}
|
||||
|
||||
private void loadConcoctions() {
|
||||
ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions");
|
||||
|
||||
loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierFour, concoctionSection.getStringList("Tier_Four_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierFive, concoctionSection.getStringList("Tier_Five_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierSix, concoctionSection.getStringList("Tier_Six_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierSeven, concoctionSection.getStringList("Tier_Seven_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierEight, concoctionSection.getStringList("Tier_Eight_Ingredients"));
|
||||
|
||||
concoctionsIngredientsTierTwo.addAll(concoctionsIngredientsTierOne);
|
||||
concoctionsIngredientsTierThree.addAll(concoctionsIngredientsTierTwo);
|
||||
concoctionsIngredientsTierFour.addAll(concoctionsIngredientsTierThree);
|
||||
concoctionsIngredientsTierFive.addAll(concoctionsIngredientsTierFour);
|
||||
concoctionsIngredientsTierSix.addAll(concoctionsIngredientsTierFive);
|
||||
concoctionsIngredientsTierSeven.addAll(concoctionsIngredientsTierSix);
|
||||
concoctionsIngredientsTierEight.addAll(concoctionsIngredientsTierSeven);
|
||||
}
|
||||
|
||||
private void loadConcoctionsTier(List<ItemStack> ingredientList, List<String> ingredientStrings) {
|
||||
if (ingredientStrings != null && ingredientStrings.size() > 0) {
|
||||
for (String ingredientString : ingredientStrings) {
|
||||
ItemStack ingredient = loadIngredient(ingredientString);
|
||||
|
||||
if (ingredient != null) {
|
||||
ingredientList.add(ingredient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the Potions configuration section and load all defined potions.
|
||||
*/
|
||||
private void loadPotionMap() {
|
||||
ConfigurationSection potionSection = config.getConfigurationSection("Potions");
|
||||
int pass = 0;
|
||||
int fail = 0;
|
||||
|
||||
for (String potionName : potionSection.getKeys(false)) {
|
||||
AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(potionName));
|
||||
|
||||
if (potion != null) {
|
||||
potionMap.put(potionName, potion);
|
||||
pass++;
|
||||
}
|
||||
else {
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
mcMMO.p.debug("Loaded " + pass + " Alchemy potions, skipped " + fail + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a ConfigurationSection representing a AlchemyPotion.
|
||||
* Returns null if input cannot be parsed.
|
||||
*
|
||||
* @param potion_section ConfigurationSection to be parsed.
|
||||
*
|
||||
* @return Parsed AlchemyPotion.
|
||||
*/
|
||||
private AlchemyPotion loadPotion(ConfigurationSection potion_section) {
|
||||
try {
|
||||
|
||||
|
||||
String name = potion_section.getString("Name");
|
||||
if (name != null) {
|
||||
name = ChatColor.translateAlternateColorCodes('&', name);
|
||||
}
|
||||
|
||||
PotionData data;
|
||||
if (!potion_section.contains("PotionData")) { // Backwards config compatability
|
||||
short dataValue = Short.parseShort(potion_section.getName());
|
||||
Potion potion = Potion.fromDamage(dataValue);
|
||||
data = new PotionData(potion.getType(), potion.hasExtendedDuration(), potion.getLevel() == 2);
|
||||
} else {
|
||||
ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData");
|
||||
data = new PotionData(PotionType.valueOf(potionData.getString("PotionType", "WATER")), potionData.getBoolean("Extended", false), potionData.getBoolean("Upgraded", false));
|
||||
}
|
||||
|
||||
Material material = Material.POTION;
|
||||
String mat = potion_section.getString("Material", null);
|
||||
if (mat != null) {
|
||||
material = Material.valueOf(mat);
|
||||
}
|
||||
|
||||
List<String> lore = new ArrayList<String>();
|
||||
if (potion_section.contains("Lore")) {
|
||||
for (String line : potion_section.getStringList("Lore")) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', line));
|
||||
}
|
||||
}
|
||||
|
||||
List<PotionEffect> effects = new ArrayList<PotionEffect>();
|
||||
if (potion_section.contains("Effects")) {
|
||||
for (String effect : potion_section.getStringList("Effects")) {
|
||||
String[] parts = effect.split(" ");
|
||||
|
||||
PotionEffectType type = parts.length > 0 ? PotionEffectType.getByName(parts[0]) : null;
|
||||
int amplifier = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
|
||||
int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
|
||||
|
||||
if (type != null) {
|
||||
effects.add(new PotionEffect(type, duration, amplifier));
|
||||
}
|
||||
else {
|
||||
mcMMO.p.getLogger().warning("Failed to parse effect for potion " + name + ": " + effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Color color = null;
|
||||
if (potion_section.contains("Color")) {
|
||||
color = Color.fromRGB(potion_section.getInt("Color"));
|
||||
}
|
||||
else {
|
||||
color = this.generateColor(effects);
|
||||
}
|
||||
|
||||
Map<ItemStack, String> children = new HashMap<ItemStack, String>();
|
||||
if (potion_section.contains("Children")) {
|
||||
for (String child : potion_section.getConfigurationSection("Children").getKeys(false)) {
|
||||
ItemStack ingredient = loadIngredient(child);
|
||||
if (ingredient != null) {
|
||||
children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child));
|
||||
}
|
||||
else {
|
||||
mcMMO.p.getLogger().warning("Failed to parse child for potion " + name + ": " + child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AlchemyPotion(material, data, name, lore, effects, color, children);
|
||||
}
|
||||
catch (Exception e) {
|
||||
mcMMO.p.getLogger().warning("Failed to load Alchemy potion: " + potion_section.getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string representation of an ingredient.
|
||||
* Format: '<MATERIAL>[:data]'
|
||||
* Returns null if input cannot be parsed.
|
||||
*
|
||||
* @param ingredient String representing an ingredient.
|
||||
*
|
||||
* @return Parsed ingredient.
|
||||
*/
|
||||
private ItemStack loadIngredient(String ingredient) {
|
||||
if (ingredient == null || ingredient.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Material material = Material.getMaterial(ingredient);
|
||||
|
||||
if (material != null) {
|
||||
return new ItemStack(material, 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ItemStack> getIngredients(int tier) {
|
||||
switch (tier) {
|
||||
case 8:
|
||||
return concoctionsIngredientsTierEight;
|
||||
case 7:
|
||||
return concoctionsIngredientsTierSeven;
|
||||
case 6:
|
||||
return concoctionsIngredientsTierSix;
|
||||
case 5:
|
||||
return concoctionsIngredientsTierFive;
|
||||
case 4:
|
||||
return concoctionsIngredientsTierFour;
|
||||
case 3:
|
||||
return concoctionsIngredientsTierThree;
|
||||
case 2:
|
||||
return concoctionsIngredientsTierTwo;
|
||||
case 1:
|
||||
default:
|
||||
return concoctionsIngredientsTierOne;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidPotion(ItemStack item) {
|
||||
return getPotion(item) != null;
|
||||
}
|
||||
|
||||
public AlchemyPotion getPotion(String name) {
|
||||
return potionMap.get(name);
|
||||
}
|
||||
|
||||
public AlchemyPotion getPotion(ItemStack item) {
|
||||
for (AlchemyPotion potion : potionMap.values()) {
|
||||
if (potion.isSimilar(item)) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Color generateColor(List<PotionEffect> effects) {
|
||||
if (effects != null && !effects.isEmpty()) {
|
||||
List<Color> colors = new ArrayList<Color>();
|
||||
for (PotionEffect effect : effects) {
|
||||
if (effect.getType().getColor() != null) {
|
||||
colors.add(effect.getType().getColor());
|
||||
}
|
||||
}
|
||||
if (!colors.isEmpty()) {
|
||||
if (colors.size() > 1) {
|
||||
return calculateAverageColor(colors);
|
||||
}
|
||||
return colors.get(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Color calculateAverageColor(List<Color> colors) {
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
for (Color color : colors) {
|
||||
red += color.getRed();
|
||||
green += color.getGreen();
|
||||
blue += color.getBlue();
|
||||
}
|
||||
Color color = Color.fromRGB(red/colors.size(), green/colors.size(), blue/colors.size());
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package com.gmail.nossr50.config.skills.repair;
|
||||
|
||||
import com.gmail.nossr50.config.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.skills.ItemType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.MaterialType;
|
||||
import com.gmail.nossr50.skills.repair.repairables.Repairable;
|
||||
import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
|
||||
import com.gmail.nossr50.util.ItemUtils;
|
||||
import com.gmail.nossr50.util.skills.SkillUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class RepairConfig extends ConfigLoader {
|
||||
private List<Repairable> repairables;
|
||||
|
||||
public RepairConfig(String fileName) {
|
||||
super(fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
repairables = new ArrayList<Repairable>();
|
||||
|
||||
ConfigurationSection section = config.getConfigurationSection("Repairables");
|
||||
Set<String> keys = section.getKeys(false);
|
||||
|
||||
for (String key : keys) {
|
||||
if (config.contains("Repairables." + key + ".ItemId")) {
|
||||
backup();
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate all the things!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
// Item Material
|
||||
Material itemMaterial = Material.matchMaterial(key);
|
||||
|
||||
if (itemMaterial == null) {
|
||||
reason.add("Invalid material: " + key);
|
||||
}
|
||||
|
||||
// Repair Material Type
|
||||
MaterialType repairMaterialType = MaterialType.OTHER;
|
||||
String repairMaterialTypeString = config.getString("Repairables." + key + ".MaterialType", "OTHER");
|
||||
|
||||
if (!config.contains("Repairables." + key + ".MaterialType") && itemMaterial != null) {
|
||||
ItemStack repairItem = new ItemStack(itemMaterial);
|
||||
|
||||
if (ItemUtils.isWoodTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.WOOD;
|
||||
}
|
||||
else if (ItemUtils.isStoneTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.STONE;
|
||||
}
|
||||
else if (ItemUtils.isStringTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.STRING;
|
||||
}
|
||||
else if (ItemUtils.isLeatherArmor(repairItem)) {
|
||||
repairMaterialType = MaterialType.LEATHER;
|
||||
}
|
||||
else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.IRON;
|
||||
}
|
||||
else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.GOLD;
|
||||
}
|
||||
else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.DIAMOND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
repairMaterialType = MaterialType.valueOf(repairMaterialTypeString);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid MaterialType of " + repairMaterialTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
// Repair Material
|
||||
String repairMaterialName = config.getString("Repairables." + key + ".RepairMaterial");
|
||||
Material repairMaterial = (repairMaterialName == null ? repairMaterialType.getDefaultMaterial() : Material.matchMaterial(repairMaterialName));
|
||||
|
||||
if (repairMaterial == null) {
|
||||
reason.add(key + " has an invalid repair material: " + repairMaterialName);
|
||||
}
|
||||
|
||||
// Maximum Durability
|
||||
short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() : (short) config.getInt("Repairables." + key + ".MaximumDurability"));
|
||||
|
||||
if (maximumDurability <= 0) {
|
||||
maximumDurability = (short) config.getInt("Repairables." + key + ".MaximumDurability");
|
||||
}
|
||||
|
||||
if (maximumDurability <= 0) {
|
||||
reason.add("Maximum durability of " + key + " must be greater than 0!");
|
||||
}
|
||||
|
||||
// Item Type
|
||||
ItemType repairItemType = ItemType.OTHER;
|
||||
String repairItemTypeString = config.getString("Repairables." + key + ".ItemType", "OTHER");
|
||||
|
||||
if (!config.contains("Repairables." + key + ".ItemType") && itemMaterial != null) {
|
||||
ItemStack repairItem = new ItemStack(itemMaterial);
|
||||
|
||||
if (ItemUtils.isMinecraftTool(repairItem)) {
|
||||
repairItemType = ItemType.TOOL;
|
||||
}
|
||||
else if (ItemUtils.isArmor(repairItem)) {
|
||||
repairItemType = ItemType.ARMOR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
repairItemType = ItemType.valueOf(repairItemTypeString);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid ItemType of " + repairItemTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
byte repairMetadata = (byte) config.getInt("Repairables." + key + ".RepairMaterialMetadata", -1);
|
||||
int minimumLevel = config.getInt("Repairables." + key + ".MinimumLevel");
|
||||
double xpMultiplier = config.getDouble("Repairables." + key + ".XpMultiplier", 1);
|
||||
|
||||
if (minimumLevel < 0) {
|
||||
reason.add(key + " has an invalid MinimumLevel of " + minimumLevel);
|
||||
}
|
||||
|
||||
// Minimum Quantity
|
||||
int minimumQuantity = (itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities(new ItemStack(itemMaterial), repairMaterial, repairMetadata) : config.getInt("Repairables." + key + ".MinimumQuantity", 2));
|
||||
|
||||
if (minimumQuantity <= 0 && itemMaterial != null) {
|
||||
minimumQuantity = config.getInt("Repairables." + key + ".MinimumQuantity", 2);
|
||||
}
|
||||
|
||||
if (minimumQuantity <= 0) {
|
||||
reason.add("Minimum quantity of " + key + " must be greater than 0!");
|
||||
}
|
||||
|
||||
if (noErrorsInRepairable(reason)) {
|
||||
Repairable repairable = RepairableFactory.getRepairable(itemMaterial, repairMaterial, repairMetadata, minimumLevel, minimumQuantity, maximumDurability, repairItemType, repairMaterialType, xpMultiplier);
|
||||
repairables.add(repairable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Repairable> getLoadedRepairables() {
|
||||
return repairables == null ? new ArrayList<Repairable>() : repairables;
|
||||
}
|
||||
|
||||
private boolean noErrorsInRepairable(List<String> issues) {
|
||||
for (String issue : issues) {
|
||||
plugin.getLogger().warning(issue);
|
||||
}
|
||||
|
||||
return issues.isEmpty();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.gmail.nossr50.config.skills.repair;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.skills.repair.repairables.Repairable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RepairConfigManager {
|
||||
private final List<Repairable> repairables = new ArrayList<Repairable>();
|
||||
|
||||
public RepairConfigManager(mcMMO plugin) {
|
||||
Pattern pattern = Pattern.compile("repair\\.(?:.+)\\.yml");
|
||||
File dataFolder = plugin.getDataFolder();
|
||||
File vanilla = new File(dataFolder, "repair.vanilla.yml");
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource("repair.vanilla.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!pattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RepairConfig rConfig = new RepairConfig(fileName);
|
||||
repairables.addAll(rConfig.getLoadedRepairables());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Repairable> getLoadedRepairables() {
|
||||
return repairables;
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package com.gmail.nossr50.config.skills.salvage;
|
||||
|
||||
import com.gmail.nossr50.config.ConfigLoader;
|
||||
import com.gmail.nossr50.core.datatypes.skills.ItemType;
|
||||
import com.gmail.nossr50.core.datatypes.skills.MaterialType;
|
||||
import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
|
||||
import com.gmail.nossr50.skills.salvage.salvageables.SalvageableFactory;
|
||||
import com.gmail.nossr50.util.ItemUtils;
|
||||
import com.gmail.nossr50.util.skills.SkillUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SalvageConfig extends ConfigLoader {
|
||||
private List<Salvageable> salvageables;
|
||||
|
||||
public SalvageConfig(String fileName) {
|
||||
super(fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
salvageables = new ArrayList<Salvageable>();
|
||||
|
||||
ConfigurationSection section = config.getConfigurationSection("Salvageables");
|
||||
Set<String> keys = section.getKeys(false);
|
||||
|
||||
for (String key : keys) {
|
||||
// Validate all the things!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
// Item Material
|
||||
Material itemMaterial = Material.matchMaterial(key);
|
||||
|
||||
if (itemMaterial == null) {
|
||||
reason.add("Invalid material: " + key);
|
||||
}
|
||||
|
||||
// Salvage Material Type
|
||||
MaterialType salvageMaterialType = MaterialType.OTHER;
|
||||
String salvageMaterialTypeString = config.getString("Salvageables." + key + ".MaterialType", "OTHER");
|
||||
|
||||
if (!config.contains("Salvageables." + key + ".MaterialType") && itemMaterial != null) {
|
||||
ItemStack salvageItem = new ItemStack(itemMaterial);
|
||||
|
||||
if (ItemUtils.isWoodTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.WOOD;
|
||||
}
|
||||
else if (ItemUtils.isStoneTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.STONE;
|
||||
}
|
||||
else if (ItemUtils.isStringTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.STRING;
|
||||
}
|
||||
else if (ItemUtils.isLeatherArmor(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.LEATHER;
|
||||
}
|
||||
else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.IRON;
|
||||
}
|
||||
else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.GOLD;
|
||||
}
|
||||
else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.DIAMOND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
salvageMaterialType = MaterialType.valueOf(salvageMaterialTypeString.replace(" ", "_").toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid MaterialType of " + salvageMaterialTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
// Salvage Material
|
||||
String salvageMaterialName = config.getString("Salvageables." + key + ".SalvageMaterial");
|
||||
Material salvageMaterial = (salvageMaterialName == null ? salvageMaterialType.getDefaultMaterial() : Material.matchMaterial(salvageMaterialName));
|
||||
|
||||
if (salvageMaterial == null) {
|
||||
reason.add(key + " has an invalid salvage material: " + salvageMaterialName);
|
||||
}
|
||||
|
||||
// Maximum Durability
|
||||
short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() : (short) config.getInt("Salvageables." + key + ".MaximumDurability"));
|
||||
|
||||
// Item Type
|
||||
ItemType salvageItemType = ItemType.OTHER;
|
||||
String salvageItemTypeString = config.getString("Salvageables." + key + ".ItemType", "OTHER");
|
||||
|
||||
if (!config.contains("Salvageables." + key + ".ItemType") && itemMaterial != null) {
|
||||
ItemStack salvageItem = new ItemStack(itemMaterial);
|
||||
|
||||
if (ItemUtils.isMinecraftTool(salvageItem)) {
|
||||
salvageItemType = ItemType.TOOL;
|
||||
}
|
||||
else if (ItemUtils.isArmor(salvageItem)) {
|
||||
salvageItemType = ItemType.ARMOR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
salvageItemType = ItemType.valueOf(salvageItemTypeString.replace(" ", "_").toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid ItemType of " + salvageItemTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
byte salvageMetadata = (byte) config.getInt("Salvageables." + key + ".SalvageMaterialMetadata", -1);
|
||||
int minimumLevel = config.getInt("Salvageables." + key + ".MinimumLevel");
|
||||
double xpMultiplier = config.getDouble("Salvageables." + key + ".XpMultiplier", 1);
|
||||
|
||||
if (minimumLevel < 0) {
|
||||
reason.add(key + " has an invalid MinimumLevel of " + minimumLevel);
|
||||
}
|
||||
|
||||
// Maximum Quantity
|
||||
int maximumQuantity = (itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities(new ItemStack(itemMaterial), salvageMaterial, salvageMetadata) : config.getInt("Salvageables." + key + ".MaximumQuantity", 2));
|
||||
|
||||
if (maximumQuantity <= 0 && itemMaterial != null) {
|
||||
maximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", 1);
|
||||
}
|
||||
|
||||
int configMaximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", -1);
|
||||
|
||||
if (configMaximumQuantity > 0) {
|
||||
maximumQuantity = configMaximumQuantity;
|
||||
}
|
||||
|
||||
if (maximumQuantity <= 0) {
|
||||
reason.add("Maximum quantity of " + key + " must be greater than 0!");
|
||||
}
|
||||
|
||||
if (noErrorsInSalvageable(reason)) {
|
||||
Salvageable salvageable = SalvageableFactory.getSalvageable(itemMaterial, salvageMaterial, salvageMetadata, minimumLevel, maximumQuantity, maximumDurability, salvageItemType, salvageMaterialType, xpMultiplier);
|
||||
salvageables.add(salvageable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Salvageable> getLoadedSalvageables() {
|
||||
return salvageables == null ? new ArrayList<Salvageable>() : salvageables;
|
||||
}
|
||||
|
||||
private boolean noErrorsInSalvageable(List<String> issues) {
|
||||
if (!issues.isEmpty()) {
|
||||
plugin.getLogger().warning("Errors have been found in: " + fileName);
|
||||
plugin.getLogger().warning("The following issues were found:");
|
||||
}
|
||||
|
||||
for (String issue : issues) {
|
||||
plugin.getLogger().warning(issue);
|
||||
}
|
||||
|
||||
return issues.isEmpty();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.gmail.nossr50.config.skills.salvage;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SalvageConfigManager {
|
||||
private final List<Salvageable> salvageables = new ArrayList<Salvageable>();
|
||||
|
||||
public SalvageConfigManager(mcMMO plugin) {
|
||||
Pattern pattern = Pattern.compile("salvage\\.(?:.+)\\.yml");
|
||||
File dataFolder = plugin.getDataFolder();
|
||||
File vanilla = new File(dataFolder, "salvage.vanilla.yml");
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource("salvage.vanilla.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!pattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SalvageConfig salvageConfig = new SalvageConfig(fileName);
|
||||
salvageables.addAll(salvageConfig.getLoadedSalvageables());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Salvageable> getLoadedSalvageables() {
|
||||
return salvageables;
|
||||
}
|
||||
}
|
@ -0,0 +1,364 @@
|
||||
package com.gmail.nossr50.core.config.treasure;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.ConfigLoader;
|
||||
import com.gmail.nossr50.util.EnchantmentUtils;
|
||||
import com.gmail.nossr50.util.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionData;
|
||||
import org.bukkit.potion.PotionType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class TreasureConfig extends ConfigLoader {
|
||||
|
||||
private static TreasureConfig instance;
|
||||
|
||||
public HashMap<String, List<ExcavationTreasure>> excavationMap = new HashMap<String, List<ExcavationTreasure>>();
|
||||
|
||||
public HashMap<EntityType, List<ShakeTreasure>> shakeMap = new HashMap<EntityType, List<ShakeTreasure>>();
|
||||
public HashMap<String, List<HylianTreasure>> hylianMap = new HashMap<String, List<HylianTreasure>>();
|
||||
|
||||
public HashMap<Rarity, List<FishingTreasure>> fishingRewards = new HashMap<Rarity, List<FishingTreasure>>();
|
||||
public HashMap<Rarity, List<EnchantmentTreasure>> fishingEnchantments = new HashMap<Rarity, List<EnchantmentTreasure>>();
|
||||
|
||||
private TreasureConfig() {
|
||||
super("treasures.yml");
|
||||
loadKeys();
|
||||
validate();
|
||||
}
|
||||
|
||||
public static TreasureConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new TreasureConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
// Validate all the settings!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
for (String tier : config.getConfigurationSection("Enchantment_Drop_Rates").getKeys(false)) {
|
||||
double totalEnchantDropRate = 0;
|
||||
double totalItemDropRate = 0;
|
||||
|
||||
for (Rarity rarity : Rarity.values()) {
|
||||
double enchantDropRate = config.getDouble("Enchantment_Drop_Rates." + tier + "." + rarity.toString());
|
||||
double itemDropRate = config.getDouble("Item_Drop_Rates." + tier + "." + rarity.toString());
|
||||
|
||||
if ((enchantDropRate < 0.0 || enchantDropRate > 100.0) && rarity != Rarity.RECORD) {
|
||||
reason.add("The enchant drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
|
||||
}
|
||||
|
||||
if (itemDropRate < 0.0 || itemDropRate > 100.0) {
|
||||
reason.add("The item drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
|
||||
}
|
||||
|
||||
totalEnchantDropRate += enchantDropRate;
|
||||
totalItemDropRate += itemDropRate;
|
||||
}
|
||||
|
||||
if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) {
|
||||
reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!");
|
||||
}
|
||||
|
||||
if (totalItemDropRate < 0 || totalItemDropRate > 100.0) {
|
||||
reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!");
|
||||
}
|
||||
}
|
||||
|
||||
return noErrorsInConfig(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
if (config.getConfigurationSection("Treasures") != null) {
|
||||
backup();
|
||||
return;
|
||||
}
|
||||
|
||||
loadTreasures("Fishing");
|
||||
loadTreasures("Excavation");
|
||||
loadTreasures("Hylian_Luck");
|
||||
loadEnchantments();
|
||||
|
||||
for (EntityType entity : EntityType.values()) {
|
||||
if (entity.isAlive()) {
|
||||
loadTreasures("Shake." + entity.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTreasures(String type) {
|
||||
boolean isFishing = type.equals("Fishing");
|
||||
boolean isShake = type.contains("Shake");
|
||||
boolean isExcavation = type.equals("Excavation");
|
||||
boolean isHylian = type.equals("Hylian_Luck");
|
||||
|
||||
ConfigurationSection treasureSection = config.getConfigurationSection(type);
|
||||
|
||||
if (treasureSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize fishing HashMap
|
||||
for (Rarity rarity : Rarity.values()) {
|
||||
if (!fishingRewards.containsKey(rarity)) {
|
||||
fishingRewards.put(rarity, (new ArrayList<FishingTreasure>()));
|
||||
}
|
||||
}
|
||||
|
||||
for (String treasureName : treasureSection.getKeys(false)) {
|
||||
// Validate all the things!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
String[] treasureInfo = treasureName.split("[|]");
|
||||
String materialName = treasureInfo[0];
|
||||
|
||||
/*
|
||||
* Material, Amount, and Data
|
||||
*/
|
||||
Material material;
|
||||
|
||||
if (materialName.contains("INVENTORY")) {
|
||||
// Use magic material BEDROCK to know that we're grabbing something from the inventory and not a normal treasure
|
||||
if (!shakeMap.containsKey(EntityType.PLAYER))
|
||||
shakeMap.put(EntityType.PLAYER, new ArrayList<ShakeTreasure>());
|
||||
shakeMap.get(EntityType.PLAYER).add(new ShakeTreasure(new ItemStack(Material.BEDROCK, 1, (byte) 0), 1, getInventoryStealDropChance(), getInventoryStealDropLevel()));
|
||||
continue;
|
||||
} else {
|
||||
material = Material.matchMaterial(materialName);
|
||||
}
|
||||
|
||||
int amount = config.getInt(type + "." + treasureName + ".Amount");
|
||||
short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) : (short) config.getInt(type + "." + treasureName + ".Data");
|
||||
|
||||
if (material == null) {
|
||||
reason.add("Invalid material: " + materialName);
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
reason.add("Amount of " + treasureName + " must be greater than 0! " + amount);
|
||||
}
|
||||
|
||||
if (material != null && material.isBlock() && (data > 127 || data < -128)) {
|
||||
reason.add("Data of " + treasureName + " is invalid! " + data);
|
||||
}
|
||||
|
||||
/*
|
||||
* XP, Drop Chance, and Drop Level
|
||||
*/
|
||||
|
||||
int xp = config.getInt(type + "." + treasureName + ".XP");
|
||||
double dropChance = config.getDouble(type + "." + treasureName + ".Drop_Chance");
|
||||
int dropLevel = config.getInt(type + "." + treasureName + ".Drop_Level");
|
||||
|
||||
if (xp < 0) {
|
||||
reason.add(treasureName + " has an invalid XP value: " + xp);
|
||||
}
|
||||
|
||||
if (dropChance < 0.0D) {
|
||||
reason.add(treasureName + " has an invalid Drop_Chance: " + dropChance);
|
||||
}
|
||||
|
||||
if (dropLevel < 0) {
|
||||
reason.add(treasureName + " has an invalid Drop_Level: " + dropLevel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Specific Types
|
||||
*/
|
||||
Rarity rarity = null;
|
||||
|
||||
if (isFishing) {
|
||||
rarity = Rarity.getRarity(config.getString(type + "." + treasureName + ".Rarity"));
|
||||
|
||||
if (rarity == null) {
|
||||
reason.add("Invalid Rarity for item: " + treasureName);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Itemstack
|
||||
*/
|
||||
ItemStack item = null;
|
||||
|
||||
if (materialName.contains("POTION")) {
|
||||
Material mat = Material.matchMaterial(materialName);
|
||||
if (mat == null) {
|
||||
reason.add("Potion format for Treasures.yml has changed");
|
||||
} else {
|
||||
item = new ItemStack(mat, amount, data);
|
||||
PotionMeta itemMeta = (PotionMeta) item.getItemMeta();
|
||||
|
||||
PotionType potionType = null;
|
||||
try {
|
||||
potionType = PotionType.valueOf(config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
reason.add("Invalid Potion_Type: " + config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
|
||||
}
|
||||
boolean extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false);
|
||||
boolean upgraded = config.getBoolean(type + "." + treasureName + ".PotionData.Upgraded", false);
|
||||
itemMeta.setBasePotionData(new PotionData(potionType, extended, upgraded));
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Custom_Name")) {
|
||||
itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', config.getString(type + "." + treasureName + ".Custom_Name")));
|
||||
}
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Lore")) {
|
||||
List<String> lore = new ArrayList<String>();
|
||||
for (String s : config.getStringList(type + "." + treasureName + ".Lore")) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', s));
|
||||
}
|
||||
itemMeta.setLore(lore);
|
||||
}
|
||||
item.setItemMeta(itemMeta);
|
||||
}
|
||||
} else if (material != null) {
|
||||
item = new ItemStack(material, amount, data);
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Custom_Name")) {
|
||||
ItemMeta itemMeta = item.getItemMeta();
|
||||
itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', config.getString(type + "." + treasureName + ".Custom_Name")));
|
||||
item.setItemMeta(itemMeta);
|
||||
}
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Lore")) {
|
||||
ItemMeta itemMeta = item.getItemMeta();
|
||||
List<String> lore = new ArrayList<String>();
|
||||
for (String s : config.getStringList(type + "." + treasureName + ".Lore")) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', s));
|
||||
}
|
||||
itemMeta.setLore(lore);
|
||||
item.setItemMeta(itemMeta);
|
||||
}
|
||||
}
|
||||
|
||||
if (noErrorsInConfig(reason)) {
|
||||
if (isFishing) {
|
||||
fishingRewards.get(rarity).add(new FishingTreasure(item, xp));
|
||||
} else if (isShake) {
|
||||
ShakeTreasure shakeTreasure = new ShakeTreasure(item, xp, dropChance, dropLevel);
|
||||
|
||||
EntityType entityType = EntityType.valueOf(type.substring(6));
|
||||
if (!shakeMap.containsKey(entityType))
|
||||
shakeMap.put(entityType, new ArrayList<ShakeTreasure>());
|
||||
shakeMap.get(entityType).add(shakeTreasure);
|
||||
} else if (isExcavation) {
|
||||
ExcavationTreasure excavationTreasure = new ExcavationTreasure(item, xp, dropChance, dropLevel);
|
||||
List<String> dropList = config.getStringList(type + "." + treasureName + ".Drops_From");
|
||||
|
||||
for (String blockType : dropList) {
|
||||
if (!excavationMap.containsKey(blockType))
|
||||
excavationMap.put(blockType, new ArrayList<ExcavationTreasure>());
|
||||
excavationMap.get(blockType).add(excavationTreasure);
|
||||
}
|
||||
} else if (isHylian) {
|
||||
HylianTreasure hylianTreasure = new HylianTreasure(item, xp, dropChance, dropLevel);
|
||||
List<String> dropList = config.getStringList(type + "." + treasureName + ".Drops_From");
|
||||
|
||||
for (String dropper : dropList) {
|
||||
if (dropper.equals("Bushes")) {
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.FERN), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.TALL_GRASS), hylianTreasure);
|
||||
for (Material species : Tag.SAPLINGS.getValues())
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(species), hylianTreasure);
|
||||
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.DEAD_BUSH), hylianTreasure);
|
||||
continue;
|
||||
}
|
||||
if (dropper.equals("Flowers")) {
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.POPPY), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.DANDELION), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.BLUE_ORCHID), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.ALLIUM), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.AZURE_BLUET), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.ORANGE_TULIP), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.PINK_TULIP), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.RED_TULIP), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.WHITE_TULIP), hylianTreasure);
|
||||
continue;
|
||||
}
|
||||
if (dropper.equals("Pots")) {
|
||||
for (Material species : Tag.FLOWER_POTS.getValues())
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(species), hylianTreasure);
|
||||
continue;
|
||||
}
|
||||
AddHylianTreasure(dropper, hylianTreasure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddHylianTreasure(String dropper, HylianTreasure treasure) {
|
||||
if (!hylianMap.containsKey(dropper))
|
||||
hylianMap.put(dropper, new ArrayList<HylianTreasure>());
|
||||
hylianMap.get(dropper).add(treasure);
|
||||
}
|
||||
|
||||
private void loadEnchantments() {
|
||||
for (Rarity rarity : Rarity.values()) {
|
||||
if (rarity == Rarity.RECORD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fishingEnchantments.containsKey(rarity)) {
|
||||
fishingEnchantments.put(rarity, (new ArrayList<EnchantmentTreasure>()));
|
||||
}
|
||||
|
||||
ConfigurationSection enchantmentSection = config.getConfigurationSection("Enchantments_Rarity." + rarity.toString());
|
||||
|
||||
if (enchantmentSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String enchantmentName : enchantmentSection.getKeys(false)) {
|
||||
int level = config.getInt("Enchantments_Rarity." + rarity.toString() + "." + enchantmentName);
|
||||
Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName);
|
||||
|
||||
if (enchantment == null) {
|
||||
plugin.getLogger().warning("Skipping invalid enchantment in treasures.yml: " + enchantmentName);
|
||||
continue;
|
||||
}
|
||||
|
||||
fishingEnchantments.get(rarity).add(new EnchantmentTreasure(enchantment, level));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getInventoryStealEnabled() {
|
||||
return config.contains("Shake.PLAYER.INVENTORY");
|
||||
}
|
||||
|
||||
public boolean getInventoryStealStacks() {
|
||||
return config.getBoolean("Shake.PLAYER.INVENTORY.Whole_Stacks");
|
||||
}
|
||||
|
||||
public double getInventoryStealDropChance() {
|
||||
return config.getDouble("Shake.PLAYER.INVENTORY.Drop_Chance");
|
||||
}
|
||||
|
||||
public int getInventoryStealDropLevel() {
|
||||
return config.getInt("Shake.PLAYER.INVENTORY.Drop_Level");
|
||||
}
|
||||
|
||||
public double getItemDropRate(int tier, Rarity rarity) {
|
||||
return config.getDouble("Item_Drop_Rates.Tier_" + tier + "." + rarity.toString());
|
||||
}
|
||||
|
||||
public double getEnchantmentDropRate(int tier, Rarity rarity) {
|
||||
return config.getDouble("Enchantment_Drop_Rates.Tier_" + tier + "." + rarity.toString());
|
||||
}
|
||||
}
|
119
core/src/main/java/com/gmail/nossr50/core/data/UserManager.java
Normal file
119
core/src/main/java/com/gmail/nossr50/core/data/UserManager.java
Normal file
@ -0,0 +1,119 @@
|
||||
package com.gmail.nossr50.core.data;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.player.McMMOPlayer;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public final class UserManager {
|
||||
|
||||
private UserManager() {}
|
||||
|
||||
/**
|
||||
* Track a new user.
|
||||
*
|
||||
* @param mcMMOPlayer the player profile to start tracking
|
||||
*/
|
||||
public static void track(McMMOPlayer mcMMOPlayer) {
|
||||
mcMMOPlayer.getPlayer().setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mcMMOPlayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user.
|
||||
*
|
||||
* @param player The Player object
|
||||
*/
|
||||
public static void remove(Player player) {
|
||||
player.removeMetadata(mcMMO.playerDataKey, mcMMO.p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all users.
|
||||
*/
|
||||
public static void clearAll() {
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all users ON THIS THREAD.
|
||||
*/
|
||||
public static void saveAll() {
|
||||
ImmutableList<Player> onlinePlayers = ImmutableList.copyOf(mcMMO.p.getServer().getOnlinePlayers());
|
||||
mcMMO.p.debug("Saving mcMMOPlayers... (" + onlinePlayers.size() + ")");
|
||||
|
||||
for (Player player : onlinePlayers) {
|
||||
try
|
||||
{
|
||||
getPlayer(player).getProfile().save();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mcMMO.p.getLogger().warning("Could not save mcMMO player data for player: " + player.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<McMMOPlayer> getPlayers() {
|
||||
Collection<McMMOPlayer> playerCollection = new ArrayList<McMMOPlayer>();
|
||||
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
if (hasPlayerDataKey(player)) {
|
||||
playerCollection.add(getPlayer(player));
|
||||
}
|
||||
}
|
||||
|
||||
return playerCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the McMMOPlayer of a player by name.
|
||||
*
|
||||
* @param playerName The name of the player whose McMMOPlayer to retrieve
|
||||
* @return the player's McMMOPlayer object
|
||||
*/
|
||||
public static McMMOPlayer getPlayer(String playerName) {
|
||||
return retrieveMcMMOPlayer(playerName, false);
|
||||
}
|
||||
|
||||
public static McMMOPlayer getOfflinePlayer(OfflinePlayer player) {
|
||||
if (player instanceof Player) {
|
||||
return getPlayer((Player) player);
|
||||
}
|
||||
|
||||
return retrieveMcMMOPlayer(player.getName(), true);
|
||||
}
|
||||
|
||||
public static McMMOPlayer getOfflinePlayer(String playerName) {
|
||||
return retrieveMcMMOPlayer(playerName, true);
|
||||
}
|
||||
|
||||
public static McMMOPlayer getPlayer(Player player) {
|
||||
return (McMMOPlayer) player.getMetadata(mcMMO.playerDataKey).get(0).value();
|
||||
}
|
||||
|
||||
private static McMMOPlayer retrieveMcMMOPlayer(String playerName, boolean offlineValid) {
|
||||
Player player = mcMMO.p.getServer().getPlayerExact(playerName);
|
||||
|
||||
if (player == null) {
|
||||
if (!offlineValid) {
|
||||
mcMMO.p.getLogger().warning("A valid mcMMOPlayer object could not be found for " + playerName + ".");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return getPlayer(player);
|
||||
}
|
||||
|
||||
public static boolean hasPlayerDataKey(Entity entity) {
|
||||
return entity != null && entity.hasMetadata(mcMMO.playerDataKey);
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public interface ChunkletManager {
|
||||
/**
|
||||
* Loads a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be loaded
|
||||
* @param cy Chunklet Y coordinate that needs to be loaded
|
||||
* @param cz Chunklet Z coordinate that needs to be loaded
|
||||
* @param world World that the chunklet needs to be loaded in
|
||||
*/
|
||||
public void loadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be unloaded
|
||||
* @param cy Chunklet Y coordinate that needs to be unloaded
|
||||
* @param cz Chunklet Z coordinate that needs to be unloaded
|
||||
* @param world World that the chunklet needs to be unloaded from
|
||||
*/
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Load a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be loaded
|
||||
* @param cz Chunk Z coordinate that is to be loaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void loadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be unloaded
|
||||
* @param cz Chunk Z coordinate that is to be unloaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void unloadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is loaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is loaded
|
||||
* @param cz Chunk Z coordinate that is loaded
|
||||
* @param world World that the chunk was loaded in
|
||||
*/
|
||||
public void chunkLoaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is unloaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is unloaded
|
||||
* @param cz Chunk Z coordinate that is unloaded
|
||||
* @param world World that the chunk was unloaded in
|
||||
*/
|
||||
public void chunkUnloaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores related to the given world
|
||||
*
|
||||
* @param world World to save
|
||||
*/
|
||||
public void saveWorld(World world);
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
||||
*
|
||||
* @param world World to unload
|
||||
*/
|
||||
public void unloadWorld(World world);
|
||||
|
||||
/**
|
||||
* Load all ChunkletStores from all loaded chunks from this world into memory
|
||||
*
|
||||
* @param world World to load
|
||||
*/
|
||||
public void loadWorld(World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores
|
||||
*/
|
||||
public void saveAll();
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores after saving them
|
||||
*/
|
||||
public void unloadAll();
|
||||
|
||||
/**
|
||||
* Check to see if a given location is set to true
|
||||
*
|
||||
* @param x X coordinate to check
|
||||
* @param y Y coordinate to check
|
||||
* @param z Z coordinate to check
|
||||
* @param world World to check in
|
||||
* @return true if the given location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Check to see if a given block location is set to true
|
||||
*
|
||||
* @param block Block location to check
|
||||
* @return true if the given block location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(Block block);
|
||||
|
||||
/**
|
||||
* Set a given location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setTrue(Block block);
|
||||
|
||||
/**
|
||||
* Set a given location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setFalse(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setFalse(Block block);
|
||||
|
||||
/**
|
||||
* Delete any ChunkletStores that are empty
|
||||
*/
|
||||
public void cleanUp();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.HiddenConfig;
|
||||
|
||||
public class ChunkletManagerFactory {
|
||||
public static ChunkletManager getChunkletManager() {
|
||||
HiddenConfig hConfig = HiddenConfig.getInstance();
|
||||
|
||||
if (hConfig.getChunkletsEnabled()) {
|
||||
return new HashChunkletManager();
|
||||
}
|
||||
|
||||
return new NullChunkletManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A ChunkletStore should be responsible for a 16x16x64 area of data
|
||||
*/
|
||||
public interface ChunkletStore extends Serializable {
|
||||
/**
|
||||
* Checks the value at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
* @return true if the value is true at the given coordinates, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to true at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to false at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setFalse(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* @return true if all values in the chunklet are false, false if otherwise
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Set all values in this ChunkletStore to the values from another provided ChunkletStore
|
||||
*
|
||||
* @param otherStore Another ChunkletStore that this one should copy all data from
|
||||
*/
|
||||
public void copyFrom(ChunkletStore otherStore);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
public class ChunkletStoreFactory {
|
||||
protected static ChunkletStore getChunkletStore() {
|
||||
// TODO: Add in loading from config what type of store we want.
|
||||
return new PrimitiveExChunkletStore();
|
||||
}
|
||||
}
|
@ -0,0 +1,410 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class HashChunkletManager implements ChunkletManager {
|
||||
public HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
|
||||
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
return;
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
return;
|
||||
}
|
||||
File yFile = new File(czDir, "" + cy);
|
||||
if (!yFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChunkletStore in = deserializeChunkletStore(yFile);
|
||||
if (in != null) {
|
||||
store.put(world.getName() + "," + cx + "," + cz + "," + cy, in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
if (store.containsKey(world.getName() + "," + cx + "," + cz + "," + cy)) {
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
cxDir.mkdir();
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
czDir.mkdir();
|
||||
}
|
||||
File yFile = new File(czDir, "" + cy);
|
||||
|
||||
ChunkletStore out = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
|
||||
serializeChunkletStore(out, yFile);
|
||||
store.remove(world.getName() + "," + cx + "," + cz + "," + cy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
return;
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = 0; y < 4; y++) {
|
||||
File yFile = new File(czDir, "" + y);
|
||||
if (!yFile.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ChunkletStore in = deserializeChunkletStore(yFile);
|
||||
if (in != null) {
|
||||
store.put(world.getName() + "," + cx + "," + cz + "," + y, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
|
||||
for (int y = 0; y < 4; y++) {
|
||||
if (store.containsKey(world.getName() + "," + cx + "," + cz + "," + y)) {
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
cxDir.mkdir();
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
czDir.mkdir();
|
||||
}
|
||||
File yFile = new File(czDir, "" + y);
|
||||
|
||||
ChunkletStore out = store.get(world.getName() + "," + cx + "," + cz + "," + y);
|
||||
serializeChunkletStore(out, yFile);
|
||||
store.remove(world.getName() + "," + cx + "," + cz + "," + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {
|
||||
//loadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {
|
||||
unloadChunk(cx, cx, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {
|
||||
String worldName = world.getName();
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
if (!dataDir.exists()) {
|
||||
dataDir.mkdirs();
|
||||
}
|
||||
|
||||
for (String key : store.keySet()) {
|
||||
String[] info = key.split(",");
|
||||
if (worldName.equals(info[0])) {
|
||||
File cxDir = new File(dataDir, "" + info[1]);
|
||||
if (!cxDir.exists()) {
|
||||
cxDir.mkdir();
|
||||
}
|
||||
File czDir = new File(cxDir, "" + info[2]);
|
||||
if (!czDir.exists()) {
|
||||
czDir.mkdir();
|
||||
}
|
||||
|
||||
File yFile = new File(czDir, "" + info[3]);
|
||||
serializeChunkletStore(store.get(key), yFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {
|
||||
saveWorld(world);
|
||||
|
||||
String worldName = world.getName();
|
||||
|
||||
for (String key : store.keySet()) {
|
||||
String tempWorldName = key.split(",")[0];
|
||||
if (tempWorldName.equals(worldName)) {
|
||||
store.remove(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {
|
||||
//for (Chunk chunk : world.getLoadedChunks()) {
|
||||
// this.chunkLoaded(chunk.getX(), chunk.getZ(), world);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
||||
saveWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {
|
||||
saveAll();
|
||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cy = y >> 6;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz + "," + cy;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunklet(cx, cy, cz, world);
|
||||
}
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkletStore check = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
int iy = Math.abs(y) % 64;
|
||||
|
||||
return check.isTrue(ix, iy, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cy = y >> 6;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
int iy = Math.abs(y) % 64;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz + "," + cy;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunklet(cx, cy, cz, world);
|
||||
}
|
||||
|
||||
ChunkletStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
cStore = ChunkletStoreFactory.getChunkletStore();
|
||||
|
||||
store.put(world.getName() + "," + cx + "," + cz + "," + cy, cStore);
|
||||
}
|
||||
|
||||
cStore.setTrue(ix, iy, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {
|
||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cy = y >> 6;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
int iy = Math.abs(y) % 64;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz + "," + cy;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunklet(cx, cy, cz, world);
|
||||
}
|
||||
|
||||
ChunkletStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
return; // No need to make a store for something we will be setting to false
|
||||
}
|
||||
|
||||
cStore.setFalse(ix, iy, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {
|
||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
for (String key : store.keySet()) {
|
||||
if (store.get(key).isEmpty()) {
|
||||
String[] info = key.split(",");
|
||||
File dataDir = new File(mcMMO.p.getServer().getWorld(info[0]).getWorldFolder(), "mcmmo_data");
|
||||
|
||||
File cxDir = new File(dataDir, "" + info[1]);
|
||||
if (!cxDir.exists()) {
|
||||
continue;
|
||||
}
|
||||
File czDir = new File(cxDir, "" + info[2]);
|
||||
if (!czDir.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File yFile = new File(czDir, "" + info[3]);
|
||||
yFile.delete();
|
||||
|
||||
// Delete empty directories
|
||||
if (czDir.list().length == 0) {
|
||||
czDir.delete();
|
||||
}
|
||||
if (cxDir.list().length == 0) {
|
||||
cxDir.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cStore ChunkletStore to save
|
||||
* @param location Where on the disk to put it
|
||||
*/
|
||||
private void serializeChunkletStore(ChunkletStore cStore, File location) {
|
||||
FileOutputStream fileOut = null;
|
||||
ObjectOutputStream objOut = null;
|
||||
|
||||
try {
|
||||
if (!location.exists()) {
|
||||
location.createNewFile();
|
||||
}
|
||||
fileOut = new FileOutputStream(location);
|
||||
objOut = new ObjectOutputStream(fileOut);
|
||||
objOut.writeObject(cStore);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
if (objOut != null) {
|
||||
try {
|
||||
objOut.flush();
|
||||
objOut.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (fileOut != null) {
|
||||
try {
|
||||
fileOut.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location Where on the disk to read from
|
||||
* @return ChunkletStore from the specified location
|
||||
*/
|
||||
private ChunkletStore deserializeChunkletStore(File location) {
|
||||
ChunkletStore storeIn = null;
|
||||
FileInputStream fileIn = null;
|
||||
ObjectInputStream objIn = null;
|
||||
|
||||
try {
|
||||
fileIn = new FileInputStream(location);
|
||||
objIn = new ObjectInputStream(fileIn);
|
||||
storeIn = (ChunkletStore) objIn.readObject();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
if (ex instanceof EOFException) {
|
||||
// EOF should only happen on Chunklets that somehow have been corrupted.
|
||||
//mcMMO.p.getLogger().severe("Chunklet data at " + location.toString() + " could not be read due to an EOFException, data in this area will be lost.");
|
||||
return ChunkletStoreFactory.getChunkletStore();
|
||||
}
|
||||
else if (ex instanceof StreamCorruptedException) {
|
||||
// StreamCorrupted happens when the Chunklet is no good.
|
||||
//mcMMO.p.getLogger().severe("Chunklet data at " + location.toString() + " is corrupted, data in this area will be lost.");
|
||||
return ChunkletStoreFactory.getChunkletStore();
|
||||
}
|
||||
else if (ex instanceof UTFDataFormatException) {
|
||||
// UTF happens when the Chunklet cannot be read or is corrupted
|
||||
//mcMMO.p.getLogger().severe("Chunklet data at " + location.toString() + " could not be read due to an UTFDataFormatException, data in this area will be lost.");
|
||||
return ChunkletStoreFactory.getChunkletStore();
|
||||
}
|
||||
|
||||
ex.printStackTrace();
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
if (objIn != null) {
|
||||
try {
|
||||
objIn.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (fileIn != null) {
|
||||
try {
|
||||
fileIn.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make this less messy, as it is, it's kinda... depressing to do it like this.
|
||||
// Might also make a mess when we move to stacks, but at that point I think I will write a new Manager...
|
||||
// IMPORTANT! If ChunkletStoreFactory is going to be returning something other than PrimitiveEx we need to remove this, as it will be breaking time for old maps
|
||||
|
||||
/*
|
||||
if (!(storeIn instanceof PrimitiveExChunkletStore)) {
|
||||
ChunkletStore tempStore = ChunkletStoreFactory.getChunkletStore();
|
||||
if (storeIn != null) {
|
||||
tempStore.copyFrom(storeIn);
|
||||
}
|
||||
storeIn = tempStore;
|
||||
}
|
||||
*/
|
||||
|
||||
return storeIn;
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
/**
|
||||
* A ChunkletManager implementation that does nothing and returns false for all checks.
|
||||
*
|
||||
* Useful for turning off Chunklets without actually doing much work
|
||||
*/
|
||||
public class NullChunkletManager implements ChunkletManager {
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
public class PrimitiveChunkletStore implements ChunkletStore {
|
||||
private static final long serialVersionUID = -3453078050608607478L;
|
||||
|
||||
/** X, Z, Y */
|
||||
public boolean[][][] store = new boolean[16][16][64];
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
store[x][z][y] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
store[x][z][y] = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
if (store[x][z][y]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
public class PrimitiveExChunkletStore implements ChunkletStore, Externalizable {
|
||||
private static final long serialVersionUID = 8603603827094383873L;
|
||||
|
||||
/** X, Z, Y */
|
||||
public boolean[][][] store = new boolean[16][16][64];
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
store[x][z][y] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
store[x][z][y] = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
if (store[x][z][y]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
byte[] buffer = new byte[2304]; // 2304 is 16*16*9
|
||||
int bufferIndex = 0;
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
if (store[x][z][y]) {
|
||||
byte[] temp = constructColumn(x, z);
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
buffer[bufferIndex] = temp[i];
|
||||
bufferIndex++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out.write(buffer, 0, bufferIndex);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
// For this we assume that store has been initialized to be all false by now
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException {
|
||||
byte[] temp = new byte[9];
|
||||
|
||||
// Could probably reorganize this loop to print nasty things if it does not equal 9 or -1
|
||||
while (in.read(temp, 0, 9) == 9) {
|
||||
int x = addressByteX(temp[0]);
|
||||
int z = addressByteZ(temp[0]);
|
||||
boolean[] yColumn = new boolean[64];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
yColumn[j + (i * 8)] = (temp[i + 1] & (1 << j)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
store[x][z] = yColumn;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The column: An array of 9 bytes which represent all y values for a given (x,z) Chunklet-coordinate
|
||||
*
|
||||
* The first byte is an address byte, this provides the x and z values.
|
||||
* The next 8 bytes are all y values from 0 to 63, with each byte containing 8 bits of true/false data
|
||||
*
|
||||
* Each of these 8 bytes address to a y value from right to left
|
||||
*
|
||||
* Examples:
|
||||
* 00000001 represents that the lowest y value in this byte is true, all others are off
|
||||
* 10000000 represents that the highest y value in this byte is true, all others are off
|
||||
* 10000001 represents that the lowest and highest y values in this byte are true, all others are off
|
||||
*
|
||||
* Full columns:
|
||||
* See comment on Address byte for information on how to use that byte
|
||||
*
|
||||
* Example:
|
||||
* ADDRESS_BYTE 10000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
* - x, z from ADDRESS_BYTE
|
||||
* - The next byte contains data from 0 to 7
|
||||
* - 1 is set in the highest bit position, this is 7 in y coordinate
|
||||
* - The next byte contains data from 8 to 15
|
||||
* - 1 is set in the lowest bit position, this is 8 in the y coordinate
|
||||
* Therefore, for this column: There are true values at (x, 7, z) and (x, 8, z)
|
||||
*/
|
||||
private byte[] constructColumn(int x, int z) {
|
||||
byte[] column = new byte[9];
|
||||
int index = 1;
|
||||
|
||||
column[0] = makeAddressByte(x, z);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
byte yCompressed = 0x0;
|
||||
int subColumnIndex = 8 * i;
|
||||
int subColumnEnd = subColumnIndex + 8;
|
||||
|
||||
for (int y = subColumnIndex; y < subColumnEnd; y++) {
|
||||
if (store[x][z][y]) {
|
||||
yCompressed |= 1 << (y % 8);
|
||||
}
|
||||
}
|
||||
|
||||
column[index] = yCompressed;
|
||||
index++;
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
/*
|
||||
* The address byte: A single byte which contains x and z values which correspond to the x and z Chunklet-coordinates
|
||||
*
|
||||
* In Chunklet-coordinates, the only valid values are 0-15, so we can fit both into a single byte.
|
||||
*
|
||||
* The top 4 bits of the address byte are for the x value
|
||||
* The bottom 4 bits of the address byte are for the z value
|
||||
*
|
||||
* Examples:
|
||||
* An address byte with a value 00000001 would be split like so:
|
||||
* - x = 0000 = 0
|
||||
* - z = 0001 = 1
|
||||
* => Chunklet coordinates (0, 1)
|
||||
*
|
||||
* 01011111
|
||||
* - x = 0101 = 5
|
||||
* - z = 1111 = 15
|
||||
* => Chunklet coordinates (5, 15)
|
||||
*/
|
||||
protected static byte makeAddressByte(int x, int z) {
|
||||
return (byte) ((x << 4) + z);
|
||||
}
|
||||
|
||||
protected static int addressByteX(byte address) {
|
||||
return (address & 0xF0) >>> 4;
|
||||
}
|
||||
|
||||
protected static int addressByteZ(byte address) {
|
||||
return address & 0x0F;
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ChunkManager {
|
||||
public void closeAll();
|
||||
|
||||
public ChunkStore readChunkStore(World world, int x, int z) throws IOException;
|
||||
|
||||
public void writeChunkStore(World world, int x, int z, ChunkStore data);
|
||||
|
||||
public void closeChunkStore(World world, int x, int z);
|
||||
|
||||
/**
|
||||
* Loads a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be loaded
|
||||
* @param cy Chunklet Y coordinate that needs to be loaded
|
||||
* @param cz Chunklet Z coordinate that needs to be loaded
|
||||
* @param world World that the chunklet needs to be loaded in
|
||||
*/
|
||||
public void loadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be unloaded
|
||||
* @param cy Chunklet Y coordinate that needs to be unloaded
|
||||
* @param cz Chunklet Z coordinate that needs to be unloaded
|
||||
* @param world World that the chunklet needs to be unloaded from
|
||||
*/
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Load a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be loaded
|
||||
* @param cz Chunk Z coordinate that is to be loaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void loadChunk(int cx, int cz, World world, Entity[] entities);
|
||||
|
||||
/**
|
||||
* Unload a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be unloaded
|
||||
* @param cz Chunk Z coordinate that is to be unloaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void unloadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Saves a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be saved
|
||||
* @param cz Chunk Z coordinate that is to be saved
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void saveChunk(int cx, int cz, World world);
|
||||
|
||||
public boolean isChunkLoaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is loaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is loaded
|
||||
* @param cz Chunk Z coordinate that is loaded
|
||||
* @param world World that the chunk was loaded in
|
||||
*/
|
||||
public void chunkLoaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is unloaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is unloaded
|
||||
* @param cz Chunk Z coordinate that is unloaded
|
||||
* @param world World that the chunk was unloaded in
|
||||
*/
|
||||
public void chunkUnloaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores related to the given world
|
||||
*
|
||||
* @param world World to save
|
||||
*/
|
||||
public void saveWorld(World world);
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
||||
*
|
||||
* @param world World to unload
|
||||
*/
|
||||
public void unloadWorld(World world);
|
||||
|
||||
/**
|
||||
* Load all ChunkletStores from all loaded chunks from this world into memory
|
||||
*
|
||||
* @param world World to load
|
||||
*/
|
||||
public void loadWorld(World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores
|
||||
*/
|
||||
public void saveAll();
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores after saving them
|
||||
*/
|
||||
public void unloadAll();
|
||||
|
||||
/**
|
||||
* Check to see if a given location is set to true
|
||||
*
|
||||
* @param x X coordinate to check
|
||||
* @param y Y coordinate to check
|
||||
* @param z Z coordinate to check
|
||||
* @param world World to check in
|
||||
* @return true if the given location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Check to see if a given block location is set to true
|
||||
*
|
||||
* @param block Block location to check
|
||||
* @return true if the given block location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(Block block);
|
||||
|
||||
/**
|
||||
* Check to see if a given BlockState location is set to true
|
||||
*
|
||||
* @param blockState BlockState to check
|
||||
* @return true if the given BlockState location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(BlockState blockState);
|
||||
|
||||
/**
|
||||
* Set a given location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setTrue(Block block);
|
||||
|
||||
/**
|
||||
* Set a given BlockState location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param blockState BlockState location to set
|
||||
*/
|
||||
public void setTrue(BlockState blockState);
|
||||
|
||||
/**
|
||||
* Set a given location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setFalse(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setFalse(Block block);
|
||||
|
||||
/**
|
||||
* Set a given BlockState location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param blockState BlockState location to set
|
||||
*/
|
||||
public void setFalse(BlockState blockState);
|
||||
|
||||
/**
|
||||
* Delete any ChunkletStores that are empty
|
||||
*/
|
||||
public void cleanUp();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.HiddenConfig;
|
||||
|
||||
public class ChunkManagerFactory {
|
||||
public static ChunkManager getChunkManager() {
|
||||
HiddenConfig hConfig = HiddenConfig.getInstance();
|
||||
|
||||
if (hConfig.getChunkletsEnabled()) {
|
||||
return new HashChunkManager();
|
||||
}
|
||||
|
||||
return new NullChunkManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.data.blockmeta.ChunkletStore;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A ChunkStore should be responsible for a 16x16xWorldHeight area of data
|
||||
*/
|
||||
public interface ChunkStore extends Serializable {
|
||||
/**
|
||||
* Checks the chunk's save state
|
||||
*
|
||||
* @return true if the has been modified since it was last saved
|
||||
*/
|
||||
public boolean isDirty();
|
||||
|
||||
/**
|
||||
* Checks the chunk's save state
|
||||
*
|
||||
* @param dirty the save state of the current chunk
|
||||
*/
|
||||
public void setDirty(boolean dirty);
|
||||
|
||||
/**
|
||||
* Checks the chunk's x coordinate
|
||||
*
|
||||
* @return the chunk's x coordinate.
|
||||
*/
|
||||
public int getChunkX();
|
||||
|
||||
/**
|
||||
* Checks the chunk's z coordinate
|
||||
*
|
||||
* @return the chunk's z coordinate.
|
||||
*/
|
||||
public int getChunkZ();
|
||||
|
||||
/**
|
||||
* Checks the value at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
* @return true if the value is true at the given coordinates, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to true at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to false at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setFalse(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* @return true if all values in the chunklet are false, false if otherwise
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Set all values in this ChunkletStore to the values from another provided ChunkletStore
|
||||
*
|
||||
* @param otherStore Another ChunkletStore that this one should copy all data from
|
||||
*/
|
||||
public void copyFrom(ChunkletStore otherStore);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
public class ChunkStoreFactory {
|
||||
protected static ChunkStore getChunkStore(World world, int x, int z) {
|
||||
// TODO: Add in loading from config what type of store we want.
|
||||
return new PrimitiveChunkStore(world, x, z);
|
||||
}
|
||||
}
|
@ -0,0 +1,462 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.data.blockmeta.blockmeta.conversion.BlockStoreConversionZDirectory;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class HashChunkManager implements ChunkManager {
|
||||
private HashMap<UUID, HashMap<Long, McMMOSimpleRegionFile>> regionFiles = new HashMap<UUID, HashMap<Long, McMMOSimpleRegionFile>>();
|
||||
public HashMap<String, ChunkStore> store = new HashMap<String, ChunkStore>();
|
||||
public ArrayList<BlockStoreConversionZDirectory> converters = new ArrayList<BlockStoreConversionZDirectory>();
|
||||
private HashMap<UUID, Boolean> oldData = new HashMap<UUID, Boolean>();
|
||||
|
||||
@Override
|
||||
public synchronized void closeAll() {
|
||||
for (UUID uid : regionFiles.keySet()) {
|
||||
HashMap<Long, McMMOSimpleRegionFile> worldRegions = regionFiles.get(uid);
|
||||
for (Iterator<McMMOSimpleRegionFile> worldRegionIterator = worldRegions.values().iterator(); worldRegionIterator.hasNext(); ) {
|
||||
McMMOSimpleRegionFile rf = worldRegionIterator.next();
|
||||
if (rf != null) {
|
||||
rf.close();
|
||||
worldRegionIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
regionFiles.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ChunkStore readChunkStore(World world, int x, int z) throws IOException {
|
||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
InputStream in = rf.getInputStream(x, z);
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
ObjectInputStream objectStream = new ObjectInputStream(in);
|
||||
try {
|
||||
Object o = objectStream.readObject();
|
||||
if (o instanceof ChunkStore) {
|
||||
return (ChunkStore) o;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Wrong class type read for chunk meta data for " + x + ", " + z);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Assume the format changed
|
||||
return null;
|
||||
//throw new RuntimeException("Unable to process chunk meta data for " + x + ", " + z, e);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
// Assume the format changed
|
||||
//System.out.println("[SpoutPlugin] is Unable to find serialized class for " + x + ", " + z + ", " + e.getMessage());
|
||||
return null;
|
||||
//throw new RuntimeException("Unable to find serialized class for " + x + ", " + z, e);
|
||||
}
|
||||
finally {
|
||||
objectStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void writeChunkStore(World world, int x, int z, ChunkStore data) {
|
||||
if (!data.isDirty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
ObjectOutputStream objectStream = new ObjectOutputStream(rf.getOutputStream(x, z));
|
||||
objectStream.writeObject(data);
|
||||
objectStream.flush();
|
||||
objectStream.close();
|
||||
data.setDirty(false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Unable to write chunk meta data for " + x + ", " + z, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeChunkStore(World world, int x, int z) {
|
||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
if (rf != null) {
|
||||
rf.close();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized McMMOSimpleRegionFile getSimpleRegionFile(World world, int x, int z) {
|
||||
File directory = new File(world.getWorldFolder(), "mcmmo_regions");
|
||||
|
||||
directory.mkdirs();
|
||||
|
||||
UUID key = world.getUID();
|
||||
|
||||
HashMap<Long, McMMOSimpleRegionFile> worldRegions = regionFiles.get(key);
|
||||
|
||||
if (worldRegions == null) {
|
||||
worldRegions = new HashMap<Long, McMMOSimpleRegionFile>();
|
||||
regionFiles.put(key, worldRegions);
|
||||
}
|
||||
|
||||
int rx = x >> 5;
|
||||
int rz = z >> 5;
|
||||
|
||||
long key2 = (((long) rx) << 32) | ((rz) & 0xFFFFFFFFL);
|
||||
|
||||
McMMOSimpleRegionFile regionFile = worldRegions.get(key2);
|
||||
|
||||
if (regionFile == null) {
|
||||
File file = new File(directory, "mcmmo_" + rx + "_" + rz + "_.mcm");
|
||||
regionFile = new McMMOSimpleRegionFile(file, rx, rz);
|
||||
worldRegions.put(key2, regionFile);
|
||||
}
|
||||
|
||||
return regionFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
unloadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadChunk(int cx, int cz, World world, Entity[] entities) {
|
||||
if (world == null || store.containsKey(world.getName() + "," + cx + "," + cz)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID key = world.getUID();
|
||||
|
||||
if (!oldData.containsKey(key)) {
|
||||
oldData.put(key, (new File(world.getWorldFolder(), "mcmmo_data")).exists());
|
||||
}
|
||||
else if (oldData.get(key)) {
|
||||
if (convertChunk(new File(world.getWorldFolder(), "mcmmo_data"), cx, cz, world, true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ChunkStore chunkStore = null;
|
||||
|
||||
try {
|
||||
chunkStore = readChunkStore(world, cx, cz);
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
|
||||
if (chunkStore == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.put(world.getName() + "," + cx + "," + cz, chunkStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadChunk(int cx, int cz, World world) {
|
||||
saveChunk(cx, cz, world);
|
||||
|
||||
if (store.containsKey(world.getName() + "," + cx + "," + cz)) {
|
||||
store.remove(world.getName() + "," + cx + "," + cz);
|
||||
|
||||
//closeChunkStore(world, cx, cz);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveChunk(int cx, int cz, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (store.containsKey(key)) {
|
||||
ChunkStore out = store.get(world.getName() + "," + cx + "," + cz);
|
||||
|
||||
if (!out.isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeChunkStore(world, cx, cz, out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isChunkLoaded(int cx, int cz, World world) {
|
||||
if (world == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return store.containsKey(world.getName() + "," + cx + "," + cz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void chunkLoaded(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public synchronized void chunkUnloaded(int cx, int cz, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
unloadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveWorld(World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeAll();
|
||||
String worldName = world.getName();
|
||||
|
||||
List<String> keys = new ArrayList<String>(store.keySet());
|
||||
for (String key : keys) {
|
||||
String[] info = key.split(",");
|
||||
if (worldName.equals(info[0])) {
|
||||
try {
|
||||
saveChunk(Integer.parseInt(info[1]), Integer.parseInt(info[2]), world);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadWorld(World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeAll();
|
||||
String worldName = world.getName();
|
||||
|
||||
List<String> keys = new ArrayList<String>(store.keySet());
|
||||
for (String key : keys) {
|
||||
String[] info = key.split(",");
|
||||
if (worldName.equals(info[0])) {
|
||||
try {
|
||||
unloadChunk(Integer.parseInt(info[1]), Integer.parseInt(info[2]), world);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public synchronized void saveAll() {
|
||||
closeAll();
|
||||
|
||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
||||
saveWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadAll() {
|
||||
closeAll();
|
||||
|
||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(int x, int y, int z, World world) {
|
||||
if (world == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkStore check = store.get(key);
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
return check.isTrue(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(Block block) {
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(BlockState blockState) {
|
||||
if (blockState == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setTrue(int x, int y, int z, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
ChunkStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
cStore = ChunkStoreFactory.getChunkStore(world, cx, cz);
|
||||
store.put(key, cStore);
|
||||
}
|
||||
|
||||
cStore.setTrue(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setTrue(Block block) {
|
||||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(BlockState blockState) {
|
||||
if (blockState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTrue(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(int x, int y, int z, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
ChunkStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
return; // No need to make a store for something we will be setting to false
|
||||
}
|
||||
|
||||
cStore.setFalse(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(Block block) {
|
||||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(BlockState blockState) {
|
||||
if (blockState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setFalse(blockState.getX(), blockState.getY(), blockState.getZ(), blockState.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cleanUp() {}
|
||||
|
||||
public synchronized void convertChunk(File dataDir, int cx, int cz, World world) {
|
||||
convertChunk(dataDir, cx, cz, world, false);
|
||||
}
|
||||
|
||||
public synchronized boolean convertChunk(File dataDir, int cx, int cz, World world, boolean actually) {
|
||||
if (!actually || !dataDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean conversionSet = false;
|
||||
|
||||
for (BlockStoreConversionZDirectory converter : this.converters) {
|
||||
if (converter == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (converter.taskID >= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
converter.start(world, cxDir, czDir);
|
||||
conversionSet = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!conversionSet) {
|
||||
BlockStoreConversionZDirectory converter = new BlockStoreConversionZDirectory();
|
||||
converter.start(world, cxDir, czDir);
|
||||
converters.add(converter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of SpoutPlugin.
|
||||
*
|
||||
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
|
||||
* SpoutPlugin is licensed under the GNU Lesser General Public License.
|
||||
*
|
||||
* SpoutPlugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SpoutPlugin 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class McMMOSimpleChunkBuffer extends ByteArrayOutputStream {
|
||||
final McMMOSimpleRegionFile rf;
|
||||
final int index;
|
||||
|
||||
McMMOSimpleChunkBuffer(McMMOSimpleRegionFile rf, int index) {
|
||||
super(1024);
|
||||
this.rf = rf;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
rf.write(index, buf, count);
|
||||
}
|
||||
}
|
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* This file is part of SpoutPlugin.
|
||||
*
|
||||
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
|
||||
* SpoutPlugin is licensed under the GNU Lesser General Public License.
|
||||
*
|
||||
* SpoutPlugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SpoutPlugin 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
public class McMMOSimpleRegionFile {
|
||||
private RandomAccessFile file;
|
||||
private final int[] dataStart = new int[1024];
|
||||
private final int[] dataActualLength = new int[1024];
|
||||
private final int[] dataLength = new int[1024];
|
||||
private final ArrayList<Boolean> inuse = new ArrayList<Boolean>();
|
||||
private int segmentSize;
|
||||
private int segmentMask;
|
||||
private final int rx;
|
||||
private final int rz;
|
||||
private final int defaultSegmentSize;
|
||||
private final File parent;
|
||||
@SuppressWarnings("unused")
|
||||
private long lastAccessTime = System.currentTimeMillis();
|
||||
@SuppressWarnings("unused")
|
||||
private static long TIMEOUT_TIME = 300000; // 5 min
|
||||
|
||||
public McMMOSimpleRegionFile(File f, int rx, int rz) {
|
||||
this(f, rx, rz, 10);
|
||||
}
|
||||
|
||||
public McMMOSimpleRegionFile(File f, int rx, int rz, int defaultSegmentSize) {
|
||||
this.rx = rx;
|
||||
this.rz = rz;
|
||||
this.defaultSegmentSize = defaultSegmentSize;
|
||||
this.parent = f;
|
||||
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
if (file == null) {
|
||||
try {
|
||||
this.file = new RandomAccessFile(parent, "rw");
|
||||
|
||||
if (file.length() < 4096 * 3) {
|
||||
for (int i = 0; i < 1024 * 3; i++) {
|
||||
file.writeInt(0);
|
||||
}
|
||||
file.seek(4096 * 2);
|
||||
file.writeInt(defaultSegmentSize);
|
||||
}
|
||||
|
||||
file.seek(4096 * 2);
|
||||
|
||||
this.segmentSize = file.readInt();
|
||||
this.segmentMask = (1 << segmentSize) - 1;
|
||||
|
||||
int reservedSegments = this.sizeToSegments(4096 * 3);
|
||||
|
||||
for (int i = 0; i < reservedSegments; i++) {
|
||||
while (inuse.size() <= i) {
|
||||
inuse.add(false);
|
||||
}
|
||||
inuse.set(i, true);
|
||||
}
|
||||
|
||||
file.seek(0);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataStart[i] = file.readInt();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataActualLength[i] = file.readInt();
|
||||
dataLength[i] = sizeToSegments(dataActualLength[i]);
|
||||
setInUse(i, true);
|
||||
}
|
||||
|
||||
extendFile();
|
||||
}
|
||||
catch (IOException fnfe) {
|
||||
throw new RuntimeException(fnfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized final RandomAccessFile getFile() {
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
if (file == null) {
|
||||
try {
|
||||
this.file = new RandomAccessFile(parent, "rw");
|
||||
|
||||
if (file.length() < 4096 * 3) {
|
||||
for (int i = 0; i < 1024 * 3; i++) {
|
||||
file.writeInt(0);
|
||||
}
|
||||
file.seek(4096 * 2);
|
||||
file.writeInt(defaultSegmentSize);
|
||||
}
|
||||
|
||||
file.seek(4096 * 2);
|
||||
|
||||
this.segmentSize = file.readInt();
|
||||
this.segmentMask = (1 << segmentSize) - 1;
|
||||
|
||||
int reservedSegments = this.sizeToSegments(4096 * 3);
|
||||
|
||||
for (int i = 0; i < reservedSegments; i++) {
|
||||
while (inuse.size() <= i) {
|
||||
inuse.add(false);
|
||||
}
|
||||
inuse.set(i, true);
|
||||
}
|
||||
|
||||
file.seek(0);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataStart[i] = file.readInt();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataActualLength[i] = file.readInt();
|
||||
dataLength[i] = sizeToSegments(dataActualLength[i]);
|
||||
setInUse(i, true);
|
||||
}
|
||||
|
||||
extendFile();
|
||||
}
|
||||
catch (IOException fnfe) {
|
||||
throw new RuntimeException(fnfe);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public synchronized boolean testCloseTimeout() {
|
||||
/*
|
||||
if (System.currentTimeMillis() - TIMEOUT_TIME > lastAccessTime) {
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized DataOutputStream getOutputStream(int x, int z) {
|
||||
int index = getChunkIndex(x, z);
|
||||
return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index)));
|
||||
}
|
||||
|
||||
public synchronized DataInputStream getInputStream(int x, int z) throws IOException {
|
||||
int index = getChunkIndex(x, z);
|
||||
int actualLength = dataActualLength[index];
|
||||
|
||||
if (actualLength == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] data = new byte[actualLength];
|
||||
|
||||
getFile().seek(dataStart[index] << segmentSize);
|
||||
getFile().readFully(data);
|
||||
return new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data)));
|
||||
}
|
||||
|
||||
synchronized void write(int index, byte[] buffer, int size) throws IOException {
|
||||
int oldStart = setInUse(index, false);
|
||||
int start = findSpace(oldStart, size);
|
||||
getFile().seek(start << segmentSize);
|
||||
getFile().write(buffer, 0, size);
|
||||
dataStart[index] = start;
|
||||
dataActualLength[index] = size;
|
||||
dataLength[index] = sizeToSegments(size);
|
||||
setInUse(index, true);
|
||||
saveFAT();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
try {
|
||||
if (file != null) {
|
||||
file.seek(4096 * 2);
|
||||
file.close();
|
||||
}
|
||||
|
||||
file = null;
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new RuntimeException("Unable to close file", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int setInUse(int index, boolean used) {
|
||||
if (dataActualLength[index] == 0) {
|
||||
return dataStart[index];
|
||||
}
|
||||
|
||||
int start = dataStart[index];
|
||||
int end = start + dataLength[index];
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
while (i > inuse.size() - 1) {
|
||||
inuse.add(false);
|
||||
}
|
||||
|
||||
Boolean old = inuse.set(i, used);
|
||||
if (old != null && old == used) {
|
||||
if (old) {
|
||||
throw new IllegalStateException("Attempting to overwrite an in-use segment");
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Attempting to delete empty segment");
|
||||
}
|
||||
}
|
||||
|
||||
return dataStart[index];
|
||||
}
|
||||
|
||||
private synchronized void extendFile() throws IOException {
|
||||
long extend = (-getFile().length()) & segmentMask;
|
||||
|
||||
getFile().seek(getFile().length());
|
||||
|
||||
while ((extend--) > 0) {
|
||||
getFile().write(0);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int findSpace(int oldStart, int size) {
|
||||
int segments = sizeToSegments(size);
|
||||
|
||||
boolean oldFree = true;
|
||||
for (int i = oldStart; i < inuse.size() && i < oldStart + segments; i++) {
|
||||
if (inuse.get(i)) {
|
||||
oldFree = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldFree) {
|
||||
return oldStart;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
|
||||
while (end < inuse.size()) {
|
||||
if (inuse.get(end)) {
|
||||
end++;
|
||||
start = end;
|
||||
}
|
||||
else {
|
||||
end++;
|
||||
}
|
||||
|
||||
if (end - start >= segments) {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private synchronized int sizeToSegments(int size) {
|
||||
if (size <= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ((size - 1) >> segmentSize) + 1;
|
||||
}
|
||||
|
||||
private synchronized Integer getChunkIndex(int x, int z) {
|
||||
if (rx != (x >> 5) || rz != (z >> 5)) {
|
||||
throw new RuntimeException(x + ", " + z + " not in region " + rx + ", " + rz);
|
||||
}
|
||||
|
||||
x = x & 0x1F;
|
||||
z = z & 0x1F;
|
||||
|
||||
return (x << 5) + z;
|
||||
}
|
||||
|
||||
private synchronized void saveFAT() throws IOException {
|
||||
getFile().seek(0);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
getFile().writeInt(dataStart[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
getFile().writeInt(dataActualLength[i]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NullChunkManager implements ChunkManager {
|
||||
|
||||
@Override
|
||||
public void closeAll() {}
|
||||
|
||||
@Override
|
||||
public ChunkStore readChunkStore(World world, int x, int z) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChunkStore(World world, int x, int z, ChunkStore data) {}
|
||||
|
||||
@Override
|
||||
public void closeChunkStore(World world, int x, int z) {}
|
||||
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world, Entity[] entities) {}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void saveChunk(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int cx, int cz, World world) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {}
|
||||
|
||||
@Override
|
||||
public void saveAll() {}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(BlockState blockState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {}
|
||||
|
||||
@Override
|
||||
public void setTrue(BlockState blockState) {}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {}
|
||||
|
||||
@Override
|
||||
public void setFalse(BlockState blockState) {}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.data.blockmeta.ChunkletStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PrimitiveChunkStore implements ChunkStore {
|
||||
private static final long serialVersionUID = -1L;
|
||||
transient private boolean dirty = false;
|
||||
/** X, Z, Y */
|
||||
public boolean[][][] store;
|
||||
private static final int CURRENT_VERSION = 7;
|
||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||
private int cx;
|
||||
private int cz;
|
||||
private UUID worldUid;
|
||||
|
||||
public PrimitiveChunkStore(World world, int cx, int cz) {
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
this.worldUid = world.getUID();
|
||||
this.store = new boolean[16][16][world.getMaxHeight()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirty(boolean dirty) {
|
||||
this.dirty = dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkX() {
|
||||
return cx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkZ() {
|
||||
return cz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
if (y >= store[0][0].length || y < 0)
|
||||
return;
|
||||
store[x][z][y] = true;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
if (y >= store[0][0].length || y < 0)
|
||||
return;
|
||||
store[x][z][y] = false;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < store[0][0].length; y++) {
|
||||
if (store[x][z][y]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < store[0][0].length; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.writeInt(MAGIC_NUMBER);
|
||||
out.writeInt(CURRENT_VERSION);
|
||||
|
||||
out.writeLong(worldUid.getLeastSignificantBits());
|
||||
out.writeLong(worldUid.getMostSignificantBits());
|
||||
out.writeInt(cx);
|
||||
out.writeInt(cz);
|
||||
out.writeObject(store);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
int magic = in.readInt();
|
||||
// Can be used to determine the format of the file
|
||||
int fileVersionNumber = in.readInt();
|
||||
|
||||
if (magic != MAGIC_NUMBER) {
|
||||
fileVersionNumber = 0;
|
||||
}
|
||||
|
||||
long lsb = in.readLong();
|
||||
long msb = in.readLong();
|
||||
worldUid = new UUID(msb, lsb);
|
||||
cx = in.readInt();
|
||||
cz = in.readInt();
|
||||
|
||||
store = (boolean[][][]) in.readObject();
|
||||
|
||||
if (fileVersionNumber < 5) {
|
||||
fixArray();
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void fixArray() {
|
||||
boolean[][][] temp = this.store;
|
||||
this.store = new boolean[16][16][Bukkit.getWorld(worldUid).getMaxHeight()];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < store[0][0].length; y++) {
|
||||
try {
|
||||
store[x][z][y] = temp[x][y][z];
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.conversion;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.HiddenConfig;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BlockStoreConversionMain implements Runnable {
|
||||
private int taskID, i;
|
||||
private org.bukkit.World world;
|
||||
BukkitScheduler scheduler;
|
||||
File dataDir;
|
||||
File[] xDirs;
|
||||
BlockStoreConversionXDirectory[] converters;
|
||||
|
||||
public BlockStoreConversionMain(org.bukkit.World world) {
|
||||
this.taskID = -1;
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.dataDir = new File(this.world.getWorldFolder(), "mcmmo_data");
|
||||
this.converters = new BlockStoreConversionXDirectory[HiddenConfig.getInstance().getConversionRate()];
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (this.taskID >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.taskID = this.scheduler.runTaskLater(mcMMO.p, this, 1).getTaskId();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!this.dataDir.exists()) {
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.xDirs = this.dataDir.listFiles();
|
||||
|
||||
for (this.i = 0; (this.i < HiddenConfig.getInstance().getConversionRate()) && (this.i < this.xDirs.length); this.i++) {
|
||||
if (this.converters[this.i] == null) {
|
||||
this.converters[this.i] = new BlockStoreConversionXDirectory();
|
||||
}
|
||||
|
||||
this.converters[this.i].start(this.world, this.xDirs[this.i]);
|
||||
}
|
||||
|
||||
softStop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.taskID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduler.cancelTask(this.taskID);
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void softStop() {
|
||||
stop();
|
||||
|
||||
if (this.dataDir.exists() || this.dataDir.isDirectory()) {
|
||||
start();
|
||||
return;
|
||||
}
|
||||
|
||||
mcMMO.p.getLogger().info("Finished converting the storage for " + world.getName() + ".");
|
||||
|
||||
this.dataDir = null;
|
||||
this.xDirs = null;
|
||||
this.world = null;
|
||||
this.scheduler = null;
|
||||
this.converters = null;
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.conversion;
|
||||
|
||||
import com.gmail.nossr50.core.config.skills.HiddenConfig;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BlockStoreConversionXDirectory implements Runnable {
|
||||
private int taskID, i;
|
||||
private org.bukkit.World world;
|
||||
BukkitScheduler scheduler;
|
||||
File dataDir;
|
||||
File[] zDirs;
|
||||
BlockStoreConversionZDirectory[] converters;
|
||||
|
||||
public BlockStoreConversionXDirectory() {
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void start(org.bukkit.World world, File dataDir) {
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.converters = new BlockStoreConversionZDirectory[HiddenConfig.getInstance().getConversionRate()];
|
||||
this.dataDir = dataDir;
|
||||
|
||||
if (this.taskID >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.taskID = this.scheduler.runTaskLater(mcMMO.p, this, 1).getTaskId();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!this.dataDir.exists()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.zDirs = this.dataDir.listFiles();
|
||||
|
||||
for (this.i = 0; (this.i < HiddenConfig.getInstance().getConversionRate()) && (this.i < this.zDirs.length); this.i++) {
|
||||
if (this.converters[this.i] == null) {
|
||||
this.converters[this.i] = new BlockStoreConversionZDirectory();
|
||||
}
|
||||
|
||||
this.converters[this.i].start(this.world, this.dataDir, this.zDirs[this.i]);
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.taskID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduler.cancelTask(this.taskID);
|
||||
this.taskID = -1;
|
||||
|
||||
this.dataDir = null;
|
||||
this.zDirs = null;
|
||||
this.world = null;
|
||||
this.scheduler = null;
|
||||
this.converters = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.conversion;
|
||||
|
||||
import com.gmail.nossr50.core.data.blockmeta.ChunkletStore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.HashChunkletManager;
|
||||
import com.gmail.nossr50.core.data.blockmeta.PrimitiveChunkletStore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.PrimitiveExChunkletStore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.chunkmeta.HashChunkManager;
|
||||
import com.gmail.nossr50.core.data.blockmeta.chunkmeta.PrimitiveChunkStore;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BlockStoreConversionZDirectory implements Runnable {
|
||||
public int taskID, cx, cz, x, y, z, y2, xPos, zPos, cxPos, czPos;
|
||||
private String cxs, czs, chunkletName, chunkName;
|
||||
private org.bukkit.World world;
|
||||
private BukkitScheduler scheduler;
|
||||
private File xDir, dataDir;
|
||||
private HashChunkletManager manager;
|
||||
private HashChunkManager newManager;
|
||||
private ChunkletStore tempChunklet;
|
||||
private PrimitiveChunkletStore primitiveChunklet = null;
|
||||
private PrimitiveExChunkletStore primitiveExChunklet = null;
|
||||
private PrimitiveChunkStore currentChunk;
|
||||
private boolean[] oldArray, newArray;
|
||||
|
||||
public BlockStoreConversionZDirectory() {
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void start(org.bukkit.World world, File xDir, File dataDir) {
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.manager = new HashChunkletManager();
|
||||
this.newManager = (HashChunkManager) mcMMO.getPlaceStore();
|
||||
this.dataDir = dataDir;
|
||||
this.xDir = xDir;
|
||||
|
||||
if (this.taskID >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.taskID = this.scheduler.runTaskLater(mcMMO.p, this, 1).getTaskId();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!this.dataDir.exists()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.cxs = this.xDir.getName();
|
||||
this.czs = this.dataDir.getName();
|
||||
this.cx = 0;
|
||||
this.cz = 0;
|
||||
|
||||
try {
|
||||
this.cx = Integer.parseInt(this.cxs);
|
||||
this.cz = Integer.parseInt(this.czs);
|
||||
}
|
||||
catch (Exception e) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.manager.loadChunk(this.cx, this.cz, this.world);
|
||||
|
||||
for (this.y = 0; this.y < (this.world.getMaxHeight() / 64); this.y++) {
|
||||
this.chunkletName = this.world.getName() + "," + this.cx + "," + this.cz + "," + this.y;
|
||||
this.tempChunklet = this.manager.store.get(this.chunkletName);
|
||||
|
||||
if (this.tempChunklet instanceof PrimitiveChunkletStore) {
|
||||
this.primitiveChunklet = (PrimitiveChunkletStore) this.tempChunklet;
|
||||
}
|
||||
else if (this.tempChunklet instanceof PrimitiveExChunkletStore) {
|
||||
this.primitiveExChunklet = (PrimitiveExChunkletStore) this.tempChunklet;
|
||||
}
|
||||
|
||||
if (this.tempChunklet == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.chunkName = this.world.getName() + "," + this.cx + "," + this.cz;
|
||||
this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
|
||||
|
||||
if (this.currentChunk != null) {
|
||||
this.xPos = this.cx * 16;
|
||||
this.zPos = this.cz * 16;
|
||||
|
||||
for (this.x = 0; this.x < 16; this.x++) {
|
||||
for (this.z = 0; this.z < 16; this.z++) {
|
||||
this.cxPos = this.xPos + this.x;
|
||||
this.czPos = this.zPos + this.z;
|
||||
|
||||
for (this.y2 = (64 * this.y); this.y2 < (64 * this.y + 64); this.y2++) {
|
||||
try {
|
||||
if (!this.manager.isTrue(this.cxPos, this.y2, this.czPos, this.world)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.newManager.setTrue(this.cxPos, this.y2, this.czPos, this.world);
|
||||
}
|
||||
catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.newManager.setTrue(this.cx * 16, 0, this.cz * 16, this.world);
|
||||
this.newManager.setFalse(this.cx * 16, 0, this.cz * 16, this.world);
|
||||
this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
|
||||
|
||||
for (this.x = 0; this.x < 16; this.x++) {
|
||||
for (this.z = 0; this.z < 16; this.z++) {
|
||||
if (this.primitiveChunklet != null) {
|
||||
this.oldArray = this.primitiveChunklet.store[x][z];
|
||||
}
|
||||
|
||||
if (this.primitiveExChunklet != null) {
|
||||
this.oldArray = this.primitiveExChunklet.store[x][z];
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
this.newArray = this.currentChunk.store[x][z];
|
||||
|
||||
if (this.oldArray.length < 64) {
|
||||
return;
|
||||
}
|
||||
else if (this.newArray.length < ((this.y * 64) + 64)) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.arraycopy(this.oldArray, 0, this.newArray, (this.y * 64), 64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.manager.unloadChunk(this.cx, this.cz, this.world);
|
||||
this.newManager.unloadChunk(this.cx, this.cz, this.world);
|
||||
|
||||
for (File yFile : dataDir.listFiles()) {
|
||||
if (!yFile.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yFile.delete();
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.taskID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduler.cancelTask(taskID);
|
||||
this.taskID = -1;
|
||||
|
||||
this.cxs = null;
|
||||
this.czs = null;
|
||||
this.chunkletName = null;
|
||||
this.chunkName = null;
|
||||
this.manager = null;
|
||||
this.xDir = null;
|
||||
this.dataDir = null;
|
||||
this.tempChunklet = null;
|
||||
this.primitiveChunklet = null;
|
||||
this.primitiveExChunklet = null;
|
||||
this.currentChunk = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package com.gmail.nossr50.core.data.database;
|
||||
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.core.datatypes.database.DatabaseType;
|
||||
import com.gmail.nossr50.core.datatypes.database.PlayerStat;
|
||||
import com.gmail.nossr50.core.datatypes.player.PlayerProfile;
|
||||
import com.gmail.nossr50.core.datatypes.skills.PrimarySkillType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface DatabaseManager {
|
||||
// One month in milliseconds
|
||||
public final long PURGE_TIME = 2630000000L * Config.getInstance().getOldUsersCutoff();
|
||||
// During convertUsers, how often to output a status
|
||||
public final int progressInterval = 200;
|
||||
|
||||
/**
|
||||
* Purge users with 0 power level from the database.
|
||||
*/
|
||||
public void purgePowerlessUsers();
|
||||
|
||||
/**
|
||||
* Purge users who haven't logged on in over a certain time frame from the database.
|
||||
*/
|
||||
public void purgeOldUsers();
|
||||
|
||||
/**
|
||||
* Remove a user from the database.
|
||||
*
|
||||
* @param playerName The name of the user to remove
|
||||
* @return true if the user was successfully removed, false otherwise
|
||||
*/
|
||||
public boolean removeUser(String playerName);
|
||||
|
||||
/**
|
||||
* Save a user to the database.
|
||||
*
|
||||
* @param profile The profile of the player to save
|
||||
* @return true if successful, false on failure
|
||||
*/
|
||||
public boolean saveUser(PlayerProfile profile);
|
||||
|
||||
/**
|
||||
* Retrieve leaderboard info.
|
||||
*
|
||||
* @param skill The skill to retrieve info on
|
||||
* @param pageNumber Which page in the leaderboards to retrieve
|
||||
* @param statsPerPage The number of stats per page
|
||||
* @return the requested leaderboard information
|
||||
*/
|
||||
public List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage);
|
||||
|
||||
/**
|
||||
* Retrieve rank info into a HashMap from PrimarySkillType to the rank.
|
||||
* <p>
|
||||
* The special value <code>null</code> is used to represent the Power
|
||||
* Level rank (the combination of all skill levels).
|
||||
*
|
||||
* @param playerName The name of the user to retrieve the rankings for
|
||||
* @return the requested rank information
|
||||
*/
|
||||
public Map<PrimarySkillType, Integer> readRank(String playerName);
|
||||
|
||||
/**
|
||||
* Add a new user to the database.
|
||||
*
|
||||
* @param playerName The name of the player to be added to the database
|
||||
* @param uuid The uuid of the player to be added to the database
|
||||
*/
|
||||
public void newUser(String playerName, UUID uuid);
|
||||
|
||||
/**
|
||||
* Load a player from the database.
|
||||
*
|
||||
* @deprecated replaced by {@link #loadPlayerProfile(String playerName, UUID uuid, boolean createNew)}
|
||||
*
|
||||
* @param playerName The name of the player to load from the database
|
||||
* @param createNew Whether to create a new record if the player is not
|
||||
* found
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
* and createNew is false
|
||||
*/
|
||||
@Deprecated
|
||||
public PlayerProfile loadPlayerProfile(String playerName, boolean createNew);
|
||||
|
||||
/**
|
||||
* Load a player from the database.
|
||||
*
|
||||
* @param uuid The uuid of the player to load from the database
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
*/
|
||||
public PlayerProfile loadPlayerProfile(UUID uuid);
|
||||
|
||||
/**
|
||||
* Load a player from the database. Attempt to use uuid, fall back on playername
|
||||
*
|
||||
* @param playerName The name of the player to load from the database
|
||||
* @param uuid The uuid of the player to load from the database
|
||||
* @param createNew Whether to create a new record if the player is not
|
||||
* found
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
* and createNew is false
|
||||
*/
|
||||
public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean createNew);
|
||||
|
||||
/**
|
||||
* Get all users currently stored in the database.
|
||||
*
|
||||
* @return list of playernames
|
||||
*/
|
||||
public List<String> getStoredUsers();
|
||||
|
||||
/**
|
||||
* Convert all users from this database to the provided database using
|
||||
* {@link #saveUser(PlayerProfile)}.
|
||||
*
|
||||
* @param destination The DatabaseManager to save to
|
||||
*/
|
||||
public void convertUsers(DatabaseManager destination);
|
||||
|
||||
public boolean saveUserUUID(String userName, UUID uuid);
|
||||
|
||||
public boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs);
|
||||
|
||||
/**
|
||||
* Retrieve the type of database in use. Custom databases should return CUSTOM.
|
||||
*
|
||||
* @return The type of database
|
||||
*/
|
||||
public DatabaseType getDatabaseType();
|
||||
|
||||
/**
|
||||
* Called when the plugin disables
|
||||
*/
|
||||
public void onDisable();
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.gmail.nossr50.core.data.database;
|
||||
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.core.datatypes.database.DatabaseType;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
|
||||
public class DatabaseManagerFactory {
|
||||
private static Class<? extends DatabaseManager> customManager = null;
|
||||
|
||||
public static DatabaseManager getDatabaseManager() {
|
||||
if (customManager != null) {
|
||||
try {
|
||||
return createDefaultCustomDatabaseManager();
|
||||
}
|
||||
catch (Exception e) {
|
||||
mcMMO.p.debug("Could not create custom database manager");
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
mcMMO.p.debug("Failed to create custom database manager");
|
||||
e.printStackTrace();
|
||||
}
|
||||
mcMMO.p.debug("Falling back on " + (Config.getInstance().getUseMySQL() ? "SQL" : "Flatfile") + " database");
|
||||
}
|
||||
|
||||
return Config.getInstance().getUseMySQL() ? new SQLDatabaseManager() : new FlatfileDatabaseManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom DatabaseManager class for mcMMO to use. This should be
|
||||
* called prior to mcMMO enabling.
|
||||
* <p/>
|
||||
* The provided class must have an empty constructor, which is the one
|
||||
* that will be used.
|
||||
* <p/>
|
||||
* This method is intended for API use, but it should not be considered
|
||||
* stable. This method is subject to change and/or removal in future
|
||||
* versions.
|
||||
*
|
||||
* @param clazz the DatabaseManager class to use
|
||||
*
|
||||
* @throws IllegalArgumentException if the provided class does not have
|
||||
* an empty constructor
|
||||
*/
|
||||
public static void setCustomDatabaseManagerClass(Class<? extends DatabaseManager> clazz) {
|
||||
try {
|
||||
clazz.getConstructor();
|
||||
customManager = clazz;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new IllegalArgumentException("Provided database manager class must have an empty constructor", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<? extends DatabaseManager> getCustomDatabaseManagerClass() {
|
||||
return customManager;
|
||||
}
|
||||
|
||||
public static DatabaseManager createDatabaseManager(DatabaseType type) {
|
||||
switch (type) {
|
||||
case DatabaseType.FLATFILE:
|
||||
return new FlatfileDatabaseManager();
|
||||
|
||||
case DatabaseType.SQL:
|
||||
return new SQLDatabaseManager();
|
||||
|
||||
case DatabaseType.CUSTOM:
|
||||
try {
|
||||
return createDefaultCustomDatabaseManager();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static DatabaseManager createDefaultCustomDatabaseManager() throws Throwable {
|
||||
return customManager.getConstructor().newInstance();
|
||||
}
|
||||
|
||||
public static DatabaseManager createCustomDatabaseManager(Class<? extends DatabaseManager> clazz) throws Throwable {
|
||||
return clazz.getConstructor().newInstance();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A World in MC
|
||||
* Stuff mcMMO does not require will not be in this class
|
||||
*/
|
||||
public abstract class AbstractWorld implements World {
|
||||
|
||||
private final String worldName;
|
||||
|
||||
public AbstractWorld(String worldName)
|
||||
{
|
||||
this.worldName = worldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this World
|
||||
*
|
||||
* @return the name of this world
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return worldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to another to see if they are equal
|
||||
* @param o the other object
|
||||
* @return true if they are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof AbstractWorld)) return false;
|
||||
AbstractWorld that = (AbstractWorld) o;
|
||||
return worldName.equals(that.worldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash code for the object, used for comparisons
|
||||
* @return hash code for this object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(worldName);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.gmail.nossr50.datatypes;
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
/**
|
||||
* This class represents a Location in MC
|
@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
public interface Nameable extends Named {
|
||||
/**
|
||||
* Change the name for this entity
|
||||
* @param newName the new name of this entity
|
||||
*/
|
||||
void setName(String newName);
|
||||
|
||||
/**
|
||||
* Returns the original name for this entity before any renaming
|
||||
* @return the original name of this entity
|
||||
*/
|
||||
String getOriginalName();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
/**
|
||||
* A lot of Objects in MC have names
|
||||
* This is what this class is for
|
||||
*/
|
||||
public interface Named {
|
||||
/**
|
||||
* Returns the name of this entity
|
||||
* @return this entity
|
||||
*/
|
||||
String getName();
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Properties are Comparable key value pairs for a blocks state
|
||||
* In MC this exists in three forms, Integer, Booleans, and Enums
|
||||
*
|
||||
* This class partially mirrors MC Internals
|
||||
*
|
||||
*/
|
||||
public interface Property<T extends Comparable<T>> {
|
||||
/**
|
||||
* The name of the Property
|
||||
* @return name of this property
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* A collection of allowed values for this property
|
||||
* @return the allowed values for this property
|
||||
*/
|
||||
Collection<T> getAllowedValues();
|
||||
|
||||
/**
|
||||
* The class of the value for this particular property
|
||||
* @return the value's class
|
||||
*/
|
||||
Class<T> getValueClass();
|
||||
|
||||
/**
|
||||
* The name for a specific value
|
||||
* @param value the value to match
|
||||
* @return the name of this value
|
||||
*/
|
||||
String getName(T value);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
public interface World {
|
||||
/**
|
||||
* Gets the name of this World
|
||||
* @return the name of this world
|
||||
*/
|
||||
String getName();
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.gmail.nossr50.datatypes.block;
|
||||
package com.gmail.nossr50.core.datatypes.block;
|
||||
|
||||
import com.gmail.nossr50.datatypes.Property;
|
||||
import com.gmail.nossr50.core.datatypes.Property;
|
||||
|
||||
/**
|
||||
* Represents a container of properties and values for a Block
|
@ -1,6 +1,6 @@
|
||||
package com.gmail.nossr50.datatypes.block;
|
||||
package com.gmail.nossr50.core.datatypes.block;
|
||||
|
||||
import com.gmail.nossr50.datatypes.Property;
|
||||
import com.gmail.nossr50.core.datatypes.Property;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.Collection;
|
@ -0,0 +1,24 @@
|
||||
package com.gmail.nossr50.core.datatypes.entity;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.Location;
|
||||
import com.gmail.nossr50.core.datatypes.Named;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Entities can be a lot of things in MC
|
||||
* Entities can be monsters, animals, players, etc...
|
||||
*/
|
||||
public interface Entity extends Location, Named {
|
||||
/**
|
||||
* The UUID for this entity
|
||||
* @return this entity's UUID
|
||||
*/
|
||||
UUID getUUID();
|
||||
|
||||
/**
|
||||
* The Location for this entity
|
||||
* @return this entity's location
|
||||
*/
|
||||
Location getLocation();
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.gmail.nossr50.core.datatypes.entity;
|
||||
|
||||
/**
|
||||
* Living means you can die, you have health, and you can be damaged
|
||||
*/
|
||||
public interface Living {
|
||||
/**
|
||||
* Whether or not this entity is still alive
|
||||
* @return true if the entity is alive
|
||||
*/
|
||||
Boolean isAlive();
|
||||
|
||||
/**
|
||||
* Change the health of an entity
|
||||
* @param newHealth the new health value for the entity
|
||||
*/
|
||||
void setHealth(int newHealth);
|
||||
|
||||
/**
|
||||
* Damage an entity
|
||||
* This damage will be reduced by any defensive modifiers such as armor
|
||||
* @param damage the damage to deal to this entity
|
||||
*/
|
||||
void damage(int damage);
|
||||
|
||||
/**
|
||||
* Damage an entity and attribute it to a source
|
||||
* This damage will be reduced by any defensive modifiers such as armor
|
||||
* @param source the source responsible for the damage
|
||||
* @param damage the damage to deal to this entity
|
||||
*/
|
||||
void damage(Entity source, int damage);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.gmail.nossr50.core.datatypes.entity;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.Nameable;
|
||||
|
||||
/**
|
||||
* Players
|
||||
*/
|
||||
public interface Player extends Living, Nameable {
|
||||
|
||||
/**
|
||||
* Players are not always online
|
||||
* @return true if the player is online
|
||||
*/
|
||||
Boolean isOnline();
|
||||
|
||||
/**
|
||||
* Gets the McMMOPlayer for this Player
|
||||
* @return the associated McMMOPlayer, can be null
|
||||
*/
|
||||
McMMOPlayer getMcMMOPlayer();
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.gmail.nossr50.core.datatypes.event;
|
||||
|
||||
/**
|
||||
* This class handles cancellations for an event
|
||||
*/
|
||||
public interface Cancellable {
|
||||
|
||||
/**
|
||||
* Whether or not the event is cancelled
|
||||
* @return true if cancelled
|
||||
*/
|
||||
Boolean isCancelled();
|
||||
|
||||
/**
|
||||
* Sets an events cancellation to b
|
||||
* @param b
|
||||
*/
|
||||
void setCancelled(boolean b);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.gmail.nossr50.core.datatypes.event;
|
||||
|
||||
/**
|
||||
* Represents an event for a given API
|
||||
*/
|
||||
public interface Event {
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.gmail.nossr50.core.datatypes.event;
|
||||
|
||||
/**
|
||||
* Different platforms have different event systems
|
||||
* These ENUMs will be the magic number for what kind of event we are targeting
|
||||
*/
|
||||
public enum EventType {
|
||||
//TODO: These are being based on the bukkit events mcMMO has used, the values will most likely change
|
||||
EVENT_BLOCK_PISTON_EXTEND,
|
||||
EVENT_BLOCK_PISTON_RETRACT,
|
||||
//Currently not sure I need this class, so I'll refrain from adding more events atm...
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.gmail.nossr50.platform;
|
||||
package com.gmail.nossr50.core.platform;
|
||||
|
||||
/**
|
||||
* This is the implementation of the Platform Interface
|
@ -1,4 +1,4 @@
|
||||
package com.gmail.nossr50.platform;
|
||||
package com.gmail.nossr50.core.platform;
|
||||
|
||||
/**
|
||||
* Represents the current API Platform
|
||||
@ -30,4 +30,9 @@ public interface Platform {
|
||||
*/
|
||||
Boolean isPlatformLoaded();
|
||||
|
||||
/**
|
||||
* Gets the PlatformSoftwareType for this platform
|
||||
* @return this PlatformSoftwareType
|
||||
*/
|
||||
PlatformSoftwareType getPlatformSoftwareType();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.gmail.nossr50.core.platform;
|
||||
|
||||
/**
|
||||
* ENUMs representing the software the platform belongs to
|
||||
*/
|
||||
public enum PlatformSoftwareType {
|
||||
NMS,
|
||||
BUKKIT,
|
||||
SPONGE
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.gmail.nossr50.platform;
|
||||
package com.gmail.nossr50.core.platform;
|
||||
|
||||
/**
|
||||
* Constants for targeted versions of MC
|
@ -0,0 +1,20 @@
|
||||
package com.gmail.nossr50.core.platform.drivers;
|
||||
|
||||
import com.gmail.nossr50.core.platform.Platform;
|
||||
|
||||
/**
|
||||
* Platform Drivers will handled translating our abstraction into instructions for various APIs
|
||||
*/
|
||||
public interface PlatformDriver {
|
||||
/**
|
||||
* Return the platform for this Driver
|
||||
* @return this platform
|
||||
*/
|
||||
Platform getPlatform();
|
||||
|
||||
/**
|
||||
* Gets the target MC Version for this driver
|
||||
* @return the target MC Version for this driver
|
||||
*/
|
||||
String getTargetMinecraftVersion();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.gmail.nossr50.core.platform.drivers;
|
||||
|
||||
/**
|
||||
* This driver handles instructions for events for a platform
|
||||
*/
|
||||
public interface PlatformEventDriver extends PlatformDriver {
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package com.gmail.nossr50.datatypes;
|
||||
|
||||
/**
|
||||
* Properties are Comparable key value pairs for a blocks state
|
||||
* In MC this exists in three forms, Integer, Booleans, and Enums
|
||||
*/
|
||||
public interface Property<T extends Comparable<T>> {
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.gmail.nossr50.datatypes;
|
||||
|
||||
public interface World {
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package com.gmail.nossr50.platform;
|
||||
|
||||
/**
|
||||
* Constants representing the software the platform belongs to
|
||||
*/
|
||||
public enum PlatformSoftwareType {
|
||||
NMS,
|
||||
BUKKIT,
|
||||
SPONGE
|
||||
}
|
Reference in New Issue
Block a user