Greenhouses/src/main/java/world/bentobox/greenhouses/Greenhouses.java

1591 lines
78 KiB
Java
Raw Normal View History

2019-01-19 16:52:04 +01:00
package world.bentobox.greenhouses;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.PluginManager;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.greenhouses.greenhouse.BiomeRecipe;
import world.bentobox.greenhouses.greenhouse.Ecosystem;
import world.bentobox.greenhouses.greenhouse.Greenhouse;
import world.bentobox.greenhouses.greenhouse.Roof;
import world.bentobox.greenhouses.greenhouse.Walls;
import world.bentobox.greenhouses.listeners.GreenhouseEvents;
import world.bentobox.greenhouses.listeners.GreenhouseGuard;
import world.bentobox.greenhouses.listeners.JoinLeaveEvents;
import world.bentobox.greenhouses.ui.ControlPanel;
import world.bentobox.greenhouses.ui.GreenhouseCmd;
import world.bentobox.greenhouses.ui.Locale;
import world.bentobox.greenhouses.ui.admin.AdminCmd;
import world.bentobox.greenhouses.util.MetricsLite;
import world.bentobox.greenhouses.util.Util;
import world.bentobox.greenhouses.util.VaultHelper;
/**
* This plugin simulates greenhouses in Minecraft. It enables players to build biomes inside
* glass houses. Each biome is different and can spawn plants and animals. The recipe for each
* biome is determined by a configuration file.b
* @author tastybento
*/
public class Greenhouses extends Addon {
// Maximum size that the Minecraft inventory can be in items before going weird
private static final int MAXIMUM_INVENTORY_SIZE = 49;
// Players object
public PlayerCache players;
// Greenhouses
private HashSet<Greenhouse> greenhouses = new HashSet<Greenhouse>();
private HashMap<UUID, HashSet<Greenhouse>> playerhouses = new HashMap<UUID, HashSet<Greenhouse>>();
// Offline Messages
private HashMap<UUID, List<String>> messages = new HashMap<UUID, List<String>>();
private YamlConfiguration messageStore;
// Ecosystem object and random number generator
private Ecosystem eco = new Ecosystem(this);
// Tasks
private BukkitTask plantTask;
private BukkitTask mobTask;
private BukkitTask blockTask;
private BukkitTask ecoTask;
// Biomes
private List<BiomeRecipe> biomeRecipes = new ArrayList<BiomeRecipe>();
private ControlPanel biomeInv;
// Debug level (0 = none, 1 = important ones, 2 = level 2, 3 = level 3
private List<String> debug = new ArrayList<String>();
/**
* Loads all the biome recipes from the file biomes.yml.
*/
public void loadBiomeRecipes() {
biomeRecipes.clear();
YamlConfiguration biomes = loadYamlFile("biomes.yml");
ConfigurationSection biomeSection = biomes.getConfigurationSection("biomes");
if (biomeSection == null) {
getLogger().severe("biomes.yml file is missing, empty or corrupted. Delete and reload plugin again!");
return;
}
// Loop through all the entries
for (String type: biomeSection.getValues(false).keySet()) {
logger(1,"Loading "+type + " biome recipe:");
try {
ConfigurationSection biomeRecipe = biomeSection.getConfigurationSection(type);
Biome thisBiome = null;
if (biomeRecipe.contains("biome")) {
// Try and get the biome via the biome setting
thisBiome = Biome.valueOf(biomeRecipe.getString("biome").toUpperCase());
} else {
// Old style, where type was the biome name
thisBiome = Biome.valueOf(type);
}
if (thisBiome != null) {
int priority = biomeRecipe.getInt("priority", 0);
BiomeRecipe b = new BiomeRecipe(this, thisBiome,priority);
// Set the name
b.setName(type);
// Set the permission
b.setPermission(biomeRecipe.getString("permission",""));
// Set the icon
b.setIcon(Material.valueOf(biomeRecipe.getString("icon", "SAPLING")));
b.setFriendlyName(ChatColor.translateAlternateColorCodes('&', biomeRecipe.getString("friendlyname", "")));
// A value of zero on these means that there must be NO coverage, e.g., desert. If the value is not present, then the default is -1
b.setWatercoverage(biomeRecipe.getInt("watercoverage",-1));
b.setLavacoverage(biomeRecipe.getInt("lavacoverage",-1));
b.setIcecoverage(biomeRecipe.getInt("icecoverage",-1));
b.setMobLimit(biomeRecipe.getInt("moblimit", 9));
// Set the needed blocks
String contents = biomeRecipe.getString("contents", "");
logger(3,"contents = '" + contents + "'");
if (!contents.isEmpty()) {
String[] split = contents.split(" ");
// Format is MATERIAL: Qty or MATERIAL: Type:Quantity
for (String s : split) {
// Split it again
String[] subSplit = s.split(":");
if (subSplit.length > 1) {
Material blockMaterial = Material.valueOf(subSplit[0]);
// TODO: Need to parse these inputs better. INTS and Strings
//logger(3,"subsplit = " + subSplit);
//logger(3,"subsplit length = " + subSplit.length);
int blockType = 0;
int blockQty = 0;
if (subSplit.length == 2) {
blockQty = Integer.valueOf(subSplit[1]);
blockType = -1; // anything okay
} else if (subSplit.length == 3) {
//logger(3,"subsplit[1] = " + subSplit[1]);
//logger(3,"subsplit[2] = " + subSplit[2]);
//logger(3,"subsplit[1] value = " + Integer.valueOf(subSplit[1]));
//logger(3,"subsplit[2] value = " + Integer.valueOf(subSplit[2]));
blockType = Integer.valueOf(subSplit[1]);
blockQty = Integer.valueOf(subSplit[2]);
}
b.addReqBlocks(blockMaterial, blockType, blockQty);
} else {
getLogger().warning("Block material " + s + " has no associated qty in biomes.yml " + type);
}
}
}
// Load plants
// # Plant Material: Probability in %:Block Material on what they grow:Plant Type(optional):Block Type(Optional)
ConfigurationSection temp = biomes.getConfigurationSection("biomes." + type + ".plants");
if (temp != null) {
HashMap<String,Object> plants = (HashMap<String,Object>)temp.getValues(false);
if (plants != null) {
for (String s: plants.keySet()) {
//logger(1, "Plant = " + s);
Material plantMaterial = null;
int plantType = 0;
if (s.contains(":")) {
String[] split = s.split(":");
if (split.length == 2) {
plantMaterial = Material.valueOf(split[0]);
plantType = Integer.valueOf(split[1]);
}
} else {
plantMaterial = Material.valueOf(s);
}
//logger(1, "Plant = " + plantMaterial);
String[] split = ((String)plants.get(s)).split(":");
//logger(1, "Split length = " + split.length);
int plantProbability = Integer.valueOf(split[0]);
Material plantGrowOn = Material.valueOf(split[1]);
if (split.length == 3) {
//logger(1, "Split legth is ==3");
plantType = Integer.valueOf(split[2]);
//logger(1, "plant type = " + plantType);
}
b.addPlants(plantMaterial, plantType, plantProbability, plantGrowOn);
}
}
}
// Load mobs!
// Mob EntityType: Probability:Spawn on Material
temp = biomes.getConfigurationSection("biomes." + type + ".mobs");
if (temp != null) {
HashMap<String,Object> mobs = (HashMap<String,Object>)temp.getValues(false);
if (mobs != null) {
for (String s: mobs.keySet()) {
EntityType mobType = EntityType.valueOf(s);
String[] split = ((String)mobs.get(s)).split(":");
int mobProbability = Integer.valueOf(split[0]);
Material mobSpawnOn = Material.valueOf(split[1]);
// TODO: Currently not used
int mobSpawnOnType = 0;
if (split.length == 3) {
mobSpawnOnType = Integer.valueOf(split[2]);
}
b.addMobs(mobType, mobProbability, mobSpawnOn);
}
}
}
// Load block conversions
String conversions = biomeSection.getString(type + ".conversions", "");
logger(3,"conversions = '" + conversions + "'");
if (!conversions.isEmpty()) {
String[] split = conversions.split(" ");
for (String s : split) {
// Split it again
String[] subSplit = s.split(":");
// After this is split, there must be 5 entries!
Material oldMaterial = null;
int oldType = 0;
Material newMaterial = null;
int newType = 0;
Material localMaterial = null;
int localType = 0;
int convChance;
oldMaterial = Material.valueOf(subSplit[0]);
oldType = Integer.valueOf(subSplit[1]);
convChance = Integer.valueOf(subSplit[2]);
newMaterial = Material.valueOf(subSplit[3]);
newType = Integer.valueOf(subSplit[4]);
if (subSplit.length == 7) {
localMaterial = Material.valueOf(subSplit[5]);
localType = Integer.valueOf(subSplit[6]);
}
b.addConvBlocks(oldMaterial, oldType, newMaterial, newType, convChance, localMaterial, localType);
}
}
// Add the recipe to the list
biomeRecipes.add(b);
}
} catch (Exception e) {
logger(1,"Problem loading biome recipe - skipping!");
String validBiomes = "";
for (Biome biome : Biome.values()) {
validBiomes = validBiomes + " " + biome.name();
}
logger(1,"Valid biomes are " + validBiomes);
e.printStackTrace();
}
// Check maximum number
if (biomeRecipes.size() == MAXIMUM_INVENTORY_SIZE) {
getLogger().warning("Cannot load any more biome recipies - limit is 49!");
break;
}
}
logger(1,"Loaded " + biomeRecipes.size() + " biome recipes.");
}
/**
* @return the biomeRecipes
*/
public List<BiomeRecipe> getBiomeRecipes() {
return biomeRecipes;
}
/**
* Loads the various settings from the config.yml file into the plugin
*/
public void loadPluginConfig() {
try {
getConfig();
} catch (final Exception e) {
e.printStackTrace();
}
// Get the localization strings
getLocale();
Locale.generalnotavailable = ChatColor.translateAlternateColorCodes('&', getLocale().getString("general.notavailable", "Greenhouses are not available in this world"));
Locale.generalgreenhouses = ChatColor.translateAlternateColorCodes('&', getLocale().getString("general.greenhouses", "Greenhouses"));
Locale.generalbiome = ChatColor.translateAlternateColorCodes('&', getLocale().getString("general.biome", "Biome"));
Locale.generalowner = ChatColor.translateAlternateColorCodes('&', getLocale().getString("general.owner", "Owner"));
Locale.helphelp = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.help", "help"));
Locale.helpmake = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.make", "Tries to make a greenhouse"));
Locale.helpremove = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.remove", "Removes a greenhouse that you are standing in if you are the owner"));
Locale.helpinfo = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.info", "Shows info on the greenhouse you and general info"));
Locale.helplist = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.list", "Lists all the greenhouse biomes that can be made"));
Locale.helpopengui = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.opengui", "Opens the Greenhouse GUI"));
Locale.helprecipe = ChatColor.translateAlternateColorCodes('&', getLocale().getString("help.recipe", "Tells you how to make greenhouse biome"));
Locale.listtitle = ChatColor.translateAlternateColorCodes('&', getLocale().getString("list.title", "[Greenhouse Biome Recipes]"));
Locale.listinfo = ChatColor.translateAlternateColorCodes('&', getLocale().getString("list.info", "Use /greenhouse recipe <number> to see details on how to make each greenhouse"));
Locale.errorunknownPlayer = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.unknownPlayer", "That player is unknown."));
Locale.errornoPermission = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.noPermission", "You don't have permission to use that command!"));
Locale.errorcommandNotReady = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.commandNotReady", "You can't use that command right now."));
Locale.errorofflinePlayer = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.offlinePlayer", "That player is offline or doesn't exist."));
Locale.errorunknownCommand = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.unknownCommand", "Unknown command."));
Locale.errormove = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.move", "Move to a greenhouse you own first."));
Locale.errornotowner = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.notowner", "You must be the owner of this greenhouse to do that."));
Locale.errorremoving = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.removing", "Removing greenhouse!"));
Locale.errornotyours = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.notyours", "This is not your greenhouse!"));
Locale.errornotinside = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.notinside", "You are not in a greenhouse!"));
Locale.errortooexpensive = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.tooexpensive", "You cannot afford [price]" ));
Locale.erroralreadyexists = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.alreadyexists", "Greenhouse already exists!"));
Locale.errornorecipe = ChatColor.translateAlternateColorCodes('&', getLocale().getString("error.norecipe", "This does not meet any greenhouse recipe!"));
Locale.messagesenter = ChatColor.translateAlternateColorCodes('&', getLocale().getString("messages.enter", "Entering [owner]'s [biome] greenhouse!"));
Locale.messagesleave = ChatColor.translateAlternateColorCodes('&', getLocale().getString("messages.leave", "Now leaving [owner]'s greenhouse."));
Locale.messagesyouarein = ChatColor.translateAlternateColorCodes('&', getLocale().getString("messages.youarein", "You are now in [owner]'s [biome] greenhouse!"));
Locale.messagesremoved = ChatColor.translateAlternateColorCodes('&', getLocale().getString("messages.removed", "This greenhouse is no more..."));
Locale.messagesremovedmessage = ChatColor.translateAlternateColorCodes('&', getLocale().getString("messages.removedmessage", "A [biome] greenhouse of yours is no more!"));
Locale.messagesecolost = ChatColor.translateAlternateColorCodes('&', getLocale().getString("messages.ecolost", "Your greenhouse at [location] lost its eco system and was removed."));
Locale.infotitle = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.title", "&A[Greenhouse Construction]"));
Locale.infoinstructions = getLocale().getStringList("info.instructions");
Locale.infoinfo = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.info", "[Greenhouse Info]"));
Locale.infonone = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.none", "None"));
Locale.infowelcome = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.welcome","&BWelcome! Click here for instructions"));
Locale.infonomore = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.nomore", "&4You cannot build any more greenhouses!"));
Locale.infoonemore = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.onemore","&6You can build one more greenhouse."));
Locale.infoyoucanbuild = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.youcanbuild","&AYou can builds up to [number] more greenhouses!"));
Locale.infounlimited = ChatColor.translateAlternateColorCodes('&', getLocale().getString("info.unlimited","&AYou can build an unlimited number of greenhouses!"));
Locale.recipehint = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.hint", "Use /greenhouse list to see a list of recipe numbers!"));
Locale.recipewrongnumber = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.wrongnumber", "Recipe number must be between 1 and [size]"));
Locale.recipetitle = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.title", "[[biome] recipe]"));
Locale.recipenowater = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.nowater", "No water allowed."));
Locale.recipenoice = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.noice", "No ice allowed."));
Locale.recipenolava = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.nolava", "No lava allowed."));
Locale.recipewatermustbe = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.watermustbe", "Water > [coverage]% of floor area."));
Locale.recipeicemustbe = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.icemustbe", "Ice blocks > [coverage]% of floor area."));
Locale.recipelavamustbe = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.lavamustbe", "Lava > [coverage]% of floor area."));
Locale.recipeminimumblockstitle = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.minimumblockstitle", "[Minimum blocks required]"));
Locale.lineColor = ChatColor.translateAlternateColorCodes('&', ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.linecolor", "&f")));
Locale.recipenootherblocks = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.nootherblocks", "No other blocks required."));
Locale.recipemissing = ChatColor.translateAlternateColorCodes('&', getLocale().getString("recipe.missing", "Greenhouse is missing"));
Locale.eventbroke = ChatColor.translateAlternateColorCodes('&', getLocale().getString("event.broke", "You broke this greenhouse! Reverting biome to [biome]!"));
Locale.eventfix = ChatColor.translateAlternateColorCodes('&', getLocale().getString("event.fix", "Fix the greenhouse and then make it again."));
Locale.eventcannotplace = ChatColor.translateAlternateColorCodes('&', getLocale().getString("event.cannotplace", "Blocks cannot be placed above a greenhouse!"));
Locale.eventpistonerror = ChatColor.translateAlternateColorCodes('&', getLocale().getString("event.pistonerror", "Pistons cannot push blocks over a greenhouse!"));
Locale.createnoroof = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.noroof", "There seems to be no roof!"));
Locale.createmissingwall = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.missingwall", "A wall is missing!"));
Locale.createnothingabove = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.nothingabove", "There can be no blocks above the greenhouse!"));
Locale.createholeinroof = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.holeinroof", "There is a hole in the roof or it is not flat!"));
Locale.createholeinwall = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.holeinwall", "There is a hole in the wall or they are not the same height all the way around!"));
Locale.createhoppererror = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.hoppererror", "Only one hopper is allowed in the walls or roof."));
Locale.createdoorerror = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.doorerror", "You cannot have more than 4 doors in the greenhouse!"));
Locale.createsuccess = ChatColor.translateAlternateColorCodes('&', getLocale().getString("create.success", "You successfully made a [biome] biome greenhouse!"));
Locale.adminHelpreload = ChatColor.translateAlternateColorCodes('&', getLocale().getString("adminHelp.reload", "reload configuration from file."));
Locale.adminHelpinfo = ChatColor.translateAlternateColorCodes('&', getLocale().getString("adminHelp.info", "provides info on the greenhouse you are in"));
Locale.reloadconfigReloaded = ChatColor.translateAlternateColorCodes('&', getLocale().getString("reload.configReloaded", "Configuration reloaded from file."));
Locale.admininfoerror = ChatColor.translateAlternateColorCodes('&', getLocale().getString("admininfo.error", "Greenhouse info only available in-game"));
Locale.admininfoerror2 = ChatColor.translateAlternateColorCodes('&', getLocale().getString("admininfo.error2", "Put yourself in a greenhouse to see info."));
Locale.admininfoflags = ChatColor.translateAlternateColorCodes('&', getLocale().getString("admininfo.flags", "[Greenhouse Flags]"));
Locale.newsheadline = ChatColor.translateAlternateColorCodes('&', getLocale().getString("news.headline", "[Greenhouse News]"));
Locale.controlpaneltitle = ChatColor.translateAlternateColorCodes('&', getLocale().getString("controlpanel.title", "&AGreenhouses"));
Locale.limitslimitedto = ChatColor.translateAlternateColorCodes('&', getLocale().getString("limits.limitedto","Permissions limit you to [limit] greenhouses so [number] were removed."));
Locale.limitsnoneallowed = ChatColor.translateAlternateColorCodes('&', getLocale().getString("limits.noneallowed", "Permissions do not allow you any greenhouses so [number] were removed."));
// Assign settings
this.debug = getConfig().getStringList("greenhouses.debug");
Settings.allowFlowIn = getConfig().getBoolean("greenhouses.allowflowin", false);
Settings.allowFlowOut = getConfig().getBoolean("greenhouses.allowflowout", false);
// Other settings
Settings.worldName = getConfig().getStringList("greenhouses.worldName");
if (Settings.worldName.isEmpty()) {
Settings.worldName.add("world");
}
logger(1,"Greenhouse worlds are: " + Settings.worldName );
Settings.snowChanceGlobal = getConfig().getDouble("greenhouses.snowchance", 0.5D);
Settings.snowDensity = getConfig().getDouble("greenhouses.snowdensity", 0.1D);
Settings.snowSpeed = getConfig().getLong("greenhouses.snowspeed", 30L);
Settings.iceInfluence = getConfig().getInt("greenhouses.iceinfluence", 125);
Settings.ecoTick = getConfig().getInt("greenhouses.ecotick", 30);
Settings.mobTick = getConfig().getInt("greenhouses.mobtick", 20);
Settings.plantTick = getConfig().getInt("greenhouses.planttick", 5);
Settings.blockTick = getConfig().getInt("greenhouses.blocktick", 10);
logger(3,"Snowchance " + Settings.snowChanceGlobal);
logger(3,"Snowdensity " + Settings.snowDensity);
logger(3,"Snowspeed " + Settings.snowSpeed);
// Max greenhouse settings
Settings.maxGreenhouses = getConfig().getInt("greenhouses.maxgreenhouses",-1);
Settings.deleteExtras = getConfig().getBoolean("greenhouses.deleteextras", false);
}
/*
* (non-Javadoc)
*
* @see org.bukkit.plugin.java.JavaPlugin#onDisable()
*/
@Override
public void onDisable() {
saveGreenhouses();
// Reset biomes back
/*
for (Greenhouse g: plugin.getGreenhouses()) {
try {
g.endBiome();
} catch (Exception e) {}
}*/
try {
// Remove players from memory
greenhouses.clear();
playerhouses.clear();
players.removeAllPlayers();
saveMessages();
} catch (final Exception e) {
addon.getLogger().severe("Something went wrong saving files!");
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*
* @see org.bukkit.plugin.java.JavaPlugin#onEnable()
*/
@Override
public void onEnable() {
// instance of this plugin
addon = this;
saveDefaultConfig();
saveDefaultLocale();
// Metrics
new MetricsLite(this);
// Economy
if (!VaultHelper.setupEconomy()) {
getLogger().severe("Could not set up economy!");
}
// Set up player's cache
players = new PlayerCache(this);
loadPluginConfig();
loadBiomeRecipes();
biomeInv = new ControlPanel(this);
// Set up commands for this plugin
getCommand("greenhouse").setExecutor(new GreenhouseCmd(this,players));
getCommand("gadmin").setExecutor(new AdminCmd(this,players));
// Register events that this plugin uses
registerEvents();
// Load messages
loadMessages();
// Kick off a few tasks on the next tick
getServer().getScheduler().runTask(addon, new Runnable() {
@Override
public void run() {
final PluginManager manager = Bukkit.getServer().getPluginManager();
if (manager.isPluginEnabled("Vault")) {
Greenhouses.getAddon().logger(1,"Trying to use Vault for permissions...");
if (!VaultHelper.setupPermissions()) {
getLogger().severe("Cannot link with Vault for permissions! Disabling plugin!");
manager.disablePlugin(Greenhouses.getAddon());
} else {
logger(1,"Success!");
};
}
// Load greenhouses
loadGreenhouses();
}
});
ecoTick();
}
public void ecoTick() {
// Cancel any old schedulers
if (plantTask != null)
plantTask.cancel();
if (blockTask != null)
blockTask.cancel();
if (mobTask != null)
mobTask.cancel();
if (ecoTask != null)
ecoTask.cancel();
// Kick off flower growing
long plantTick = Settings.plantTick * 60 * 20; // In minutes
if (plantTick > 0) {
logger(1,"Kicking off flower growing scheduler every " + Settings.plantTick + " minutes");
plantTask = getServer().getScheduler().runTaskTimer(addon, new Runnable() {
@Override
public void run() {
for (Greenhouse g : getGreenhouses()) {
logger(3,"Servicing greenhouse biome : " + g.getBiome().toString());
//checkEco();
try {
g.growFlowers();
} catch (Exception e) {
getLogger().severe("Problem found with greenhouse during growing flowers. Skipping...");
if (addon.getDebug().contains("3")) {
e.printStackTrace();
}
}
//g.populateGreenhouse();
}
}
}, 80L, plantTick);
} else {
logger(1,"Flower growth disabled.");
}
// Kick off flower growing
long blockTick = Settings.blockTick * 60 * 20; // In minutes
if (blockTick > 0) {
logger(1,"Kicking off block conversion scheduler every " + Settings.blockTick + " minutes");
blockTask = getServer().getScheduler().runTaskTimer(addon, new Runnable() {
@Override
public void run() {
for (Greenhouse g : getGreenhouses()) {
try {
g.convertBlocks();
} catch (Exception e) {
getLogger().severe("Problem found with greenhouse during block conversion. Skipping...");
getLogger().severe("[Greenhouse info]");
getLogger().severe("Owner: " + g.getOwner());
getLogger().severe("Location " + g.getPos1().toString() + " to " + g.getPos2().toString());
e.printStackTrace();
}
logger(3,"Servicing greenhouse biome : " + g.getBiome().toString());
}
}
}, 60L, blockTick);
} else {
logger(1,"Block conversion disabled.");
}
// Kick off g/h verification
long ecoTick = Settings.plantTick * 60 * 20; // In minutes
if (ecoTick > 0) {
logger(1,"Kicking off greenhouse verify scheduler every " + Settings.ecoTick + " minutes");
ecoTask = getServer().getScheduler().runTaskTimer(addon, new Runnable() {
@Override
public void run() {
try {
checkEco();
} catch (Exception e) {
getLogger().severe("Problem found with greenhouse during eco check. Skipping...");
if (addon.getDebug().contains("3")) {
e.printStackTrace();
}
}
//}
}
}, ecoTick, ecoTick);
} else {
logger(1,"Greenhouse verification disabled.");
}
// Kick off mob population
long mobTick = Settings.mobTick * 60 * 20; // In minutes
if (mobTick > 0) {
logger(1,"Kicking off mob populator scheduler every " + Settings.plantTick + " minutes");
mobTask = getServer().getScheduler().runTaskTimer(addon, new Runnable() {
@Override
public void run() {
for (Greenhouse g : getGreenhouses()) {
g.populateGreenhouse();
}
}
}, 120L, mobTick);
} else {
logger(1,"Mob disabled.");
}
}
/**
* Returns a pseudo-random number between min and max, inclusive.
* The difference between min and max can be at most
* <code>Integer.MAX_VALUE - 1</code>.
*
* @param min Minimum value
* @param max Maximum value. Must be greater than min.
* @return Integer between min and max, inclusive.
* @see java.util.Random#nextInt(int)
*/
public static int randInt(int min, int max) {
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
//Bukkit.logger(1,"Random number = " + randomNum);
return randomNum;
}
/**
* Load all known greenhouses
*/
protected void loadGreenhouses() {
// Load all known greenhouses
// Clear them first
greenhouses.clear();
// Check for updated file
greenhouseFile = new File(this.getDataFolder(),"greenhouses.yml");
greenhouseConfig = new YamlConfiguration();
File playersFolder = new File(this.getDataFolder(),"players");
// See if the new file exists or not, if not make it
if (!greenhouseFile.exists() && !playersFolder.exists()) {
// Brand new install
logger(1,"Creating new greenhouse.yml file");
greenhouseConfig.createSection("greenhouses");
try {
greenhouseConfig.save(greenhouseFile);
} catch (IOException e) {
logger(1,"Could not save greenhouse.yml file!");
// Could not save
e.printStackTrace();
}
} else if (!greenhouseFile.exists() && playersFolder.exists()) {
logger(1,"Converting from old greenhouse storage to new greenhouse storage");
ConfigurationSection greenhouseSection = greenhouseConfig.createSection("greenhouses");
int greenhouseNum = 0;
// Load all the players
for (final File f : playersFolder.listFiles()) {
// Need to remove the .yml suffix
String fileName = f.getName();
if (fileName.endsWith(".yml")) {
try {
logger(1,"Converting " + fileName.substring(0, fileName.length() - 4));
final UUID playerUUID = UUID.fromString(fileName.substring(0, fileName.length() - 4));
if (playerUUID == null) {
getLogger().warning("Player file contains erroneous UUID data.");
getLogger().warning("Looking at " + fileName.substring(0, fileName.length() - 4));
}
//new Players(this, playerUUID);
YamlConfiguration playerInfo = new YamlConfiguration();
playerInfo.load(f);
// Copy over greenhouses
ConfigurationSection myHouses = playerInfo.getConfigurationSection("greenhouses");
if (myHouses != null) {
// Get a list of all the greenhouses
for (String key : myHouses.getKeys(false)) {
try {
// Copy over the info
greenhouseSection.set(greenhouseNum + ".owner", playerUUID.toString());
greenhouseSection.set(greenhouseNum + ".playerName", playerInfo.getString("playerName",""));
greenhouseSection.set(greenhouseNum + ".pos-one", playerInfo.getString("greenhouses." + key + ".pos-one",""));
greenhouseSection.set(greenhouseNum + ".pos-two", playerInfo.getString("greenhouses." + key + ".pos-two",""));
greenhouseSection.set(greenhouseNum + ".originalBiome", playerInfo.getString("greenhouses." + key + ".originalBiome", "PLAINS"));
greenhouseSection.set(greenhouseNum + ".greenhouseBiome", playerInfo.getString("greenhouses." + key + ".greenhouseBiome", "PLAINS"));
greenhouseSection.set(greenhouseNum + ".roofHopperLocation", playerInfo.getString("greenhouses." + key + ".roofHopperLocation"));
greenhouseSection.set(greenhouseNum + ".farewellMessage", playerInfo.getString("greenhouses." + key + ".flags.farewellMessage",""));
greenhouseSection.set(greenhouseNum + ".enterMessage", playerInfo.getString("greenhouses." + key + ".flags.enterMessage",""));
} catch (Exception e) {
addon.getLogger().severe("Problem copying player files");
e.printStackTrace();
}
greenhouseNum++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Save the greenhouse file
try {
greenhouseConfig.save(greenhouseFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (greenhouseFile.exists()){
// Load greenhouses from new file
try {
greenhouseConfig.load(greenhouseFile);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (greenhouseConfig.isConfigurationSection("greenhouses")) {
ConfigurationSection myHouses = greenhouseConfig.getConfigurationSection("greenhouses");
if (myHouses != null) {
// Get a list of all the greenhouses
for (String key : myHouses.getKeys(false)) {
logger(3,"Loading greenhouse #" + key);
try {
String playerName = myHouses.getString(key + ".playerName", "");
// Load all the values
Location pos1 = getLocationString(myHouses.getString(key + ".pos-one"));
Location pos2 = getLocationString(myHouses.getString(key + ".pos-two"));
UUID owner = UUID.fromString(myHouses.getString(key + ".owner"));
logger(3,"File pos1: " + pos1.toString());
logger(3,"File pos1: " + pos2.toString());
if (pos1 != null && pos2 !=null) {
// Check if this greenhouse already exists
if (!checkGreenhouseIntersection(pos1, pos2)) {
Greenhouse g = new Greenhouse(this, pos1, pos2, owner);
logger(3,"Greenhouse pos1: " + g.getPos1().toString());
logger(3,"Greenhouse pos2: " + g.getPos2().toString());
// Set owner name
g.setPlayerName(playerName);
logger(3,"Owner is " + playerName);
// Set biome
String oBiome = myHouses.getString(key + ".originalBiome", "PLAINS");
// Do some conversions
Biome originalBiome = convertBiome(oBiome);
g.setOriginalBiome(originalBiome);
logger(3,"original biome = " + oBiome + " converted = " + originalBiome);
String gBiome = myHouses.getString(key + ".greenhouseBiome", "PLAINS");
Biome greenhouseBiome = convertBiome(gBiome);
if (greenhouseBiome == null) {
greenhouseBiome = Biome.PLAINS;
}
logger(3,"greenhouse biome = " + gBiome + " converted = " + greenhouseBiome);
String recipeName = myHouses.getString(key + ".greenhouseRecipe", "");
boolean success = false;
// Check to see if this biome has a recipe
// Try by name first
for (BiomeRecipe br : getBiomeRecipes()) {
if (br.getName().equalsIgnoreCase(recipeName)) {
success = true;
g.setBiomeRecipe(br);
break;
}
}
// Fall back to biome
if (!success) {
for (BiomeRecipe br : getBiomeRecipes()) {
if (br.getBiome().equals(greenhouseBiome)) {
success = true;
g.setBiomeRecipe(br);
break;
}
}
}
// Check to see if it was set properly
if (!success) {
getLogger().warning("*****************************************");
getLogger().warning("WARNING: No known recipe for biome " + greenhouseBiome.toString());
getLogger().warning("[Greenhouse info]");
getLogger().warning("Owner: " + playerName + " UUID:" + g.getOwner());
getLogger().warning("Location :" + g.getPos1().getWorld().getName() + " " + g.getPos1().getBlockX() + "," + g.getPos1().getBlockZ());
getLogger().warning("Greenhouse will be removed next eco-tick!");
getLogger().warning("*****************************************");
}
// Start the biome
g.startBiome(false);
Location hopperLoc = getLocationString(myHouses.getString(key + ".roofHopperLocation"));
if (hopperLoc != null) {
g.setRoofHopperLocation(hopperLoc);
}
// Load farewell and hello messages
g.setEnterMessage(myHouses.getString(key +".enterMessage",(Locale.messagesenter.replace("[owner]", playerName )).replace("[biome]", Util.prettifyText(gBiome))));
g.setFarewellMessage(myHouses.getString(key +".farewellMessage",Locale.messagesleave.replace("[owner]", playerName)));
// Add to the cache
addGHToPlayer(owner, g);
}
} else {
getLogger().severe("Problem loading greenhouse with locations " + myHouses.getString(key + ".pos-one") + " and " + myHouses.getString(key + ".pos-two") + " skipping.");
getLogger().severe("Has this world been deleted?");
}
} catch (Exception e) {
getLogger().severe("Problem loading greenhouse file");
e.printStackTrace();
}
}
logger(3,"Loaded " + addon.getGreenhouses().size() + " greenhouses.");
}
}
logger(1,"Loaded " + getGreenhouses().size() + " greenhouses.");
}
public void addGHToPlayer(UUID owner, Greenhouse g) {
HashSet<Greenhouse> storedhouses = null;
if (playerhouses.get(owner) != null) {
storedhouses = playerhouses.get(owner);
playerhouses.remove(owner);
} else {
storedhouses = new HashSet<Greenhouse>();
}
storedhouses.add(g);
greenhouses.add(g);
playerhouses.put(owner, storedhouses);
}
public void removeGHFromPlayer(UUID owner, Greenhouse g) {
HashSet<Greenhouse> storedhouses = null;
if (playerhouses.get(owner) != null) {
storedhouses = playerhouses.get(owner);
playerhouses.remove(owner);
} else {
storedhouses = new HashSet<Greenhouse>();
}
storedhouses.remove(g);
greenhouses.remove(g);
playerhouses.put(owner, storedhouses);
}
/**
* Converts biomes to known biomes if required
* @param oBiome
* @return
*/
private Biome convertBiome(String oBiome) {
if (addon.getServer().getVersion().contains("(MC: 1.8") || addon.getServer().getVersion().contains("(MC: 1.7")) {
try {
return Biome.valueOf(oBiome);
} catch (Exception e) {
getLogger().severe("Could not identify Biome " + oBiome + " setting to PLAINS - may destroy greenhouse");
return Biome.PLAINS;
}
} else {
// May need to convert Biome
if (oBiome.equalsIgnoreCase("COLD_TAIGA")) {
getLogger().warning("Converting Cold Taiga biome to 1.9 Taiga Cold");
return Biome.TAIGA_COLD;
}
if (oBiome.equalsIgnoreCase("FLOWER_FOREST")) {
getLogger().warning("Converting Flower Forest biome to 1.9 Forest");
return Biome.FOREST;
}
if (oBiome.equalsIgnoreCase("BEACH")) {
getLogger().warning("Converting Beach biome to 1.9 Beaches");
return Biome.BEACHES;
}
String test = oBiome;
while (!test.isEmpty()) {
for (Biome biome: Biome.values()) {
if (biome.name().contains(test)) {
if (!biome.name().equals(test)) {
getLogger().warning("Converting " + oBiome + " biome to 1.9 " + biome.name() + " - may destroy greenhouse.");
}
return biome;
}
}
test = test.substring(0, test.length() - 1);
}
}
getLogger().severe("Could not identify Biome " + oBiome + " setting to PLAINS - may destroy greenhouse");
return Biome.PLAINS;
}
/**
* Registers events
*/
public void registerEvents() {
final PluginManager manager = getServer().getPluginManager();
// Greenhouse Protection events
manager.registerEvents(new GreenhouseGuard(this), this);
// Listen to greenhouse change events
manager.registerEvents(new GreenhouseEvents(this), this);
// Events for when a player joins or leaves the server
manager.registerEvents(new JoinLeaveEvents(this, players), this);
// Biome CP
manager.registerEvents(biomeInv, this);
// Weather event
manager.registerEvents(eco, this);
}
// Localization
/**
* Saves the locale.yml file if it does not exist
*/
public void saveDefaultLocale() {
if (localeFile == null) {
localeFile = new File(getDataFolder(), "locale.yml");
}
if (!localeFile.exists()) {
saveResource("locale.yml", false);
}
}
/**
* Reloads the locale file
*/
public void reloadLocale() {
if (localeFile == null) {
saveDefaultLocale();
}
locale = YamlConfiguration.loadConfiguration(localeFile);
}
/**
* @return locale FileConfiguration object
*/
public FileConfiguration getLocale() {
if (locale == null) {
reloadLocale();
}
return locale;
}
/*
public void saveLocale() {
if (locale == null || localeFile == null) {
return;
}
try {
getLocale().save(localeFile);
} catch (IOException ex) {
getLogger().severe("Could not save config to " + localeFile);
}
}
*/
/**
* Sets a message for the player to receive next time they login
* @param player
* @param message
* @return true if player is offline, false if online
*/
public boolean setMessage(UUID playerUUID, String message) {
logger(3,"received message - " + message);
Player player = getServer().getPlayer(playerUUID);
// Check if player is online
if (player != null) {
if (player.isOnline()) {
//player.sendMessage(message);
return false;
}
}
// Player is offline so store the message
List<String> playerMessages = messages.get(playerUUID);
if (playerMessages != null) {
playerMessages.add(message);
} else {
playerMessages = new ArrayList<String>(Arrays.asList(message));
}
messages.put(playerUUID, playerMessages);
return true;
}
public List<String> getMessages(UUID playerUUID) {
List<String> playerMessages = messages.get(playerUUID);
if (playerMessages != null) {
// Remove the messages
messages.remove(playerUUID);
} else {
// No messages
playerMessages = new ArrayList<String>();
}
return playerMessages;
}
public boolean saveMessages() {
logger(1,"Saving offline messages...");
try {
// Convert to a serialized string
final HashMap<String,Object> offlineMessages = new HashMap<String,Object>();
for (UUID p : messages.keySet()) {
offlineMessages.put(p.toString(),messages.get(p));
}
// Convert to YAML
messageStore.set("messages", offlineMessages);
saveYamlFile(messageStore, "messages.yml");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean loadMessages() {
logger(1,"Loading offline messages...");
try {
messageStore = loadYamlFile("messages.yml");
if (messageStore.getConfigurationSection("messages") == null) {
messageStore.createSection("messages"); // This is only used to create
}
HashMap<String,Object> temp = (HashMap<String, Object>) messageStore.getConfigurationSection("messages").getValues(true);
for (String s : temp.keySet()) {
List<String> messageList = messageStore.getStringList("messages." + s);
if (!messageList.isEmpty()) {
messages.put(UUID.fromString(s), messageList);
}
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* @return the greenhouses
*/
public HashSet<Greenhouse> getGreenhouses() {
return greenhouses;
}
/**
*
* @param uuid
* @return Cached player greenhouses
*/
/*
public HashSet<Greenhouse> getPlayerGHouse(UUID uuid) {
if (playerhouses.containsKey(uuid)) {
return playerhouses.get(uuid);
}
return null;
}
*/
/**
* @param greenhouses the greenhouses to set
*/
public void setGreenhouses(HashSet<Greenhouse> greenhouses) {
this.greenhouses = greenhouses;
}
/**
* @return the playerhouses
*/
public HashMap<UUID, HashSet<Greenhouse>> getPlayerhouses() {
return playerhouses;
}
/**
* Clears the greenhouses list
*/
public void clearGreenhouses() {
this.greenhouses.clear();
}
/**
* Checks if a greenhouse defined by the corner points pos1 and pos2 overlaps any known greenhouses
* @param pos1
* @param pos2
* @return
*/
public boolean checkGreenhouseIntersection(Location pos1, Location pos2) {
// Create a 2D rectangle of this
Rectangle2D.Double rect = new Rectangle2D.Double();
rect.setFrameFromDiagonal(pos1.getX(), pos1.getZ(), pos2.getX(), pos2.getZ());
Rectangle2D.Double testRect = new Rectangle2D.Double();
// Create a set of rectangles of current greenhouses
for (Greenhouse d: greenhouses) {
testRect.setFrameFromDiagonal(d.getPos1().getX(), d.getPos1().getZ(),d.getPos2().getX(),d.getPos2().getZ());
if (rect.intersects(testRect)) {
return true;
}
}
return false;
}
/**
* Checks if a location is inside a greenhouse (3D space)
* @param location
* @return Greenhouse or null if none
*/
public Greenhouse getInGreenhouse(Location location) {
for (Greenhouse g : greenhouses) {
//logger(3,"greenhouse check");
if (g.insideGreenhouse(location)) {
return g;
}
}
// This location is not in a greenhouse
return null;
}
/**
* Checks if the location is on the greenhouse
* @param location
* @return the greenhouse that this is above
*/
public Greenhouse aboveAGreenhouse(Location location) {
for (Greenhouse g : greenhouses) {
//logger(3,"greenhouse check");
if (g.aboveGreenhouse(location)) {
return g;
}
}
// This location is above in a greenhouse
return null;
}
/**
* Removes the greenhouse from the world and resets biomes
* @param g
*/
public void removeGreenhouse(Greenhouse g) {
//players.get(g.getOwner());
// Remove the greenhouse
greenhouses.remove(g);
// Remove the greenhouse from the owner's count (only does anything if they are online)
players.decGreenhouseCount(g.getOwner());
// Stop any eco action
eco.remove(g);
logger(3,"Returning biome to original state: " + g.getOriginalBiome().toString());
//g.setBiome(g.getOriginalBiome()); // just in case
if (g.getOriginalBiome().equals(Biome.HELL) || g.getOriginalBiome().equals(Biome.DESERT)
|| g.getOriginalBiome().equals(Biome.DESERT_HILLS)) {
// Remove any water
for (int y = g.getPos1().getBlockY(); y< g.getPos2().getBlockY();y++) {
for (int x = g.getPos1().getBlockX();x<=g.getPos2().getBlockX();x++) {
for (int z = g.getPos1().getBlockZ();z<=g.getPos2().getBlockZ();z++) {
Block b = g.getPos1().getWorld().getBlockAt(x, y, z);
if (b.getType().equals(Material.WATER) || b.getType().equals(Material.STATIONARY_WATER)
|| b.getType().equals(Material.ICE) || b.getType().equals(Material.PACKED_ICE)
|| b.getType().equals(Material.SNOW) || b.getType().equals(Material.SNOW_BLOCK)) {
// Evaporate it
b.setType(Material.AIR);
//ParticleEffects.SMOKE_LARGE.send(Bukkit.getOnlinePlayers(),b.getLocation(),0D,0D,0D,1F,5,20);
b.getWorld().spawnParticle(Particle.SMOKE_LARGE, b.getLocation(), 5);
//ParticleEffect.SMOKE_LARGE.display(0F,0F,0F, 0.1F, 5, b.getLocation(), 30D);
}
}
}
}
}
g.endBiome();
boolean ownerOnline = false;
if (!ownerOnline) {
setMessage(g.getOwner(), Locale.messagesremovedmessage.replace("[biome]", Util.prettifyText(g.getBiome().toString())) + " [" + g.getPos1().getBlockX() + "," + g.getPos1().getBlockZ() + "]");
}
/*
// Set the biome
for (int y = g.getPos1().getBlockY(); y< g.getPos2().getBlockY();y++) {
for (int x = g.getPos1().getBlockX()+1;x<g.getPos2().getBlockX();x++) {
for (int z = g.getPos1().getBlockZ()+1;z<g.getPos2().getBlockZ();z++) {
g.getPos1().getWorld().getBlockAt(x, y, z).setBiome(g.getOriginalBiome());
}
}
}
int minx = Math.min(g.getPos1().getChunk().getX(), g.getPos2().getChunk().getX());
int maxx = Math.max(g.getPos1().getChunk().getX(), g.getPos2().getChunk().getX());
int minz = Math.min(g.getPos1().getChunk().getZ(), g.getPos2().getChunk().getZ());
int maxz = Math.max(g.getPos1().getChunk().getZ(), g.getPos2().getChunk().getZ());
for (int x = minx; x < maxx + 1; x++) {
for (int z = minz; z < maxz+1;z++) {
world.refreshChunk(x,z);
}
}
*/
}
/**
* Checks that each greenhouse is still viable
*/
public void checkEco() {
// Run through each greenhouse
logger(3,"started eco check");
// Check all the greenhouses to see if they still meet the g/h recipe
List<Greenhouse> onesToRemove = new ArrayList<Greenhouse>();
for (Greenhouse g : getGreenhouses()) {
logger(3,"Testing greenhouse owned by " + g.getOwner().toString());
if (!g.checkEco()) {
// The greenhouse failed an eco check - remove it
onesToRemove.add(g);
}
}
for (Greenhouse gg : onesToRemove) {
// Check if player is online
Player owner = addon.getServer().getPlayer(gg.getOwner());
if (owner == null) {
// TODO messages.ecolost
setMessage(gg.getOwner(), Locale.messagesecolost.replace("[location]", Greenhouses.getStringLocation(gg.getPos1())));
} else {
owner.sendMessage(ChatColor.RED + Locale.messagesecolost.replace("[location]", Greenhouses.getStringLocation(gg.getPos1())));
}
logger(1,"Greenhouse at " + Greenhouses.getStringLocation(gg.getPos1()) + " lost its eco system and was removed.");
logger(1,"Greenhouse biome was " + Util.prettifyText(gg.getBiome().toString()) + " - reverted to " + Util.prettifyText(gg.getOriginalBiome().toString()));
//UUID ownerUUID = gg.getOwner();
removeGreenhouse(gg);
removeGHFromPlayer(owner.getUniqueId(), gg);
//players.save(ownerUUID);
}
saveGreenhouses();
}
public Inventory getRecipeInv(Player player) {
return biomeInv.getPanel(player);
}
/**
* Checks that a greenhouse meets specs and makes it
* @param player
* @return the Greenhouse object
*/
public Greenhouse tryToMakeGreenhouse(final Player player) {
return tryToMakeGreenhouse(player, null);
}
/**
* Checks that a greenhouse meets specs and makes it
* If type is stated then only this specific type will be checked
* @param player
* @param greenhouseRecipe
* @return
*/
@SuppressWarnings("deprecation")
public Greenhouse tryToMakeGreenhouse(final Player player, BiomeRecipe greenhouseRecipe) {
if (greenhouseRecipe != null) {
// Do an immediate permissions check of the biome recipe if the type is declared
if (!greenhouseRecipe.getPermission().isEmpty()) {
if (!VaultHelper.checkPerm(player, greenhouseRecipe.getPermission())) {
player.sendMessage(ChatColor.RED + Locale.errornoPermission);
logger(2,"no permssions to use this biome");
return null;
}
}
String name = greenhouseRecipe.getFriendlyName();
if (name.isEmpty()) {
name = Util.prettifyText(greenhouseRecipe.getBiome().name()) + " biome";
}
player.sendMessage(ChatColor.GOLD + "Trying to make a " + name + " greenhouse...");
}
// Proceed to check the greenhouse
final Location location = player.getLocation().add(new Vector(0,1,0));
logger(3,"Player location is " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
final Biome originalBiome = location.getBlock().getBiome();
final World world = location.getWorld();
// we have the height above this location where a roof block is
// Check the sides
// Now look along the roof until we find the dimensions of the roof
Roof roof = new Roof(this, location);
if (!roof.isRoofFound()) {
player.sendMessage(ChatColor.RED + Locale.createnoroof);
logger(3,"Roof not found with roof check");
return null;
}
// Check that the player is under the roof
if (!(player.getLocation().getBlockX() > roof.getMinX() && player.getLocation().getBlockX() <= roof.getMaxX()
&& player.getLocation().getBlockZ() > roof.getMinZ() && player.getLocation().getBlockZ() <= roof.getMaxZ())) {
logger(3,"Player does not appear to be inside the greenhouse");
logger(3,"Player location " + player.getLocation());
logger(3,"Roof minx = " + roof.getMinX() + " maxx = " + roof.getMaxX());
logger(3,"Roof minz = " + roof.getMinZ() + " maxz = " + roof.getMaxZ());
player.sendMessage(ChatColor.RED + Locale.errornotinside);
return null;
}
// Now see if the walls match the roof - they may not
Walls walls = new Walls(this, player, roof);
// Roof is never smaller than walls, but walls can be smaller than the roof
int maxX = walls.getMaxX();
int minX = walls.getMinX();
int maxZ = walls.getMaxZ();
int minZ = walls.getMinZ();
logger(3,"minx = " + minX);
logger(3,"maxx = " + maxX);
logger(3,"minz = " + minZ);
logger(3,"maxz = " + maxZ);
// Now check again to see if the floor really is the floor and the walls follow the rules
// Counts
int wallDoors = 0;
// Hoppers
int ghHopper = 0;
// Air
boolean airHoles = false;
// Other blocks
boolean otherBlocks = false;
// Ceiling issue
boolean inCeiling = false;
// Blocks above the greenhouse
boolean blocksAbove = false;
// The y height where other blocks were found
// If this is the bottom layer, the player has most likely uneven walls
int otherBlockLayer = -1;
int wallBlockCount = 0;
Location roofHopperLoc = null;
Set<Location> redGlass = new HashSet<Location>();
int y = 0;
for (y = world.getMaxHeight(); y >= walls.getFloor(); y--) {
Set<Location> redLayer = new HashSet<Location>();
int doorCount = 0;
int hopperCount = 0;
boolean airHole = false;
boolean otherBlock = false;
boolean blockAbove = false;
wallBlockCount = 0;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
Location thisBlock = new Location(world, x, y, z);
Material blockType = world.getBlockAt(x, y, z).getType();
// Checking above greenhouse - no blocks allowed
if (y > roof.getHeight()) {
//Greenhouses.logger(3,"DEBUG: Above greenhouse");
// We are above the greenhouse
if ((world.getEnvironment().equals(Environment.NORMAL) || world.getEnvironment().equals(Environment.THE_END))
&& blockType != Material.AIR) {
blockAbove = true;
redLayer.add(thisBlock);
}
} else {
//Greenhouses.logger(3,"DEBUG: In greenhouse");
// Check just the walls
if (y == roof.getHeight() || x == minX || x == maxX || z == minZ || z== maxZ) {
//Greenhouses.logger(3,"DEBUG: Checking " + x + " " + y + " " + z);
// Doing string check for DOOR allows all 1.8 doors to be covered even if the server is not 1.8
if ((y != roof.getHeight() && !WALLBLOCKS.contains(blockType.name()) && !blockType.toString().contains("DOOR"))
|| (y == roof.getHeight() && !roof.isRoofBlock(blockType) && !blockType.toString().contains("DOOR"))) {
logger(2,"DEBUG: bad block found at " + x + "," + y+ "," + z + " " + blockType);
if (blockType == Material.AIR) {
airHole = true;
if (y == roof.getHeight()) {
inCeiling = true;
}
} else {
otherBlock = true;
}
redLayer.add(thisBlock);
} else {
wallBlockCount++;
// A string comparison is used to capture 1.8+ door types without stopping pre-1.8
// servers from working
if (blockType.toString().contains("DOOR")) {
doorCount++;
// If we already have 8 doors add these blocks to the red list
if (wallDoors == 8) {
redLayer.add(thisBlock);
}
}
if (blockType.equals(Material.HOPPER)) {
hopperCount++;
if (ghHopper > 0) {
// Problem! Add extra hoppers to the red glass list
redLayer.add(thisBlock);
} else {
// This is the first hopper
roofHopperLoc = thisBlock.clone();
}
}
}
}
}
}
}
if (wallBlockCount == 0 && y < roof.getHeight()) {
// This is the floor
break;
} else {
wallBlockCount = 0;
wallDoors += doorCount;
ghHopper += hopperCount;
if (airHole) {
airHoles = true;
}
if (otherBlock) {
otherBlocks = true;
if (otherBlockLayer < 0) {
otherBlockLayer = y;
}
}
if (blockAbove) {
blocksAbove = true;
}
// Collect the holes
redGlass.addAll(redLayer);
}
}
logger(3,"Floor is at height y = " + y);
// Check that the player is vertically in the greenhouse
if (player.getLocation().getBlockY() <= y) {
player.sendMessage(ChatColor.RED + Locale.errornotinside);
return null;
}
if (!redGlass.isEmpty()) {
// Show errors
if (blocksAbove) {
player.sendMessage(ChatColor.RED + Locale.createnothingabove);
}
if (airHoles & !inCeiling) {
player.sendMessage(ChatColor.RED + Locale.createholeinwall);
} else if (airHoles & inCeiling) {
player.sendMessage(ChatColor.RED + Locale.createholeinroof);
}
//Greenhouses.logger(3,"DEBUG: otherBlockLayer = " + otherBlockLayer);
if (otherBlocks && otherBlockLayer == y + 1) {
player.sendMessage(ChatColor.RED + "Walls must be even all the way around");
} else if (otherBlocks && otherBlockLayer == roof.getHeight()) {
player.sendMessage(ChatColor.RED + "Roof blocks must be glass, glowstone, doors or a hopper.");
} else if (otherBlocks) {
player.sendMessage(ChatColor.RED + "Wall blocks must be glass, glowstone, doors or a hopper.");
}
if (wallDoors > 8) {
player.sendMessage(ChatColor.RED + Locale.createdoorerror);
}
if (ghHopper > 1) {
player.sendMessage(ChatColor.RED + Locale.createhoppererror);
}
// Display the red glass and then erase it
for (Location loc: redGlass) {
player.sendBlockChange(loc,Material.STAINED_GLASS,(byte)14);
}
final Set<Location> original = redGlass;
Bukkit.getScheduler().runTaskLater(this, new Runnable() {
@Override
public void run() {
for (Location loc: original) {
player.sendBlockChange(loc,loc.getBlock().getType(),loc.getBlock().getData());
}
}}, 120L);
return null;
}
//player.sendMessage(ChatColor.GREEN + "Seems ok");
Location insideOne = new Location(world,minX,walls.getFloor(),minZ);
Location insideTwo = new Location(world,maxX,roof.getHeight(),maxZ);
BiomeRecipe winner = null;
// Now check for the greenhouse biomes
if (greenhouseRecipe != null) {
if (greenhouseRecipe.checkRecipe(insideOne, insideTwo, player)) {
winner = greenhouseRecipe;
} else {
return null;
}
}
if (winner == null) {
// Loop through biomes to see which ones match
// Int is the priority. Higher priority ones win
int priority = 0;
for (BiomeRecipe r : addon.getBiomeRecipes()) {
// Only check ones that this player has permission to use
if (r.getPermission().isEmpty() || (!r.getPermission().isEmpty() && VaultHelper.checkPerm(player, r.getPermission()))) {
// Only check higher priority ones
if (r.getPriority()>priority) {
player.sendMessage(ChatColor.GOLD + "Trying " + Util.prettifyText(r.getBiome().toString()));
if (r.checkRecipe(insideOne, insideTwo, null)) {
player.sendMessage(ChatColor.GOLD + "Maybe...");
winner = r;
priority = r.getPriority();
} else {
player.sendMessage(ChatColor.GOLD + "No.");
}
}
} else {
addon.logger(2, "No permission for " + player.getName() + " to make " + r.getBiome().toString());
//player.sendMessage(ChatColor.RED + "No permission for " + r.getType().toString());
}
}
}
if (winner != null) {
logger(3,"biome winner is " + winner.getFriendlyName());
Greenhouse g = new Greenhouse(this, insideOne, insideTwo, player.getUniqueId());
g.setOriginalBiome(originalBiome);
g.setBiomeRecipe(winner);
String friendlyName = Util.prettifyText(winner.getBiome().toString());
if (!winner.getFriendlyName().isEmpty()) {
friendlyName = winner.getFriendlyName();
}
g.setPlayerName(player.getName());
g.setEnterMessage((Locale.messagesenter.replace("[owner]", player.getDisplayName())).replace("[biome]", friendlyName));
g.setFarewellMessage((Locale.messagesleave.replace("[owner]", player.getDisplayName())).replace("[biome]", friendlyName));
// Store the roof hopper location so it can be tapped in the future
if (ghHopper == 1) {
g.setRoofHopperLocation(roofHopperLoc);
}
g.startBiome(false);
player.sendMessage(ChatColor.GREEN + Locale.createsuccess.replace("[biome]", friendlyName));
players.incGreenhouseCount(player);
// Store this greenhouse
greenhouses.add(g);
// Find everyone who is in this greenhouse and tell them they are in a greenhouse now
for (Player p : getServer().getOnlinePlayers()) {
if (g.insideGreenhouse(p.getLocation())) {
if (!p.equals(player)) {
p.sendMessage((Locale.messagesyouarein.replace("[owner]", player.getDisplayName())).replace("[biome]", friendlyName));
}
}
}
return g;
}
return null;
}
/**
* Saves all the greenhouses to greenhouse.yml
*/
public void saveGreenhouses() {
logger(2,"Saving greenhouses...");
ConfigurationSection greenhouseSection = greenhouseConfig.createSection("greenhouses");
// Get a list of all the greenhouses
int greenhouseNum = 0;
for (Greenhouse g: greenhouses) {
try {
// Copy over the info
greenhouseSection.set(greenhouseNum + ".owner", g.getOwner().toString());
greenhouseSection.set(greenhouseNum + ".playerName", g.getPlayerName());
greenhouseSection.set(greenhouseNum + ".pos-one", getStringLocation(g.getPos1()));
greenhouseSection.set(greenhouseNum + ".pos-two", getStringLocation(g.getPos2()));
greenhouseSection.set(greenhouseNum + ".originalBiome", g.getOriginalBiome().toString());
greenhouseSection.set(greenhouseNum + ".greenhouseBiome", g.getBiome().toString());
greenhouseSection.set(greenhouseNum + ".greenhouseRecipe", g.getBiomeRecipe().getName());
greenhouseSection.set(greenhouseNum + ".roofHopperLocation", getStringLocation(g.getRoofHopperLocation()));
greenhouseSection.set(greenhouseNum + ".farewellMessage", g.getFarewellMessage());
greenhouseSection.set(greenhouseNum + ".enterMessage", g.getEnterMessage());
} catch (Exception e) {
addon.getLogger().severe("Problem copying player files");
e.printStackTrace();
}
greenhouseNum++;
}
try {
greenhouseConfig.save(greenhouseFile);
} catch (IOException e) {
getLogger().severe("Could not save greenhouse.yml!");
e.printStackTrace();
}
}
/**
* General purpose logger to reduce console spam
* @param level
* @param info
*/
public void logger(int level, String info) {
if (debug.contains("0")) {
return;
}
if (debug.contains("1") && level == 1) {
Bukkit.getLogger().info(info);
} else if (debug.contains(String.valueOf(level))){
Bukkit.getLogger().info("DEBUG ["+level+"]:"+info);
}
}
/**
* @return the debug
*/
public List<String> getDebug() {
return debug;
}
/**
* Returns the maximum number of greenhouses this player can make
* @param player
* @return number of greenhouses or -1 to indicate unlimited
*/
public int getMaxGreenhouses(Player player) {
// -1 is unimited
int maxGreenhouses = Settings.maxGreenhouses;
for (PermissionAttachmentInfo perms : player.getEffectivePermissions()) {
if (perms.getPermission().startsWith("greenhouses.limit")) {
logger(2,"Permission is = " + perms.getPermission());
try {
int max = Integer.valueOf(perms.getPermission().split("greenhouses.limit.")[1]);
if (max > maxGreenhouses) {
maxGreenhouses = max;
}
} catch (Exception e) {} // Do nothing
}
// Do some sanity checking
if (maxGreenhouses < 0) {
maxGreenhouses = -1;
}
}
return maxGreenhouses;
}
}