Fix mcMMO saving copies of config files into the main server directory instead of the correct place

This commit is contained in:
nossr50 2021-04-09 10:19:34 -07:00
parent 6d057c577e
commit c1c32cb1fd
13 changed files with 64 additions and 49 deletions

View File

@ -1,5 +1,6 @@
package com.gmail.nossr50.config; package com.gmail.nossr50.config;
import com.gmail.nossr50.mcMMO;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -31,7 +32,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
protected void saveConfig() { protected void saveConfig() {
try { try {
plugin.getLogger().info("Saving changes to config file - "+fileName); mcMMO.p.getLogger().info("Saving changes to config file - "+fileName);
config.save(configFile); config.save(configFile);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -39,13 +40,13 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
} }
protected @NotNull FileConfiguration getInternalConfig() { protected @NotNull FileConfiguration getInternalConfig() {
return YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName)); return YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName));
} }
@Override @Override
protected void loadFile() { protected void loadFile() {
super.loadFile(); super.loadFile();
FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName)); FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName));
Set<String> configKeys = config.getKeys(true); Set<String> configKeys = config.getKeys(true);
Set<String> internalConfigKeys = internalConfig.getKeys(true); Set<String> internalConfigKeys = internalConfig.getKeys(true);
@ -65,12 +66,12 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
} }
// //
// for (String key : oldKeys) { // for (String key : oldKeys) {
// plugin.debug("Detected potentially unused key: " + key); // mcMMO.p.debug("Detected potentially unused key: " + key);
// //config.set(key, null); // //config.set(key, null);
// } // }
for (String key : newKeys) { for (String key : newKeys) {
plugin.debug("Adding new key: " + key + " = " + internalConfig.get(key)); mcMMO.p.debug("Adding new key: " + key + " = " + internalConfig.get(key));
config.set(key, internalConfig.get(key)); config.set(key, internalConfig.get(key));
} }
@ -89,7 +90,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
// Read the internal config to get comments, then put them in the new one // Read the internal config to get comments, then put them in the new one
try { try {
// Read internal // Read internal
BufferedReader reader = new BufferedReader(new InputStreamReader(plugin.getResource(fileName))); BufferedReader reader = new BufferedReader(new InputStreamReader(mcMMO.p.getResource(fileName)));
LinkedHashMap<String, String> comments = new LinkedHashMap<>(); LinkedHashMap<String, String> comments = new LinkedHashMap<>();
StringBuilder temp = new StringBuilder(); StringBuilder temp = new StringBuilder();
@ -139,14 +140,21 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
} }
// Save it // Save it
if(dataFolder == null) {
mcMMO.p.getLogger().severe("Data folder should never be null!");
return;
}
try { try {
String saveName = fileName; String saveName = fileName;
// At this stage we cannot guarantee that Config has been loaded, so we do the check directly here // 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)) { if (!mcMMO.p.getConfig().getBoolean("General.Config_Update_Overwrite", true)) {
saveName += ".new"; saveName += ".new";
} }
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(dataFolder, saveName))); File newSaveFile = new File(dataFolder, saveName);
FileWriter fileWriter = new FileWriter(newSaveFile.getAbsolutePath());
BufferedWriter writer = new BufferedWriter(fileWriter);
writer.write(output); writer.write(output);
writer.flush(); writer.flush();
writer.close(); writer.close();

View File

@ -9,11 +9,10 @@ import java.io.File;
import java.util.List; import java.util.List;
public abstract class ConfigLoader { public abstract class ConfigLoader {
protected static final mcMMO plugin = mcMMO.p;
protected String fileName; protected String fileName;
protected final File configFile; protected final File configFile;
protected FileConfiguration config; protected FileConfiguration config;
protected @NotNull File dataFolder; protected @NotNull final File dataFolder;
public ConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) { public ConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) {
this.fileName = fileName; this.fileName = fileName;
@ -33,6 +32,7 @@ public abstract class ConfigLoader {
public ConfigLoader(String relativePath, String fileName) { public ConfigLoader(String relativePath, String fileName) {
this.fileName = fileName; this.fileName = fileName;
configFile = new File(mcMMO.p.getDataFolder(), relativePath + File.separator + fileName); configFile = new File(mcMMO.p.getDataFolder(), relativePath + File.separator + fileName);
this.dataFolder = mcMMO.p.getDataFolder();
loadFile(); loadFile();
} }
@ -40,22 +40,23 @@ public abstract class ConfigLoader {
public ConfigLoader(String fileName) { public ConfigLoader(String fileName) {
this.fileName = fileName; this.fileName = fileName;
configFile = new File(mcMMO.p.getDataFolder(), fileName); configFile = new File(mcMMO.p.getDataFolder(), fileName);
this.dataFolder = mcMMO.p.getDataFolder();
loadFile(); loadFile();
} }
protected void loadFile() { protected void loadFile() {
if (!configFile.exists()) { if (!configFile.exists()) {
plugin.debug("Creating mcMMO " + fileName + " File..."); mcMMO.p.debug("Creating mcMMO " + fileName + " File...");
try { try {
plugin.saveResource(fileName, false); // Normal files mcMMO.p.saveResource(fileName, false); // Normal files
} }
catch (IllegalArgumentException ex) { catch (IllegalArgumentException ex) {
plugin.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files mcMMO.p.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files
} }
} }
else { else {
plugin.debug("Loading mcMMO " + fileName + " File..."); mcMMO.p.debug("Loading mcMMO " + fileName + " File...");
} }
config = YamlConfiguration.loadConfiguration(configFile); config = YamlConfiguration.loadConfiguration(configFile);
@ -69,7 +70,7 @@ public abstract class ConfigLoader {
protected boolean noErrorsInConfig(List<String> issues) { protected boolean noErrorsInConfig(List<String> issues) {
for (String issue : issues) { for (String issue : issues) {
plugin.getLogger().warning(issue); mcMMO.p.getLogger().warning(issue);
} }
return issues.isEmpty(); return issues.isEmpty();
@ -77,12 +78,12 @@ public abstract class ConfigLoader {
protected void validate() { protected void validate() {
if (validateKeys()) { if (validateKeys()) {
plugin.debug("No errors found in " + fileName + "!"); mcMMO.p.debug("No errors found in " + fileName + "!");
} }
else { else {
plugin.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!");
plugin.getServer().getPluginManager().disablePlugin(plugin); mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p);
plugin.noErrorsInConfigFiles = false; mcMMO.p.noErrorsInConfigFiles = false;
} }
} }
@ -91,16 +92,16 @@ public abstract class ConfigLoader {
} }
public void backup() { public void backup() {
plugin.getLogger().warning("You are using an old version of the " + fileName + " file."); mcMMO.p.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."); mcMMO.p.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")); configFile.renameTo(new File(configFile.getPath() + ".old"));
if (plugin.getResource(fileName) != null) { if (mcMMO.p.getResource(fileName) != null) {
plugin.saveResource(fileName, true); mcMMO.p.saveResource(fileName, true);
} }
plugin.getLogger().warning("Reloading " + fileName + " with new values..."); mcMMO.p.getLogger().warning("Reloading " + fileName + " with new values...");
loadFile(); loadFile();
loadKeys(); loadKeys();
} }

View File

@ -127,7 +127,7 @@ public class RankConfig extends AutoUpdateConfigLoader {
String key = getRankAddressKey(subSkillType, rank, retroMode); String key = getRankAddressKey(subSkillType, rank, retroMode);
int defaultValue = getInternalConfig().getInt(key); int defaultValue = getInternalConfig().getInt(key);
config.set(key, defaultValue); config.set(key, defaultValue);
plugin.getLogger().info(key +" SET -> " + defaultValue); mcMMO.p.getLogger().info(key +" SET -> " + defaultValue);
} }
/** /**
@ -145,10 +145,10 @@ public class RankConfig extends AutoUpdateConfigLoader {
if(badSkillSetup.isEmpty()) if(badSkillSetup.isEmpty())
return; return;
plugin.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); mcMMO.p.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup");
for(SubSkillType subSkillType : badSkillSetup) { for(SubSkillType subSkillType : badSkillSetup) {
plugin.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString()); mcMMO.p.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString());
fixBadEntries(subSkillType); fixBadEntries(subSkillType);
} }
} }
@ -180,7 +180,7 @@ public class RankConfig extends AutoUpdateConfigLoader {
if(prevRank > curRank) if(prevRank > curRank)
{ {
//We're going to allow this but we're going to warn them //We're going to allow this but we're going to warn them
plugin.getLogger().info("(CONFIG ISSUE) You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); mcMMO.p.getLogger().info("(CONFIG ISSUE) You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements");
badSkillSetup.add(subSkillType); badSkillSetup.add(subSkillType);
} }
} }

View File

@ -1,5 +1,6 @@
package com.gmail.nossr50.config; package com.gmail.nossr50.config;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.util.sounds.SoundType;
public class SoundConfig extends AutoUpdateConfigLoader { public class SoundConfig extends AutoUpdateConfigLoader {
@ -31,7 +32,7 @@ public class SoundConfig extends AutoUpdateConfigLoader {
{ {
if(config.getDouble("Sounds."+soundType.toString()+".Volume") < 0) if(config.getDouble("Sounds."+soundType.toString()+".Volume") < 0)
{ {
plugin.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString()); mcMMO.p.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString());
return false; return false;
} }
@ -40,7 +41,7 @@ public class SoundConfig extends AutoUpdateConfigLoader {
{ {
if(config.getDouble("Sounds."+soundType.toString()+".Pitch") < 0) if(config.getDouble("Sounds."+soundType.toString()+".Pitch") < 0)
{ {
plugin.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString()); mcMMO.p.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString());
return false; return false;
} }
} }

View File

@ -3,6 +3,7 @@ package com.gmail.nossr50.config.mods;
import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.config.ConfigLoader;
import com.gmail.nossr50.datatypes.skills.ItemType; import com.gmail.nossr50.datatypes.skills.ItemType;
import com.gmail.nossr50.datatypes.skills.MaterialType; import com.gmail.nossr50.datatypes.skills.MaterialType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.Repairable;
import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
import org.bukkit.Material; import org.bukkit.Material;
@ -62,7 +63,7 @@ public class CustomArmorConfig extends ConfigLoader {
Material armorMaterial = Material.matchMaterial(armorName); Material armorMaterial = Material.matchMaterial(armorName);
if (armorMaterial == null) { if (armorMaterial == null) {
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName); mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName);
continue; continue;
} }
@ -70,7 +71,7 @@ public class CustomArmorConfig extends ConfigLoader {
Material repairMaterial = Material.matchMaterial(config.getString(armorType + "." + armorName + ".Repair_Material", "")); Material repairMaterial = Material.matchMaterial(config.getString(armorType + "." + armorName + ".Repair_Material", ""));
if (repairable && (repairMaterial == null)) { if (repairable && (repairMaterial == null)) {
plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName); mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName);
repairable = false; repairable = false;
} }

View File

@ -2,6 +2,7 @@ package com.gmail.nossr50.config.mods;
import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.config.ConfigLoader;
import com.gmail.nossr50.datatypes.mods.CustomBlock; import com.gmail.nossr50.datatypes.mods.CustomBlock;
import com.gmail.nossr50.mcMMO;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
@ -66,7 +67,7 @@ public class CustomBlockConfig extends ConfigLoader {
Material blockMaterial = Material.matchMaterial(blockInfo[0]); Material blockMaterial = Material.matchMaterial(blockInfo[0]);
if (blockMaterial == null) { if (blockMaterial == null) {
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]); mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]);
continue; continue;
} }

View File

@ -2,6 +2,7 @@ package com.gmail.nossr50.config.mods;
import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.config.ConfigLoader;
import com.gmail.nossr50.datatypes.mods.CustomEntity; import com.gmail.nossr50.datatypes.mods.CustomEntity;
import com.gmail.nossr50.mcMMO;
import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.ClassUtils;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -32,8 +33,8 @@ public class CustomEntityConfig extends ConfigLoader {
clazz = ClassUtils.getClass(className); clazz = ClassUtils.getClass(className);
} }
catch (ClassNotFoundException e) { catch (ClassNotFoundException e) {
plugin.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + "."); mcMMO.p.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + ".");
plugin.getLogger().warning("This custom entity may not function properly."); mcMMO.p.getLogger().warning("This custom entity may not function properly.");
} }
String entityTypeName = entityName.replace("_", "."); String entityTypeName = entityName.replace("_", ".");
@ -48,7 +49,7 @@ public class CustomEntityConfig extends ConfigLoader {
int callOfTheWildAmount = config.getInt(entityName + ".COTW_Material_Amount"); int callOfTheWildAmount = config.getInt(entityName + ".COTW_Material_Amount");
if (canBeSummoned && (callOfTheWildMaterial == null || callOfTheWildAmount == 0)) { 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."); mcMMO.p.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild.");
canBeSummoned = false; canBeSummoned = false;
} }

View File

@ -4,6 +4,7 @@ import com.gmail.nossr50.config.ConfigLoader;
import com.gmail.nossr50.datatypes.mods.CustomTool; import com.gmail.nossr50.datatypes.mods.CustomTool;
import com.gmail.nossr50.datatypes.skills.ItemType; import com.gmail.nossr50.datatypes.skills.ItemType;
import com.gmail.nossr50.datatypes.skills.MaterialType; import com.gmail.nossr50.datatypes.skills.MaterialType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.Repairable;
import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
import org.bukkit.Material; import org.bukkit.Material;
@ -70,7 +71,7 @@ public class CustomToolConfig extends ConfigLoader {
Material toolMaterial = Material.matchMaterial(toolName); Material toolMaterial = Material.matchMaterial(toolName);
if (toolMaterial == null) { if (toolMaterial == null) {
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName); mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName);
continue; continue;
} }
@ -78,7 +79,7 @@ public class CustomToolConfig extends ConfigLoader {
Material repairMaterial = Material.matchMaterial(config.getString(toolType + "." + toolName + ".Repair_Material", "")); Material repairMaterial = Material.matchMaterial(config.getString(toolType + "." + toolName + ".Repair_Material", ""));
if (repairable && (repairMaterial == null)) { if (repairable && (repairMaterial == null)) {
plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName); mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName);
repairable = false; repairable = false;
} }

View File

@ -182,7 +182,7 @@ public class RepairConfig extends ConfigLoader {
private boolean noErrorsInRepairable(List<String> issues) { private boolean noErrorsInRepairable(List<String> issues) {
for (String issue : issues) { for (String issue : issues) {
plugin.getLogger().warning(issue); mcMMO.p.getLogger().warning(issue);
} }
return issues.isEmpty(); return issues.isEmpty();

View File

@ -200,12 +200,12 @@ public class SalvageConfig extends ConfigLoader {
private boolean noErrorsInSalvageable(List<String> issues) { private boolean noErrorsInSalvageable(List<String> issues) {
if (!issues.isEmpty()) { if (!issues.isEmpty()) {
plugin.getLogger().warning("Errors have been found in: " + fileName); mcMMO.p.getLogger().warning("Errors have been found in: " + fileName);
plugin.getLogger().warning("The following issues were found:"); mcMMO.p.getLogger().warning("The following issues were found:");
} }
for (String issue : issues) { for (String issue : issues) {
plugin.getLogger().warning(issue); mcMMO.p.getLogger().warning(issue);
} }
return issues.isEmpty(); return issues.isEmpty();

View File

@ -348,7 +348,7 @@ public class FishingTreasureConfig extends ConfigLoader {
Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName); Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName);
if (enchantment == null) { if (enchantment == null) {
plugin.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); mcMMO.p.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName);
continue; continue;
} }

View File

@ -17,12 +17,12 @@ public class ChildConfig extends AutoUpdateConfigLoader {
@Override @Override
protected void loadKeys() { protected void loadKeys() {
config.setDefaults(YamlConfiguration.loadConfiguration(plugin.getResourceAsReader("child.yml"))); config.setDefaults(YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader("child.yml")));
FamilyTree.clearRegistrations(); // when reloading, need to clear statics FamilyTree.clearRegistrations(); // when reloading, need to clear statics
for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) { for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) {
plugin.debug("Finding parents of " + skill.name()); mcMMO.p.debug("Finding parents of " + skill.name());
EnumSet<PrimarySkillType> parentSkills = EnumSet.noneOf(PrimarySkillType.class); EnumSet<PrimarySkillType> parentSkills = EnumSet.noneOf(PrimarySkillType.class);
boolean useDefaults = false; // If we had an error we back out and use defaults boolean useDefaults = false; // If we had an error we back out and use defaults
@ -34,7 +34,7 @@ public class ChildConfig extends AutoUpdateConfigLoader {
parentSkills.add(parentSkill); parentSkills.add(parentSkill);
} }
catch (IllegalArgumentException ex) { catch (IllegalArgumentException ex) {
plugin.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); mcMMO.p.getLogger().warning(name + " is not a valid skill type, or is a child skill!");
useDefaults = true; useDefaults = true;
break; break;
} }
@ -53,7 +53,7 @@ public class ChildConfig extends AutoUpdateConfigLoader {
// Register them // Register them
for (PrimarySkillType parentSkill : parentSkills) { for (PrimarySkillType parentSkill : parentSkills) {
plugin.debug("Registering " + parentSkill.name() + " as parent of " + skill.name()); mcMMO.p.debug("Registering " + parentSkill.name() + " as parent of " + skill.name());
FamilyTree.registerParent(skill, parentSkill); FamilyTree.registerParent(skill, parentSkill);
} }
} }

View File

@ -2,6 +2,7 @@ package com.gmail.nossr50.util.upgrade;
import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.config.ConfigLoader;
import com.gmail.nossr50.datatypes.database.UpgradeType; import com.gmail.nossr50.datatypes.database.UpgradeType;
import com.gmail.nossr50.mcMMO;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
@ -40,7 +41,7 @@ public class UpgradeManager extends ConfigLoader {
return; return;
} }
plugin.debug("Saving upgrade status for type " + type.toString() + "..."); mcMMO.p.debug("Saving upgrade status for type " + type.toString() + "...");
config.set("Upgrades_Finished." + type.toString(), true); config.set("Upgrades_Finished." + type.toString(), true);
@ -60,6 +61,6 @@ public class UpgradeManager extends ConfigLoader {
} }
} }
plugin.debug("Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); mcMMO.p.debug("Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()])));
} }
} }