diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..839d647 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding/=UTF-8 diff --git a/src/main/java/world/bentobox/greenhouses/Greenhouses.java b/src/main/java/world/bentobox/greenhouses/Greenhouses.java index 5292f8a..44b7cdc 100644 --- a/src/main/java/world/bentobox/greenhouses/Greenhouses.java +++ b/src/main/java/world/bentobox/greenhouses/Greenhouses.java @@ -1,1590 +1,103 @@ +/** + * + */ 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.bentobox.api.configuration.Config; 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; +import world.bentobox.greenhouses.listeners.SnowTracker; +import world.bentobox.greenhouses.managers.GreenhouseManager; +import world.bentobox.greenhouses.managers.RecipeManager; +import world.bentobox.greenhouses.ui.user.UserCommand; /** - * 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; + private GreenhouseManager manager; + private Settings settings; + private RecipeManager recipes; + private List activeWorlds = new ArrayList<>(); - // Greenhouses - private HashSet greenhouses = new HashSet(); - private HashMap> playerhouses = new HashMap>(); - - // Offline Messages - private HashMap> messages = new HashMap>(); - 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 biomeRecipes = new ArrayList(); - private ControlPanel biomeInv; - // Debug level (0 = none, 1 = important ones, 2 = level 2, 3 = level 3 - private List debug = new ArrayList(); - - /** - * 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 plants = (HashMap)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 mobs = (HashMap)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 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 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() + /* (non-Javadoc) + * @see world.bentobox.bentobox.api.addons.Addon#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 - * Integer.MAX_VALUE - 1. - * - * @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 storedhouses = null; - - if (playerhouses.get(owner) != null) { - storedhouses = playerhouses.get(owner); - playerhouses.remove(owner); - } else { - storedhouses = new HashSet(); - } - - storedhouses.add(g); - greenhouses.add(g); - playerhouses.put(owner, storedhouses); - } - - public void removeGHFromPlayer(UUID owner, Greenhouse g) { - HashSet storedhouses = null; - - if (playerhouses.get(owner) != null) { - storedhouses = playerhouses.get(owner); - playerhouses.remove(owner); - } else { - storedhouses = new HashSet(); - } - - 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 playerMessages = messages.get(playerUUID); - if (playerMessages != null) { - playerMessages.add(message); - } else { - playerMessages = new ArrayList(Arrays.asList(message)); - } - messages.put(playerUUID, playerMessages); - return true; - } - - public List getMessages(UUID playerUUID) { - List playerMessages = messages.get(playerUUID); - if (playerMessages != null) { - // Remove the messages - messages.remove(playerUUID); - } else { - // No messages - playerMessages = new ArrayList(); - } - return playerMessages; - } - - public boolean saveMessages() { - logger(1,"Saving offline messages..."); - try { - // Convert to a serialized string - final HashMap offlineMessages = new HashMap(); - 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 temp = (HashMap) messageStore.getConfigurationSection("messages").getValues(true); - for (String s : temp.keySet()) { - List 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 getGreenhouses() { - return greenhouses; - } - - /** - * - * @param uuid - * @return Cached player greenhouses - */ - /* - public HashSet getPlayerGHouse(UUID uuid) { - if (playerhouses.containsKey(uuid)) { - return playerhouses.get(uuid); - } - return null; - } - */ - - /** - * @param greenhouses the greenhouses to set - */ - public void setGreenhouses(HashSet greenhouses) { - this.greenhouses = greenhouses; - } - - /** - * @return the playerhouses - */ - public HashMap> 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 onesToRemove = new ArrayList(); - 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 redGlass = new HashSet(); - int y = 0; - for (y = world.getMaxHeight(); y >= walls.getFloor(); y--) { - Set redLayer = new HashSet(); - 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 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")) { + this.saveResource("biomes.yml", false); + settings = new Config<>(this, Settings.class).loadConfigObject(); + if (settings == null) { + // Settings did no load correctly. Disable. + logError("Settings did not load correctly - disabling Greenhouses - please check config.yml"); + this.setState(State.DISABLED); return; } - if (debug.contains("1") && level == 1) { - Bukkit.getLogger().info(info); - } else if (debug.contains(String.valueOf(level))){ - Bukkit.getLogger().info("DEBUG ["+level+"]:"+info); - } + // Load manager + manager = new GreenhouseManager(this); + // Load recipes + recipes = new RecipeManager(this); + + // Register commands for AcidIsland and BSkyBlock + getPlugin().getAddonsManager().getGameModeAddons().stream() + .filter(gm -> gm.getDescription().getName().equals("AcidIsland") || gm.getDescription().getName().equals("BSkyBlock")) + .forEach(gm -> { + // Register command + gm.getPlayerCommand().ifPresent(playerCmd -> new UserCommand(this, playerCmd)); + // Store active world + activeWorlds.add(gm.getOverWorld()); + }); + + // Register listeners + this.registerListener(new SnowTracker(this)); + this.registerListener(new GreenhouseEvents(this)); + this.registerListener(new GreenhouseGuard(this)); + } - - /** - * @return the debug + /* (non-Javadoc) + * @see world.bentobox.bentobox.api.addons.Addon#onDisable() */ - public List getDebug() { - return debug; + @Override + public void onDisable() { + if (manager != null) { + manager.saveGreenhouses(); + } + } /** - * Returns the maximum number of greenhouses this player can make - * @param player - * @return number of greenhouses or -1 to indicate unlimited + * @return the manager */ - 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; + public GreenhouseManager getManager() { + return manager; } + + /** + * @return Settings + */ + public Settings getSettings() { + return settings; + } + + /** + * @return the recipes + */ + public RecipeManager getRecipes() { + return recipes; + } + + public List getActiveWorlds() { + return activeWorlds; + } + } diff --git a/src/main/java/world/bentobox/greenhouses/PlayerCache.java b/src/main/java/world/bentobox/greenhouses/PlayerCache.java deleted file mode 100644 index 4e6cc57..0000000 --- a/src/main/java/world/bentobox/greenhouses/PlayerCache.java +++ /dev/null @@ -1,193 +0,0 @@ -package world.bentobox.greenhouses; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; - -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; - -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.ui.Locale; - -/** - * @author tastybento - * Provides a memory cache of online player information - * This is the one-stop-shop of player info - */ -public class PlayerCache { - private HashMap playerCache = new HashMap(); - private final Greenhouses plugin; - - public PlayerCache(Greenhouses plugin) { - this.plugin = plugin; - playerCache.clear(); - // Add any players currently online (handles the /reload condition) - final Collection serverPlayers = plugin.getServer().getOnlinePlayers(); - for (Player p : serverPlayers) { - // Add this player to the online cache - playerCache.put(p.getUniqueId(), new Players(p)); - } - } - - /** - * Add a player to the cache when they join the server (called in JoinLeaveEvents) - * @param player - */ - public void addPlayer(Player player) { - if (!playerCache.containsKey(player.getUniqueId())) { - playerCache.put(player.getUniqueId(),new Players(player)); - } - // Check permission limits on number of greenhouses - int limit = plugin.getMaxGreenhouses(player); // 0 = none allowed. Positive numbers = limit. Negative = unlimited - /* - if (plugin.getPlayerGHouse(player.getUniqueId()) == null) { - return; - } - */ - List toBeRemoved = new ArrayList(); - // Look at how many greenhouses player has and remove any over their limit - int owned = 0; - for (Greenhouse g: plugin.getGreenhouses()) { - if (g.getOwner().equals(player.getUniqueId())) { - owned++; - if (owned <= limit) { - // Allowed - playerCache.get(player.getUniqueId()).incrementGreenhouses(); - g.setPlayerName(player.getName()); - } else { - // Over the limit - toBeRemoved.add(g); - } - } - } - if (Settings.deleteExtras && limit >= 0) { - // Remove greenhouses - for (Greenhouse g : toBeRemoved) { - plugin.removeGreenhouse(g); - plugin.logger(2,"Removed greenhouse over the limit for " + player.getName()); - } - if (toBeRemoved.size() > 0) { - if (limit == 0) { - player.sendMessage(ChatColor.RED + Locale.limitsnoneallowed.replace("[number]",String.valueOf(toBeRemoved.size()))); - } else { - player.sendMessage(ChatColor.RED + Locale.limitslimitedto.replace("[limit]", String.valueOf(limit)).replace("[number]",String.valueOf(toBeRemoved.size()))); - } - } - } - } - - - public void removeOnlinePlayer(Player player) { - if (playerCache.containsKey(player.getUniqueId())) { - playerCache.remove(player); - plugin.logger(3,"Removing player from cache: " + player); - } - } - - /** - * Removes all players on the server now from cache and saves their info - */ - public void removeAllPlayers() { - playerCache.clear(); - } - - /* - * Player info query methods - */ - /* - public void setInGreenhouse(Player player, Greenhouse inGreenhouse) { - if (playerCache.containsKey(player.getUniqueId())) { - playerCache.get(player.getUniqueId()).setInGreenhouse(inGreenhouse); - } - } -*/ - /** - * @param playerUUID - * @return the greenhouse the player is in or null if no greenhouse - */ - public Greenhouse getInGreenhouse(Player player) { - for (Greenhouse g : plugin.getGreenhouses()) { - if (g.insideGreenhouse(player.getLocation())) { - return g; - } - } - return null; - } - - /** - * Increments the player's greenhouse count if permissions allow - * @param player - * @return true if successful, otherwise false - */ - public boolean incGreenhouseCount(Player player) { - // Do a permission check if there are limits - // Check permission limits on number of greenhouses - int limit = plugin.getMaxGreenhouses(player); // 0 = none allowed. Positive numbers = limit. Negative = unlimited - if (limit < 0 || playerCache.get(player.getUniqueId()).getNumberOfGreenhouses() < limit) { - playerCache.get(player.getUniqueId()).incrementGreenhouses(); - return true; - } - - // At the limit, sorry - return false; - } - - /** - * Decrements the number of greenhouses this player has - * @param player - */ - public void decGreenhouseCount(Player player) { - playerCache.get(player.getUniqueId()).decrementGreenhouses(); - } - - /** - * Decrements by UUID - * @param playerUUID - */ - public void decGreenhouseCount(UUID playerUUID) { - if (playerCache.containsKey(playerUUID)) { - playerCache.get(playerUUID).decrementGreenhouses(); - } - } - - - /** - * Returns true if the player is at their permitted limit of greenhouses otherwise false - * @param player - * @return - */ - public boolean isAtLimit(Player player) { - if (getRemainingGreenhouses(player) == 0) { - return true; - } - return false; - } - - /** - * Returns how many greenhouses the player is allowed to make - * @param player - * @return - */ - public int getRemainingGreenhouses(Player player) { - int limit = plugin.getMaxGreenhouses(player); - if (limit < 0) { - return -1; - } - int size = 0; - if (plugin.getPlayerhouses().containsKey(player.getUniqueId())) { - size = plugin.getPlayerhouses().get(player.getUniqueId()).size(); - } - int remaining = limit - size; - if (remaining < 0) { - return 0; - } else { - return remaining; - } - - } -} - - - diff --git a/src/main/java/world/bentobox/greenhouses/Players.java b/src/main/java/world/bentobox/greenhouses/Players.java deleted file mode 100644 index 51390ed..0000000 --- a/src/main/java/world/bentobox/greenhouses/Players.java +++ /dev/null @@ -1,70 +0,0 @@ -package world.bentobox.greenhouses; - -import java.util.UUID; - -import org.bukkit.entity.Player; - -import world.bentobox.greenhouses.greenhouse.Greenhouse; - -/** - * Tracks the following info on the player - * UUID, player name, whether they are in a greenhouse or not and how many greenhouses they have - */ -public class Players { - private UUID uuid; - private Greenhouse inGreenhouse; - private int numberOfGreenhouses; - - /** - * @param uuid - * Constructor - initializes the state variables - * - */ - public Players(final Player player) { - this.uuid = player.getUniqueId(); - // We do not know if the player is in a greenhouse or not yet - this.inGreenhouse = null; - // We start with the assumption they have no greenhouses yet - this.numberOfGreenhouses = 0; - } - - /** - * @return the inGreenhouse - */ - public Greenhouse getInGreenhouse() { - return inGreenhouse; - } - - /** - * @param inGreenhouse the inGreenhouse to set - */ - public void setInGreenhouse(Greenhouse inGreenhouse) { - this.inGreenhouse = inGreenhouse; - } - - /** - * @return the numberOfGreenhouses - */ - public int getNumberOfGreenhouses() { - return numberOfGreenhouses; - } - - public void incrementGreenhouses() { - numberOfGreenhouses++; - } - - public void decrementGreenhouses() { - numberOfGreenhouses--; - if (numberOfGreenhouses < 0) { - numberOfGreenhouses = 0; - } - } - - /** - * @return the uuid - */ - public UUID getUuid() { - return uuid; - } - -} diff --git a/src/main/java/world/bentobox/greenhouses/Settings.java b/src/main/java/world/bentobox/greenhouses/Settings.java index ee23c8f..956aa6e 100644 --- a/src/main/java/world/bentobox/greenhouses/Settings.java +++ b/src/main/java/world/bentobox/greenhouses/Settings.java @@ -1,25 +1,193 @@ package world.bentobox.greenhouses; +import java.util.ArrayList; import java.util.List; +import world.bentobox.bentobox.api.configuration.ConfigComment; +import world.bentobox.bentobox.api.configuration.ConfigEntry; +import world.bentobox.bentobox.api.configuration.StoreAt; +import world.bentobox.bentobox.database.objects.DataObject; + /** - * @author ben + * @author tastybento * Where all the settings are */ -public class Settings { +@StoreAt(filename="config.yml", path="addons/Greenhouses") // Explicitly call out what name this should have. +@ConfigComment("Greenhouses Configuration [version]") +@ConfigComment("") +public class Settings implements DataObject { + // General - public static List worldName; - public static double snowChanceGlobal; - public static double snowDensity; - public static long snowSpeed; - public static int plantTick; - public static int iceInfluence; - public static int blockTick; - public static int mobTick; - public static int ecoTick; - public static boolean allowFlowIn; - public static boolean allowFlowOut; - public static boolean deleteExtras; - public static int maxGreenhouses; + @ConfigComment("BentoBox GameModes that will use Greenhouses") + @ConfigEntry(path = "greenhouses.game-modes") + private List gameModes = new ArrayList<>(); + + @ConfigComment("Weather and ecosystem settings") + @ConfigComment("How often it should snow in the g/h when the weather is raining, in seconds") + @ConfigEntry(path = "greenhouses.snowspeed") + private double snowSpeed = 30; + + @ConfigComment("Chance of any snow falling in a greenhouse when the snow tick occurs") + @ConfigComment("(1.0 = always, 0.0 = never)") + @ConfigEntry(path = "greenhouses.snowchance") + private double snowChanceGlobal = 1; + @ConfigComment("How many blocks should get snow 1 = all of them, 0 = none, 0.1 = 1 in 10") + @ConfigEntry(path = "greenhouses.snowdensity") + private double snowDensity = 0.1; + + @ConfigComment("Biome activity") + @ConfigComment("How often should greenhouse biomes be checked to make sure they are still valid") + @ConfigEntry(path = "greenhouses.ecotick") + private int ecoTick = 5; + @ConfigComment("How often should plants potentially grow in minutes if bonemeal is in the hopper") + @ConfigEntry(path = "greenhouses.planttick") + private int plantTick = 1; + @ConfigComment("How often should blocks potentially convert, in minutes ") + @ConfigComment("Example: dirt-> sand in desert greenhouse") + @ConfigEntry(path = "greenhouses.blocktick") + private int blockTick = 2; + @ConfigComment("How often should mobs be potentially spawned in a greenhouse, in minutes") + @ConfigEntry(path = "greenhouses.mobtick") + private int mobTick = 5; + + + @ConfigComment("Default settings for greenhouse actions") + @ConfigComment("Allow lava or water to flow out of a greenhouse, e.g. through the door, floor") + @ConfigEntry(path = "greenhouses.allowflowout") + private boolean allowFlowOut; + @ConfigComment("Allow lava or water to flow into a greenhouse, e.g., through the door") + @ConfigEntry(path = "greenhouses.allowflowin") + private boolean allowFlowIn; + + + + + @Override + public String getUniqueId() { + return "config"; + } + @Override + public void setUniqueId(String uniqueId) {} + /** + * @return the gameModes + */ + public List getGameModes() { + return gameModes; + } + /** + * @return the snowSpeed + */ + public double getSnowSpeed() { + return snowSpeed; + } + /** + * @return the snowChanceGlobal + */ + public double getSnowChanceGlobal() { + return snowChanceGlobal; + } + /** + * @return the snowDensity + */ + public double getSnowDensity() { + return snowDensity; + } + /** + * @return the ecoTick + */ + public int getEcoTick() { + return ecoTick; + } + /** + * @return the plantTick + */ + public int getPlantTick() { + return plantTick; + } + /** + * @return the blockTick + */ + public int getBlockTick() { + return blockTick; + } + /** + * @return the mobTick + */ + public int getMobTick() { + return mobTick; + } + /** + * @return the allowFlowOut + */ + public boolean isAllowFlowOut() { + return allowFlowOut; + } + /** + * @return the allowFlowIn + */ + public boolean isAllowFlowIn() { + return allowFlowIn; + } + /** + * @param gameModes the gameModes to set + */ + public void setGameModes(List gameModes) { + this.gameModes = gameModes; + } + /** + * @param snowSpeed the snowSpeed to set + */ + public void setSnowSpeed(double snowSpeed) { + this.snowSpeed = snowSpeed; + } + /** + * @param snowChanceGlobal the snowChanceGlobal to set + */ + public void setSnowChanceGlobal(double snowChanceGlobal) { + this.snowChanceGlobal = snowChanceGlobal; + } + /** + * @param snowDensity the snowDensity to set + */ + public void setSnowDensity(double snowDensity) { + this.snowDensity = snowDensity; + } + /** + * @param ecoTick the ecoTick to set + */ + public void setEcoTick(int ecoTick) { + this.ecoTick = ecoTick; + } + /** + * @param plantTick the plantTick to set + */ + public void setPlantTick(int plantTick) { + this.plantTick = plantTick; + } + /** + * @param blockTick the blockTick to set + */ + public void setBlockTick(int blockTick) { + this.blockTick = blockTick; + } + /** + * @param mobTick the mobTick to set + */ + public void setMobTick(int mobTick) { + this.mobTick = mobTick; + } + /** + * @param allowFlowOut the allowFlowOut to set + */ + public void setAllowFlowOut(boolean allowFlowOut) { + this.allowFlowOut = allowFlowOut; + } + /** + * @param allowFlowIn the allowFlowIn to set + */ + public void setAllowFlowIn(boolean allowFlowIn) { + this.allowFlowIn = allowFlowIn; + } + } \ No newline at end of file diff --git a/src/main/java/world/bentobox/greenhouses/data/Greenhouse.java b/src/main/java/world/bentobox/greenhouses/data/Greenhouse.java new file mode 100644 index 0000000..da6b039 --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/data/Greenhouse.java @@ -0,0 +1,195 @@ +/** + * + */ +package world.bentobox.greenhouses.data; + +import java.awt.Rectangle; +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Biome; + +import world.bentobox.bentobox.database.objects.DataObject; +import world.bentobox.greenhouses.greenhouse.BiomeRecipe; + +/** + * @author tastybento + * + */ +public class Greenhouse implements DataObject { + + private String uniqueId = UUID.randomUUID().toString(); + private Location location; + private Rectangle footprint; + private int ceilingHeight; + private Biome originalBiome; + private Biome greenhouseBiome; + private Location roofHopperLocation; + private BiomeRecipe biomeRecipe; + private boolean broken; + + public Greenhouse() {} + + /** + * @param world + * @param footprint + * @param ceilingHeight + */ + public Greenhouse(World world, Rectangle footprint, int floorHeight, int ceilingHeight) { + this.location = new Location(world, footprint.getMinX(), floorHeight, footprint.getMinY()); + this.footprint = footprint; + this.ceilingHeight = ceilingHeight; + } + + /** + * @return the biomeRecipe + */ + public BiomeRecipe getBiomeRecipe() { + return biomeRecipe; + } + + /** + * @return the ceilingHeight + */ + public int getCeilingHeight() { + return ceilingHeight; + } + + /** + * @return the floorHeight + */ + public int getFloorHeight() { + return location.getBlockY(); + } + + /** + * @return the floor + */ + public Rectangle getFootprint() { + return footprint; + } + + /** + * @return the greenhouseBiome + */ + public Biome getGreenhouseBiome() { + return greenhouseBiome; + } + + /** + * @return the location + */ + public Location getLocation() { + return location; + } + + /** + * @return the originalBiome + */ + public Biome getOriginalBiome() { + return originalBiome; + } + + /** + * @return the roofHopperLocation + */ + public Location getRoofHopperLocation() { + return roofHopperLocation; + } + + /* (non-Javadoc) + * @see world.bentobox.bentobox.database.objects.DataObject#getUniqueId() + */ + @Override + public String getUniqueId() { + return uniqueId; + } + + /** + * @return the broken + */ + public boolean isBroken() { + return broken; + } + + /** + * @param biomeRecipe the biomeRecipe to set + */ + public void setBiomeRecipe(BiomeRecipe biomeRecipe) { + this.biomeRecipe = biomeRecipe; + } + + /** + * @param broken the broken to set + */ + public void setBroken(boolean broken) { + this.broken = broken; + } + + /** + * @param ceilingHeight the ceilingHeight to set + */ + public void setCeilingHeight(int ceilingHeight) { + this.ceilingHeight = ceilingHeight; + } + + /** + * @param floor the floor to set + */ + public void setFootprint(Rectangle floor) { + this.footprint = floor; + } + + /** + * @param greenhouseBiome the greenhouseBiome to set + */ + public void setGreenhouseBiome(Biome greenhouseBiome) { + this.greenhouseBiome = greenhouseBiome; + } + + /** + * @param location the location to set + */ + public void setLocation(Location location) { + this.location = location; + } + + /** + * @param originalBiome the originalBiome to set + */ + public void setOriginalBiome(Biome originalBiome) { + this.originalBiome = originalBiome; + } + + /** + * @param roofHopperLocation the roofHopperLocation to set + */ + public void setRoofHopperLocation(Location roofHopperLocation) { + this.roofHopperLocation = roofHopperLocation; + } + + /* (non-Javadoc) + * @see world.bentobox.bentobox.database.objects.DataObject#setUniqueId(java.lang.String) + */ + @Override + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + + } + + /** + * @return area of greenhouse + */ + public int getArea() { + return this.footprint.height * this.footprint.width; + } + + /** + * @return the world + */ + public World getWorld() { + return this.getLocation().getWorld(); + } + +} diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java b/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java index a5334e8..7e40907 100644 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java +++ b/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java @@ -2,27 +2,27 @@ package world.bentobox.greenhouses.greenhouse; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Random; +import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; -import org.bukkit.ChatColor; -import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; import world.bentobox.bentobox.util.Util; import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.ui.Locale; +import world.bentobox.greenhouses.data.Greenhouse; +import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; -public class BiomeRecipe { +public class BiomeRecipe implements Comparable { private Greenhouses plugin; private Biome type; private Material icon; // Biome icon for control panel @@ -53,16 +53,17 @@ public class BiomeRecipe { private String permission = ""; private Random random = new Random(); + private Map missingBlocks; /** * @param type * @param priority */ - public BiomeRecipe(Greenhouses plugin, Biome type, int priority) { - this.plugin = plugin; + public BiomeRecipe(Greenhouses addon, Biome type, int priority) { + this.plugin = addon; this.type = type; this.priority = priority; - plugin.logger(3,"" + type.toString() + " priority " + priority); + //addon.logger(3,"" + type.toString() + " priority " + priority); mobLimit = 9; // Default } @@ -75,7 +76,7 @@ public class BiomeRecipe { public void addConvBlocks(Material oldMaterial, Material newMaterial, double convChance, Material localMaterial) { double probability = Math.min(convChance/100 , 1D); conversionBlocks.put(oldMaterial, new GreenhouseBlockConversions(oldMaterial, newMaterial, probability, localMaterial)); - plugin.logger(1," " + convChance + "% chance for " + Util.prettifyText(oldMaterial.toString()) + " to convert to " + Util.prettifyText(newMaterial.toString())); + //plugin.logger(1," " + convChance + "% chance for " + Util.prettifyText(oldMaterial.toString()) + " to convert to " + Util.prettifyText(newMaterial.toString())); } @@ -85,12 +86,13 @@ public class BiomeRecipe { * @param mobSpawnOn */ public void addMobs(EntityType mobType, int mobProbability, Material mobSpawnOn) { - plugin.logger(1," " + mobProbability + "% chance for " + Util.prettifyText(mobType.toString()) + " to spawn on " + Util.prettifyText(mobSpawnOn.toString())+ "."); + //plugin.logger(1," " + mobProbability + "% chance for " + Util.prettifyText(mobType.toString()) + " to spawn on " + Util.prettifyText(mobSpawnOn.toString())+ "."); double probability = ((double)mobProbability/100); + double lastProb = mobTree.isEmpty() ? 0D : mobTree.lastKey(); // Add up all the probabilities in the list so far - if ((1D - mobTree.lastKey()) >= probability) { + if ((1D - lastProb) >= probability) { // Add to probability tree - mobTree.put(mobTree.lastKey() + probability, new GreenhouseMob(mobType, mobSpawnOn)); + mobTree.put(lastProb + probability, new GreenhouseMob(mobType, mobSpawnOn)); } else { plugin.logError("Mob chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + mobType.toString()); } @@ -106,13 +108,14 @@ public class BiomeRecipe { public void addPlants(Material plantMaterial, int plantProbability, Material plantGrowOn) { double probability = ((double)plantProbability/100); // Add up all the probabilities in the list so far - if ((1D - plantTree.lastKey()) >= probability) { + double lastProb = plantTree.isEmpty() ? 0D : plantTree.lastKey(); + if ((1D - lastProb) >= probability) { // Add to probability tree - plantTree.put(plantTree.lastKey() + probability, new GreenhousePlant(plantMaterial, plantGrowOn)); + plantTree.put(lastProb + probability, new GreenhousePlant(plantMaterial, plantGrowOn)); } else { plugin.logError("Plant chances add up to > 100% in " + type.toString() + " biome recipe! Skipping " + plantMaterial.toString()); } - plugin.logger(1," " + plantProbability + "% chance for " + Util.prettifyText(plantMaterial.toString()) + " to grow on " + Util.prettifyText(plantGrowOn.toString())); + //plugin.logger(1," " + plantProbability + "% chance for " + Util.prettifyText(plantMaterial.toString()) + " to grow on " + Util.prettifyText(plantGrowOn.toString())); } /** @@ -121,31 +124,24 @@ public class BiomeRecipe { */ public void addReqBlocks(Material blockMaterial, int blockQty) { requiredBlocks.put(blockMaterial, blockQty); - plugin.logger(1," " + blockMaterial + " x " + blockQty); + //plugin.logger(1," " + blockMaterial + " x " + blockQty); } // Check required blocks /** * Checks greenhouse meets recipe requirements. If player is not null, a explanation of * any failures will be provided. - * @param pos1 - * @param pos2 - * @param player - * @return true if a cube defined by pos1 and pos2 meet this biome recipe. + * @return true if meet this biome recipe. */ - public boolean checkRecipe(Location pos1, Location pos2, Player player) { - plugin.logger(3,"Checking for biome " + type.toString()); - long area = (pos2.getBlockX()-pos1.getBlockX()-1) * (pos2.getBlockZ()-pos1.getBlockZ()-1); - plugin.logger(3,"area =" + area); - plugin.logger(3,"Pos1 = " + pos1.toString()); - plugin.logger(3,"Pos1 = " + pos2.toString()); - boolean pass = true; + public Set checkRecipe(Greenhouse gh) { + Set result = new HashSet<>(); + long area = gh.getArea(); Map blockCount = new HashMap<>(); // Look through the greenhouse and count what is in there - for (int y = pos1.getBlockY(); y 0 && lavaRatio < lavaCoverage) { - if (player != null) { - player.sendMessage(ChatColor.RED + Locale.recipelavamustbe.replace("[coverage]", String.valueOf(lavaCoverage))); - } - pass=false; - + result.add(GreenhouseResult.FAIL_INSUFFICIENT_LAVA); } if (iceCoverage > 0 && iceRatio < iceCoverage) { - if (player != null) { - player.sendMessage(ChatColor.RED + Locale.recipeicemustbe.replace("[coverage]", String.valueOf(iceCoverage))); - } - pass=false; + result.add(GreenhouseResult.FAIL_INSUFFICIENT_ICE); } // Compare to the required blocks - Map missingBlocks = requiredBlocks.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() - blockCount.getOrDefault(e.getKey(), 0))); + missingBlocks = requiredBlocks.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() - blockCount.getOrDefault(e.getKey(), 0))); // Remove any entries that are 0 or less missingBlocks.values().removeIf(v -> v <= 0); - if (!missingBlocks.isEmpty()) { - pass = false; - } - missingBlocks.forEach((k,v) -> player.sendMessage(ChatColor.RED + Locale.recipemissing + " " + Util.prettifyText(k.toString()) + " x " + v)); - return pass; + return result; } /** * @param b */ public void convertBlock(Block b) { - plugin.logger(3,"try to convert block"); + //plugin.logger(3,"try to convert block"); GreenhouseBlockConversions bc = conversionBlocks.get(b.getType()); if (bc == null || random.nextDouble() > bc.getProbability()) { return; @@ -226,7 +199,7 @@ public class BiomeRecipe { // Check if the block is in the right area, up, down, n,s,e,w if (ADJ_BLOCKS.stream().map(b::getRelative).map(Block::getType).anyMatch(m -> bc.getLocalMaterial() == null || m == bc.getLocalMaterial())) { // Convert! - plugin.logger(3,"Convert block"); + //plugin.logger(3,"Convert block"); b.setType(bc.getNewMaterial()); } } @@ -333,18 +306,20 @@ public class BiomeRecipe { /** * Plants a plant on block bl if it makes sense. - * @param bl - * @return + * @param bl - block + * @return true if successful */ - public void growPlant(Block bl) { + public boolean growPlant(Block bl) { if (bl.getType() != Material.AIR) { - return; + return false; } - getRandomPlant().ifPresent(p -> { + return getRandomPlant().map(p -> { if (bl.getY() != 0 && p.getPlantGrownOn().map(m -> m.equals(bl.getRelative(BlockFace.DOWN).getType())).orElse(true)) { bl.setType(p.getPlantMaterial()); + return true; } - }); + return false; + }).orElse(false); } /** @@ -358,9 +333,9 @@ public class BiomeRecipe { */ public void setIcecoverage(int icecoverage) { if (icecoverage == 0) { - plugin.logger(1," No Ice Allowed"); + //plugin.logger(1," No Ice Allowed"); } else if (icecoverage > 0) { - plugin.logger(1," Ice > " + icecoverage + "%"); + //plugin.logger(1," Ice > " + icecoverage + "%"); } this.iceCoverage = icecoverage; } @@ -377,9 +352,9 @@ public class BiomeRecipe { */ public void setLavacoverage(int lavacoverage) { if (lavacoverage == 0) { - plugin.logger(1," No Lava Allowed"); + //plugin.logger(1," No Lava Allowed"); } else if (lavacoverage > 0) { - plugin.logger(1," Lava > " + lavacoverage + "%"); + //plugin.logger(1," Lava > " + lavacoverage + "%"); } this.lavaCoverage = lavacoverage; } @@ -424,11 +399,23 @@ public class BiomeRecipe { */ public void setWatercoverage(int watercoverage) { if (watercoverage == 0) { - plugin.logger(1," No Water Allowed"); + //plugin.logger(1," No Water Allowed"); } else if (watercoverage > 0) { - plugin.logger(1," Water > " + watercoverage + "%"); + //plugin.logger(1," Water > " + watercoverage + "%"); } this.waterCoverage = watercoverage; } + /** + * @return the missingBlocks + */ + public Map getMissingBlocks() { + return missingBlocks; + } + + @Override + public int compareTo(BiomeRecipe o) { + return Integer.compare(o.getPriority(), this.getPriority()); + } + } diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/Ecosystem.java b/src/main/java/world/bentobox/greenhouses/greenhouse/Ecosystem.java deleted file mode 100644 index 16400d4..0000000 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/Ecosystem.java +++ /dev/null @@ -1,144 +0,0 @@ -package world.bentobox.greenhouses.greenhouse; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.Hopper; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.weather.WeatherChangeEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitTask; - -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.Settings; - -/** - * Monitors the greenhouses and grows things, adds weather etc. - * @author ben - * - */ -public class Ecosystem implements Listener { - private final Greenhouses addon; - private final static List SNOWBIOMES = Arrays.stream(Biome.values()).filter(b -> b.name().contains("COLD") || b.name().contains("ICE") || b.name().contains("FROZEN")).collect(Collectors.toList()); - private BukkitTask snow; - private List snowGlobes = new ArrayList(); - - public Ecosystem(final Greenhouses plugin) { - this.addon = plugin; - } - - @EventHandler - public void onWeatherChangeEvent(final WeatherChangeEvent e) { - if (!Settings.worldName.contains(e.getWorld().getName())) { - return; - } - if (e.toWeatherState()) { - // It's raining - addon.logger(3,"It's raining!"); - startSnow(); - } else { - // It's stopped raining! - addon.logger(3,"Stopped raining!"); - if (snow != null) - snow.cancel(); - } - } - - private void startSnow() { - if (snow != null) { - // Cancel the old snow task - snow.cancel(); - } - - // Spin off scheduler - snowGlobes.clear(); - snow = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { - - // Run through each greenhouse - only bother with snow biomes - addon.logger(3,"started scheduler"); - // Check all the greenhouses and their hoppers and build a list of snow greenhouses that exist now - List toBeRemoved = new ArrayList(); - for (Greenhouse g : addon.getGreenhouses()) { - addon.logger(3,"Testing greenhouse biome : " + g.getBiome().toString()); - if (SNOWBIOMES.contains(g.getBiome())) { - addon.logger(3,"Snow biome found!"); - // If it is already on the list, just snow, otherwise check if the hopper has water - if (!snowGlobes.contains(g)) { - Location hopper = g.getRoofHopperLocation(); - if (hopper != null) { - addon.logger(3,"Hopper location:" + hopper.toString()); - Block b = hopper.getBlock(); - // Check the hopper is still there - if (b.getType().equals(Material.HOPPER)) { - Hopper h = (Hopper)b.getState(); - addon.logger(3,"Hopper found!"); - // Check what is in the hopper - if (h.getInventory().contains(Material.WATER_BUCKET)) { - // Remove the water in the bucket - // We cannot remove an itemstack the easy way because on acid island the bucket is changed to acid - for (ItemStack item : h.getInventory().getContents()) { - if (item != null && item.getType().equals(Material.WATER_BUCKET)) { - // Remove one from this item stack - // Water buckets in theory do no stack... - ItemStack i = item.clone(); - i.setAmount(1); - h.getInventory().removeItem(i); - h.getInventory().addItem(new ItemStack(Material.BUCKET)); - break; - } - } - // Add to list - snowGlobes.add(g); - } - } else { - // Greenhouse is broken or no longer has a hopper when it should - addon.getLogger().warning("Hopper missing from greenhouse at " + g.getRoofHopperLocation().getBlockX() + " " - + g.getRoofHopperLocation().getBlockY() + " " + g.getRoofHopperLocation().getBlockZ()); - addon.getLogger().warning("Removing greenhouse"); - toBeRemoved.add(g); - } - } - } - } - } - if (!snowGlobes.isEmpty()) { - snowOn(snowGlobes); - } - // Remove any greenhouses that need it - for (Greenhouse g : toBeRemoved) { - //UUID owner = g.getOwner(); - addon.removeGreenhouse(g); - //plugin.players.save(owner); - } - addon.saveGreenhouses(); - }, 0L, (Settings.snowSpeed * 20L)); // Every 30 seconds - - } - - protected void snowOn(List snowGlobes) { - for (Greenhouse g : snowGlobes) { - addon.logger(3,"snowing in a greenhouse"); - // Chance of snow - if (Math.random()>Settings.snowChanceGlobal) - return; - g.snow(); - } - } - - /** - * Removes any greenhouses that are currently in the eco system - * @param g - */ - public void remove(Greenhouse g) { - if (snowGlobes.contains(g)) - snowGlobes.remove(g); - } - -} \ No newline at end of file diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/Greenhouse.java b/src/main/java/world/bentobox/greenhouses/greenhouse/Greenhouse.java deleted file mode 100644 index 5e6fe4d..0000000 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/Greenhouse.java +++ /dev/null @@ -1,606 +0,0 @@ -package world.bentobox.greenhouses.greenhouse; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.Hopper; -import org.bukkit.block.data.type.Snow; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.Vector; - -import world.bentobox.bentobox.util.Pair; -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.Settings; - -/** - * Defines a greenhouse - * @author tastybento - * - */ -public class Greenhouse { - private Greenhouses plugin; - private final Location pos1; - private final Location pos2; - private final World world; - private UUID owner; - private String playerName; - private HashMap flags = new HashMap(); - private Biome originalBiome; - private Biome greenhouseBiome; - private Location roofHopperLocation; - private int area; - private int heightY; - private int height; - private int groundY; - private BiomeRecipe biomeRecipe; - - - public Greenhouse(Greenhouses plugin, Location pos1, Location pos2, UUID owner) { - this.plugin = plugin; - this.pos1 = pos1; - this.pos2 = pos2; - int minx = Math.min(pos1.getBlockX(), pos2.getBlockX()); - int maxx = Math.max(pos1.getBlockX(), pos2.getBlockX()); - int minz = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - int maxz = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - this.area = (maxx-minx - 1) * (maxz-minz -1); - this.heightY = Math.max(pos1.getBlockY(), pos2.getBlockY()); // Should always be pos2 is higher, but just in case - this.groundY = Math.min(pos1.getBlockY(), pos2.getBlockY()); - this.height = heightY - groundY; - this.world = pos1.getWorld(); - if (pos1.getWorld() == null || pos2.getWorld() == null) { - plugin.getLogger().severe("This greenhouse's world does not exist!"); - } else { - if (!pos1.getWorld().equals(pos2.getWorld())) { - plugin.getLogger().severe("Pos 1 and Pos 2 are not in the same world!"); - } - } - this.originalBiome = pos1.getBlock().getBiome(); - this.greenhouseBiome = pos2.getBlock().getBiome(); - this.owner = owner; - this.playerName = ""; - flags.put("enterMessage", ""); - flags.put("farewellMessage", ""); - } - - - /** - * @return the originalBiome - */ - public Biome getOriginalBiome() { - return originalBiome; - } - - - /** - * @return the greenhouseBiome - */ - public Biome getBiome() { - return greenhouseBiome; - } - - - /** - * @param winner.getType() the greenhouseBiome to set - */ - public void setBiomeRecipe(BiomeRecipe winner) { - this.greenhouseBiome = winner.getBiome(); - this.biomeRecipe = winner; - } - - /** - * @return the greenhouse's biome recipe - */ - public BiomeRecipe getBiomeRecipe() { - return biomeRecipe; - } - - public void setBiome(Biome greenhouseBiome2) { - this.greenhouseBiome = greenhouseBiome2; - } - - - public boolean insideGreenhouse(Location loc) { - if (loc.getWorld().equals(world)) { - plugin.logger(4,"Checking intersection"); - Vector v = loc.toVector(); - plugin.logger(4,"Pos 1 = " + pos1.toString()); - plugin.logger(4,"Pos 2 = " + pos2.toString()); - plugin.logger(4,"V = " + v.toString()); - boolean i = v.isInAABB(Vector.getMinimum(pos1.toVector(), pos2.toVector()), Vector.getMaximum(pos1.toVector(), pos2.toVector())); - return i; - } - return false; - } - - /** - * Check to see if a location is above a greenhouse - * @param loc - * @return - */ - public boolean aboveGreenhouse(Location loc) { - if (loc.getWorld().equals(world)) { - Vector v = loc.toVector(); - Vector p1 = new Vector(pos1.getBlockX(),heightY,pos1.getBlockZ()); - Vector p2 = new Vector(pos2.getBlockX(),world.getMaxHeight(),pos2.getBlockZ()); - boolean i = v.isInAABB(Vector.getMinimum(p1, p2), Vector.getMaximum(p1, p2)); - return i; - } - return false; - } - - - /** - * Returns true if this location is in a greenhouse wall - * @param loc - * @return - */ - public boolean isAWall(Location loc) { - plugin.logger(3,"wall check"); - if (loc.getBlockX() == pos1.getBlockX() || loc.getBlockX() == pos2.getBlockX() - || loc.getBlockZ() == pos1.getBlockZ() || loc.getBlockZ() == pos2.getBlockZ()) { - return true; - } - return false; - } - - /** - * @return the pos1 - */ - public Location getPos1() { - return new Location (world, pos1.getBlockX(), pos1.getBlockY(), pos1.getBlockZ()); - } - - /** - * @return the pos2 - */ - public Location getPos2() { - return new Location (world, pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ()); - - } - - /** - * @return the owner - */ - public UUID getOwner() { - return owner; - } - - /** - * @return the flags - */ - public HashMap getFlags() { - return flags; - } - - - /** - * @param flags the flags to set - */ - public void setFlags(HashMap flags) { - this.flags = flags; - } - - - - /** - * @param owner the owner to set - */ - public void setOwner(UUID owner) { - this.owner = owner; - } - - /** - * @return the playerName - */ - public String getPlayerName() { - return playerName; - } - - - /** - * @param playerName the playerName to set - */ - public void setPlayerName(String playerName) { - //plugin.getLogger().info("DEBUG: setting name to " + playerName); - this.playerName = playerName; - } - - - /** - * @return the enterMessage - */ - public String getEnterMessage() { - return (String)flags.get("enterMessage"); - } - - - /** - * @return the farewallMessage - */ - public String getFarewellMessage() { - return (String)flags.get("farewellMessage"); - } - - - /** - * @param enterMessage the enterMessage to set - */ - public void setEnterMessage(String enterMessage) { - flags.put("enterMessage",enterMessage); - } - - - /** - * @param farewallMessage the farewallMessage to set - */ - public void setFarewellMessage(String farewellMessage) { - flags.put("farewellMessage",farewellMessage); - } - - - public void setOriginalBiome(Biome originalBiome) { - this.originalBiome = originalBiome; - } - - - public void setRoofHopperLocation(Location roofHopperLoc) { - this.roofHopperLocation = roofHopperLoc; - - } - - - /** - * @return the world - */ - public World getWorld() { - return world; - } - - - public Location getRoofHopperLocation() { - return roofHopperLocation; - } - - /** - * @return the area - */ - public int getArea() { - return area; - } - - - /** - * @return the heightY - */ - public int getHeightY() { - return heightY; - } - - - /** - * @return the height - */ - public int getHeight() { - return height; - } - - - /** - * Reruns the recipe check to see if this greenhouse is still viable - * @return true if okay, otherwise false - */ - public boolean checkEco() { - plugin.logger(3,"Checking the ecology of the greenhouse."); - if (biomeRecipe != null) { - return this.biomeRecipe.checkRecipe(getPos1(), getPos2(), null); - } else { - plugin.logger(3,"BiomeRecipe is null! "); - plugin.getLogger().warning("[Greenhouse info]"); - plugin.getLogger().warning("Owner: " + getOwner()); - plugin.getLogger().warning("Location :" + getPos1().toString() + " to " + getPos2().toString()); - return false; - } - } - - - /** - * Starts the biome in the greenhouse - * @param teleport - if true will teleport the player away and back to force the biome to change - */ - public void startBiome(boolean teleport) { - setBiomeBlocks(greenhouseBiome, teleport); - } - - /** - * Reverts the biome of the greenhouse to the original unless someone is in this greenhouse - * @param to - */ - public void endBiome() { - setBiomeBlocks(originalBiome, false); - } - - - /** - * Actually set blocks to a biome - * The chunk refresh command has been deprecated and no longer works on 1.8+ - * so jumping through hoops to refresh mobs is no longer needed - * If teleport is true, this biome starting is happening during a teleport - * sequence, i.e, gh is being generated or removed - * @param biome - * @param teleport - */ - private void setBiomeBlocks(Biome biome, boolean teleport) { - if (biome == null) { - return; - } - plugin.logger(2,"Biome seting to " + biome.toString()); - Set> chunkCoords = new HashSet<>(); - final Set chunks = new HashSet(); - for (int x = pos1.getBlockX();x(b.getChunk().getX(), b.getChunk().getZ())); - } - } - } - } - - /** - * Spawns friendly mobs according to the type of biome - */ - public void populateGreenhouse() { - if (biomeRecipe == null) { - return; - } - plugin.logger(3,"populating mobs in greenhouse"); - // Make sure no players are around - /* - if (plugin.players.getNumberInGreenhouse(this) > 0) - return; - */ - // Quick check - see if any animal is going to spawn - EntityType mob = biomeRecipe.getRandomMob(); - if (mob == null) { - return; - } - plugin.logger(3,"Mob ready to spawn in location " + pos1.getBlockX() + "," + pos2.getBlockZ() + " in world " + world.getName()); - // Load greenhouse chunks - int numberOfMobs = 0; - Set chunkSet = new HashSet(); - for (int x = (pos1.getBlockX()-15); x < (pos2.getBlockX()+15); x += 16) { - for (int z = (pos1.getBlockZ()-15); z < (pos2.getBlockZ()+15); z += 16) { - Chunk chunk = world.getChunkAt(x/16, z/16); - chunkSet.add(new Pair(x/16,z/16)); - chunk.load(); - plugin.logger(3, "Chunk = " + (x/16) + "," + (z/16) + " number of entities = " + chunk.getEntities().length); - for (Entity entity : chunk.getEntities()) { - plugin.logger(3,entity.getType().toString()); - if (mob.equals(entity.getType())) { - numberOfMobs++; - } - } - } - } - plugin.logger(3,"Mobs in area = " + numberOfMobs); - plugin.logger(3,"Area of greenhouse = " + area); - if (area - (numberOfMobs * biomeRecipe.getMobLimit()) <= 0) { - plugin.logger(3,"Too many mobs already in this greenhouse"); - for (Pair pair: chunkSet) { - world.unloadChunkRequest(pair.getLeft(), pair.getRight()); - } - return; - } - Material type = biomeRecipe.getMobSpawnOn(mob); - int minx = Math.min(pos1.getBlockX(), pos2.getBlockX()); - int maxx = Math.max(pos1.getBlockX(), pos2.getBlockX()); - int minz = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - int maxz = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - // Try 10 times - for (int i = 0; i<10; i++) { - int x = Greenhouses.randInt(minx,maxx); - int z = Greenhouses.randInt(minz,maxz); - Block h = getHighestBlockInGreenhouse(x,z); - Block b = h.getRelative(BlockFace.DOWN); - Block a = h.getRelative(BlockFace.UP); - plugin.logger(3,"block found " + h.getType().toString()); - plugin.logger(3,"below found " + b.getType().toString()); - plugin.logger(3,"above found " + a.getType().toString()); - if ((b.getType().equals(type) && h.getType().equals(Material.AIR)) - || (h.getType().equals(type) && a.getType().equals(Material.AIR)) ) { - Location midBlock = new Location(world, h.getLocation().getX()+0.5D, h.getLocation().getY(), h.getLocation().getZ()+0.5D); - Entity e = world.spawnEntity(midBlock, mob); - if (e != null) - plugin.logger(1,"Spawned a "+ Util.prettifyText(mob.toString()) + " on "+ Util.prettifyText(type.toString()) + " at " - + midBlock.getBlockX() + "," + midBlock.getBlockY() + "," + midBlock.getBlockZ()); - break; - } - } - for (Pair pair: chunkSet) { - world.unloadChunkRequest(pair.getLeft(), pair.getRight()); - } - } - - /** - * Lay down snow in the greenhouse - */ - public void snow() { - // Lay down snow and ice - List waterToIceBlocks = new ArrayList(); - long water = 0; - int minx = Math.min(pos1.getBlockX(), pos2.getBlockX()); - int maxx = Math.max(pos1.getBlockX(), pos2.getBlockX()); - int minz = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - int maxz = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - for (int x = minx+1; x < maxx; x++) { - for (int z = minz+1; z < maxz;z++) { - Block b = getHighestBlockInGreenhouse(x,z); - // Display snow particles in air above b and count water blocks - for (int y = pos1.getBlockY(); y < heightY; y++) { - Block airCheck = world.getBlockAt(x, y, z); - if (airCheck.getType().equals(Material.AIR)) { - //).display(0F,0F,0F, 0.1F, 5, - //ParticleEffects.SNOWBALL.send(Bukkit.getOnlinePlayers(),airCheck.getLocation(),0D,0D,0D,1F,5,20); - world.spawnParticle(Particle.SNOWBALL, airCheck.getLocation(), 5); - } else if (airCheck.getType().equals(Material.WATER)) { - water++; - } - } - Block belowB = b.getRelative(BlockFace.DOWN); - if (Math.random() 0) { - waterToIceBlocks.add(belowB); - } else { - belowB.setType(Material.ICE); - } - } else if (belowB.getType().equals(Material.SNOW)) { - Snow snow = (Snow)belowB.getBlockData(); - // Increment snow layers - snow.setLayers(Math.min(snow.getLayers() + 1, snow.getMaximumLayers())); - } else if (b.getType().equals(Material.AIR)) { - // Don't put snow on liquids or snow... - if (!belowB.isLiquid() && !belowB.getType().equals(Material.SNOW)) - b.setType(Material.SNOW); - } - } - } - } - plugin.logger(3,"water = " + water); - if (biomeRecipe.getWaterCoverage() > 0 && water >0) { - plugin.logger(3,"water coverage required = " + biomeRecipe.getWaterCoverage()); - // Check if ice can be made - for (Block toIce: waterToIceBlocks) { - plugin.logger(3,"water ratio = " + ((double)(water-1)/(double)area * 100)); - if (((double)(water-1)/(double)area * 100) > biomeRecipe.getWaterCoverage()) { - toIce.setType(Material.ICE); - water--; - } else { - plugin.logger(3,"no more ice allowed"); - break; - } - } - } - } - - public void growFlowers() { - if (biomeRecipe == null) { - return; - } - Location hopper = roofHopperLocation; - if (hopper != null) { - plugin.logger(3,"Hopper location:" + hopper.toString()); - Block b = hopper.getBlock(); - // Check the hopper is still there - if (b.getType().equals(Material.HOPPER)) { - Hopper h = (Hopper)b.getState(); - plugin.logger(3,"Hopper found!"); - // Check what is in the hopper - if (h.getInventory().contains(Material.BONE_MEAL)) { - int total = h.getInventory().all(Material.BONE_MEAL).values().stream().mapToInt(ItemStack::getAmount).sum(); - // We need one bonemeal for each flower made - if (total > 0) { - /* - ItemStack remBoneMeal = new ItemStack(Material.INK_SACK); - remBoneMeal.setDurability((short)15); - remBoneMeal.setAmount(1); - */ - // Rewrite to use on bonemeal per flower - plugin.logger(3,"Bonemeal found! Amount = " + total); - // Now go and grow stuff with the set probability - int minx = Math.min(pos1.getBlockX(), pos2.getBlockX()); - int maxx = Math.max(pos1.getBlockX(), pos2.getBlockX()); - int minz = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - int maxz = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - for (int x = minx+1; x < maxx; x++) { - for (int z = minz+1; z < maxz;z++) { - Block bl = getHighestBlockInGreenhouse(x,z); - //if (Math.random() 0 && biomeRecipe.growPlant(bl)) { - total --; - plugin.logger(3,"Grew plant, spraying bonemeal"); - // Spray the bonemeal - for (int y = bl.getLocation().getBlockY(); y< heightY; y++) { - Block airCheck = world.getBlockAt(x, y, z); - if (airCheck.getType().equals(Material.AIR)) { - world.spawnParticle(Particle.EXPLOSION_NORMAL, airCheck.getLocation(), 5); - //ParticleEffects.EXPLOSION_NORMAL.send(Bukkit.getOnlinePlayers(),airCheck.getLocation(),0D,0D,0D,1F,5,20); - //ParticleEffect.EXPLOSION_NORMAL.display(0F,0F,0F, 0.1F, 5, airCheck.getLocation(), 30D); - } - } - } - } - } - plugin.logger(3,"Bonemeal left = " + total); - // Remove the bonemeal from the hopper - h.getInventory().remove(Material.BONE_MEAL); - h.getInventory().addItem(new ItemStack(Material.BONE_MEAL, total)); - } - } - } else { - // Greenhouse is broken or no longer has a hopper when it should - // TODO remove the greenhouse - plugin.logger(3,"Hopper is not there anymore..."); - } - } - } - - - /** - * Converts blocks in the greenhouse over time at a random rate - * Depends on the biome recipe - */ - public void convertBlocks() { - if (biomeRecipe == null) { - return; - } - if (biomeRecipe.getBlockConvert()) { - // Check biome recipe - int minx = Math.min(pos1.getBlockX(), pos2.getBlockX()); - int maxx = Math.max(pos1.getBlockX(), pos2.getBlockX()); - int minz = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); - int maxz = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); - for (int x = minx+1; x < maxx; x++) { - for (int z = minz+1; z < maxz;z++) { - for (int y = groundY; y < heightY; y++) { - biomeRecipe.convertBlock(world.getBlockAt(x,y,z)); - } - } - } - } - } - /** - * Replaces the getHighestBlock function by only looking within a greenhouse - * @param x - * @param z - * @return Non-solid block just above the highest solid block at x,z - should always be AIR - */ - public Block getHighestBlockInGreenhouse(int x, int z) { - Block bl = world.getBlockAt(x,heightY,z).getRelative(BlockFace.DOWN); - while (bl.getLocation().getBlockY() >= groundY && bl.isEmpty()) { - bl = bl.getRelative(BlockFace.DOWN); - } - return bl.getRelative(BlockFace.UP); - } -} diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/Roof.java b/src/main/java/world/bentobox/greenhouses/greenhouse/Roof.java index dc3eb2e..2013b3f 100644 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/Roof.java +++ b/src/main/java/world/bentobox/greenhouses/greenhouse/Roof.java @@ -2,6 +2,7 @@ package world.bentobox.greenhouses.greenhouse; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.bukkit.Location; import org.bukkit.Material; @@ -9,27 +10,33 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.util.Vector; -import world.bentobox.greenhouses.Greenhouses; - /** * Contains the parameters of a greenhouse roof * @author tastybento * */ public class Roof { + private final Location location; private int minX; private int maxX; private int minZ; private int maxZ; private int height; private boolean roofFound; - private final static List ROOFBLOCKS = Arrays.asList("GLASS","STAINED_GLASS","HOPPER","TRAP_DOOR","IRON_TRAPDOOR","GLOWSTONE"); - + public final static List ROOFBLOCKS = Arrays.stream(Material.values()) + .filter(Material::isBlock) // Blocks only, no items + .filter(m -> !m.name().contains("DOOR")) // No doors + .filter(m -> m.name().contains("TRAPDOOR") // All trapdoors + || m.name().contains("GLASS") // All glass blocks + || m.equals(Material.HOPPER) // Hoppers + || m.equals(Material.GLOWSTONE)) // Glowstone + .collect(Collectors.toList()); /** * Finds a roof from a starting location under the roof and characterizes it * @param loc */ - public Roof(Greenhouses plugin, Location loc) { + public Roof(Location loc) { + this.location = loc; World world = loc.getWorld(); // This section tries to find a roof block // Try just going up - this covers every case except if the player is standing under a hole @@ -43,18 +50,18 @@ public class Roof { for (int radius = 0; radius < 100; radius++) { for (int x = loc.getBlockX() - radius; x <= loc.getBlockX() + radius; x++) { for (int z = loc.getBlockZ() - radius; z <= loc.getBlockZ() + radius; z++) { - if (!((x > loc.getBlockX() - radius && x < loc.getBlockX() + radius) + if (!((x > loc.getBlockX() - radius && x < loc.getBlockX() + radius) && (z > loc.getBlockZ() - radius && z < loc.getBlockZ() + radius))) { //player.sendBlockChange(new Location(world,x,roofY,z), Material.GLASS, (byte)(radius % 14)); Block b = world.getBlockAt(x,roofY,z); - plugin.logger(3,"Checking column " + x + " " + z ); + //plugin.logger(3,"Checking column " + x + " " + z ); if (!Walls.isWallBlock(b.getType())) { // Look up for (int y = roofY; y < world.getMaxHeight(); y++) { - if (ROOFBLOCKS.contains(world.getBlockAt(x,y,z).getType().name())) { + if (ROOFBLOCKS.contains(world.getBlockAt(x,y,z).getType())) { roofFound = true; loc = new Location(world,x,y,z); - plugin.logger(3,"Roof block found at " + x + " " + y + " " + z + " of type " + loc.getBlock().getType().toString()); + //plugin.logger(3,"Roof block found at " + x + " " + y + " " + z + " of type " + loc.getBlock().getType().toString()); break; } } @@ -87,10 +94,10 @@ public class Roof { int maxz = maxZ; // Now we have some idea of the mins and maxes, check each block and see if it goes further do { - plugin.logger(3, "Roof minx=" + minx); - plugin.logger(3, "Roof maxx=" + maxx); - plugin.logger(3, "Roof minz=" + minz); - plugin.logger(3, "Roof maxz=" + maxz); + //plugin.logger(3, "Roof minx=" + minx); + //plugin.logger(3, "Roof maxx=" + maxx); + //plugin.logger(3, "Roof minz=" + minz); + //plugin.logger(3, "Roof maxz=" + maxz); minx = minX; maxx = maxX; minz = minZ; @@ -118,7 +125,7 @@ public class Roof { Location maxz = height.clone(); Location minz = height.clone(); int limit = 0; - while (ROOFBLOCKS.contains(maxx.getBlock().getType().name()) && limit < 100) { + while (ROOFBLOCKS.contains(maxx.getBlock().getType()) && limit < 100) { limit++; maxx.add(new Vector(1,0,0)); } @@ -126,7 +133,7 @@ public class Roof { maxX = maxx.getBlockX()-1; } - while (ROOFBLOCKS.contains(minx.getBlock().getType().name()) && limit < 200) { + while (ROOFBLOCKS.contains(minx.getBlock().getType()) && limit < 200) { limit++; minx.subtract(new Vector(1,0,0)); } @@ -134,15 +141,15 @@ public class Roof { minX = minx.getBlockX() + 1; } - while (ROOFBLOCKS.contains(maxz.getBlock().getType().name()) && limit < 300) { + while (ROOFBLOCKS.contains(maxz.getBlock().getType()) && limit < 300) { limit++; maxz.add(new Vector(0,0,1)); - } + } if (maxz.getBlockZ() - 1 > maxZ) { maxZ = maxz.getBlockZ() - 1; } - while (ROOFBLOCKS.contains(minz.getBlock().getType().name()) && limit < 400) { + while (ROOFBLOCKS.contains(minz.getBlock().getType()) && limit < 400) { limit++; minz.subtract(new Vector(0,0,1)); } @@ -221,14 +228,19 @@ public class Roof { } /** - * Check if roof block - * @param blockType - * @return true if this is a roof block + * @return the location */ - public boolean isRoofBlock(Material blockType) { - if (ROOFBLOCKS.contains(blockType.name())) { - return true; - } - return false; + public Location getLocation() { + return location; + } + + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Roof [location=" + location + ", minX=" + minX + ", maxX=" + maxX + ", minZ=" + minZ + ", maxZ=" + maxZ + + ", height=" + height + ", roofFound=" + roofFound + "]"; } } diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/Walls.java b/src/main/java/world/bentobox/greenhouses/greenhouse/Walls.java index 285f876..5d12652 100644 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/Walls.java +++ b/src/main/java/world/bentobox/greenhouses/greenhouse/Walls.java @@ -8,9 +8,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; - -import world.bentobox.greenhouses.Greenhouses; public class Walls { private int minX; @@ -22,8 +19,7 @@ public class Walls { private boolean useRoofMinX; private boolean useRoofMaxZ; private boolean useRoofMinZ; - private Location roofBlock; - Location roofHopperLoc = null; + public final static List WALL_BLOCKS = Arrays.stream(Material.values()) .filter(Material::isBlock) // Blocks only, no items .filter(m -> !m.name().contains("TRAPDOOR")) // No trapdoors @@ -33,11 +29,11 @@ public class Walls { || m.equals(Material.GLOWSTONE)) // Glowstone .collect(Collectors.toList()); - public Walls(Greenhouses addon, final Player player, Roof roof) { + public Walls(Roof roof) { // The player is under the roof // Assume the player is inside the greenhouse they are trying to create - Location loc = player.getLocation(); - World world = player.getWorld(); + Location loc = roof.getLocation(); + World world = roof.getLocation().getWorld(); // Find the floor - defined as the last y under the roof where there are no wall blocks int wallBlockCount = 0; int y = roof.getHeight(); @@ -53,7 +49,7 @@ public class Walls { } while( y-- > 0 && wallBlockCount > 0); floor = y + 1; - addon.logger(3,"#1 Floor found at " + floor); + //addon.logger(3,"#1 Floor found at " + floor); // Now start with the player's x and z location int radiusMinX = 0; int radiusMaxX = 0; @@ -67,17 +63,7 @@ public class Walls { maxX = loc.getBlockX(); minZ = loc.getBlockZ(); maxZ = loc.getBlockZ(); - addon.logger(3,"Starting point = " + loc.getBlockX() + "," + loc.getBlockZ()); - addon.logger(3,"roof minX = " + roof.getMinX()); - addon.logger(3,"roof maxX = " + roof.getMaxX()); - addon.logger(3,"roof minZ = " + roof.getMinZ()); - addon.logger(3,"roof maxZ = " + roof.getMaxZ()); do { - addon.logger(3,"wall radiusminX = " + radiusMinX); - addon.logger(3,"wall radius maxX = " + radiusMaxX); - addon.logger(3,"wall radius minZ = " + radiusMinZ); - addon.logger(3,"wall radius maxZ = " + radiusMaxZ); - // Look around player in an ever expanding cube minX = loc.getBlockX() - radiusMinX; maxX = loc.getBlockX() + radiusMaxX; @@ -89,7 +75,6 @@ public class Walls { for (int z = minZ; z <= maxZ; z++) { // Only look around outside edge if (!((x > minX && x < maxX) && (z > minZ && z < maxZ))) { - addon.logger(3,"Checking block " + x + " " + y + " " + z); // Look at block faces for (BlockFace bf: BlockFace.values()) { switch (bf) { @@ -97,28 +82,24 @@ public class Walls { // positive x if (WALL_BLOCKS.contains(world.getBlockAt(x, y, z).getRelative(bf).getType())) { stopMaxX = true; - addon.logger(3,"Wall found, stopping MaxX"); } break; case WEST: // negative x if (WALL_BLOCKS.contains(world.getBlockAt(x, y, z).getRelative(bf).getType())) { stopMinX = true; - addon.logger(3,"Wall found, stopping minX"); } break; case NORTH: // negative Z if (WALL_BLOCKS.contains(world.getBlockAt(x, y, z).getRelative(bf).getType())) { stopMinZ = true; - addon.logger(3,"Wall found, stopping minZ"); } break; case SOUTH: // positive Z if (WALL_BLOCKS.contains(world.getBlockAt(x, y, z).getRelative(bf).getType())) { stopMaxZ = true; - addon.logger(3,"Wall found, stopping maxZ"); } break; default: @@ -130,19 +111,15 @@ public class Walls { } } if (minX < roof.getMinX()) { - addon.logger(3,"minx is less that the roof minX"); stopMinX = true; } if (maxX > roof.getMaxX()) { - addon.logger(3,"maxx is > that the roof minX"); stopMaxX = true; } if (minZ < roof.getMinZ()) { - addon.logger(3,"minz is less that the roof minz"); stopMinZ = true; } if (maxZ > roof.getMaxZ()) { - addon.logger(3,"maxZ is >t the roof maxZ"); stopMaxZ = true; } // Expand the edges @@ -164,11 +141,6 @@ public class Walls { maxX++; minZ--; maxZ++; - addon.logger(3,"wall minX = " + minX); - addon.logger(3,"wall maxX = " + maxX); - addon.logger(3,"wall minZ = " + minZ); - addon.logger(3,"wall maxZ = " + maxZ); - // Find the floor again, only looking within the walls y = roof.getHeight(); do { @@ -183,8 +155,6 @@ public class Walls { } while( y-- > 0 && wallBlockCount > 0); floor = y + 1; - addon.logger(3,"#2 floor = " + floor); - } /** @@ -247,20 +217,6 @@ public class Walls { return (maxX - minX) * (maxZ - minZ); } - /** - * @return the roofBlock - */ - public Location getRoofBlock() { - return roofBlock; - } - - /** - * @return the roofHopperLoc - */ - public Location getRoofHopperLoc() { - return roofHopperLoc; - } - /** * @return the floor */ diff --git a/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseEvents.java b/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseEvents.java index e1a3a9a..515c4ef 100644 --- a/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseEvents.java +++ b/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseEvents.java @@ -1,15 +1,11 @@ package world.bentobox.greenhouses.listeners; -import java.util.ArrayList; -import java.util.List; +import java.util.Optional; -import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.World.Environment; -import org.bukkit.block.Biome; -import org.bukkit.entity.Player; +import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -18,12 +14,12 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import world.bentobox.bentobox.api.user.User; import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.Settings; -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.ui.Locale; -import world.bentobox.greenhouses.util.Util; +import world.bentobox.greenhouses.data.Greenhouse; /** * @author tastybento @@ -31,7 +27,6 @@ import world.bentobox.greenhouses.util.Util; */ public class GreenhouseEvents implements Listener { private final Greenhouses plugin; - private List blockedPistons = new ArrayList(); public GreenhouseEvents(final Greenhouses plugin) { this.plugin = plugin; @@ -43,208 +38,103 @@ public class GreenhouseEvents implements Listener { * @param event */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled=true) - public void onPlayerInteract(PlayerInteractEvent event){ - Player player = event.getPlayer(); - World world = player.getWorld(); - // Check we are in the right world - if (!world.getEnvironment().equals(Environment.NETHER) || !Settings.worldName.contains(world.getName())) { + public void onPlayerInteract(PlayerInteractEvent e) { + if (!e.getPlayer().getWorld().getEnvironment().equals(World.Environment.NETHER)) { return; } - if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { - Biome biome = event.getClickedBlock().getBiome(); - if (event.getItem() != null && biome != null) { - // Allow pouring of water if biome is okay - if (event.getItem().getType().equals(Material.WATER_BUCKET) && !biome.equals(Biome.NETHER) - && !biome.equals(Biome.DESERT) && !biome.equals(Biome.DESERT_HILLS)) { - event.setCancelled(true); - event.getClickedBlock().getRelative(event.getBlockFace()).setType(Material.WATER); - } - } + if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK) && e.getItem() != null && e.getItem().getType().equals(Material.WATER_BUCKET)) { + e.setCancelled(true); + e.getClickedBlock().getRelative(e.getBlockFace()).setType(Material.WATER); + e.getItem().setType(Material.BUCKET); } } /** * Makes water in the Nether if ice is broken and in a greenhouse - * @param event + * @param e - event */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled=true) - public void onIceBreak(BlockBreakEvent event){ - Player player = event.getPlayer(); - World world = player.getWorld(); - // Check we are in the right world - if (!Settings.worldName.contains(world.getName())) { + public void onIceBreak(BlockBreakEvent e) { + if (!e.getBlock().getWorld().getEnvironment().equals(World.Environment.NETHER) + || (!e.getBlock().getType().equals(Material.ICE) && !e.getBlock().getType().equals(Material.BLUE_ICE))) { return; } - Biome biome = event.getBlock().getBiome(); - // Set to water if the biome is okay. - if(event.getBlock().getWorld().getEnvironment() == Environment.NETHER && event.getBlock().getType() == Material.ICE - && !biome.equals(Biome.NETHER) && !biome.equals(Biome.DESERT) && !biome.equals(Biome.DESERT_HILLS)) { - event.setCancelled(true); - event.getBlock().setType(Material.WATER); - } + if (plugin.getManager().getMap().getGreenhouse(e.getBlock().getLocation()).isPresent()) { + e.setCancelled(true); + e.getBlock().setType(Material.WATER); + }; } /** * Tracks player movement - * @param event + * @param e - event */ - /* - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true) - public void onPlayerMove(PlayerMoveEvent event) { - //plugin.logger(3,event.getEventName()); - Player player = event.getPlayer(); - UUID uuid = player.getUniqueId(); - if (plugin.getPlayerGHouse(uuid) == null || plugin.getPlayerGHouse(uuid).isEmpty()) { - return; - } - World world = player.getWorld(); - // Check we are in the right world - if (!Settings.worldName.contains(world.getName())) { - plugin.logger(4,"Not in a Greenhouse world"); - return; - } - // Did we move a block? - if (event.getFrom().getBlockX() != event.getTo().getBlockX() - || event.getFrom().getBlockY() != event.getTo().getBlockY() - || event.getFrom().getBlockZ() != event.getTo().getBlockZ()) { - boolean result = checkMove(player, event.getFrom(), event.getTo(), uuid); - if (result) { - Location newLoc = event.getFrom(); - newLoc.setX(newLoc.getBlockX() + 0.5); - newLoc.setY(newLoc.getBlockY()); - newLoc.setZ(newLoc.getBlockZ() + 0.5); - event.setTo(newLoc); - } - } + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onPlayerMove(PlayerMoveEvent e) { + handleTransition(User.getInstance(e.getPlayer()), e.getTo(), e.getFrom()); } + private void handleTransition(User user, Location toLoc, Location fromLoc) { + Optional to = plugin.getManager().getMap().getGreenhouse(toLoc); + Optional from = plugin.getManager().getMap().getGreenhouse(fromLoc); + if (!to.isPresent() && !from.isPresent()) { + return; + } + if (to.isPresent() && from.isPresent() && to.equals(from)) { + // Same greenhouse + return; + } + // to is a greenhouse + if (to.isPresent() && from.isPresent() && !to.equals(from)) { + // Leaving greenhouse, entering another + user.sendRawMessage("Leaving " + to.get().getBiomeRecipe().getFriendlyName() + " greenhouse"); + user.sendRawMessage("Entering " + from.get().getBiomeRecipe().getFriendlyName() + " greenhouse"); + return; + } + // from is a greenhouse + if (from.isPresent() && !to.isPresent()) { + // Exiting + user.sendRawMessage("Leaving " + to.get().getBiomeRecipe().getFriendlyName() + " greenhouse"); + return; + } + if (!from.isPresent() && to.isPresent()) { + // Entering + user.sendRawMessage("Entering " + from.get().getBiomeRecipe().getFriendlyName() + " greenhouse"); + return; + } - @EventHandler(priority = EventPriority.HIGH) - public void onPlayerTeleport(PlayerTeleportEvent event) { + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onPlayerTeleport(PlayerTeleportEvent e) { // Strangely, sometimes these worlds can be null - if (event.getFrom() == null || event.getTo() == null) { + if (e.getFrom() == null || e.getTo() == null) { return; } - // Check if they changed worlds - UUID uuid = event.getPlayer().getUniqueId(); - if (plugin.getPlayerGHouse(uuid) == null || plugin.getPlayerGHouse(uuid).isEmpty()) { - return; - } - - World fromWorld = event.getFrom().getWorld(); - World toWorld = event.getTo().getWorld(); - // Check we are in the right world - if (!Settings.worldName.contains(fromWorld.getName()) && !Settings.worldName.contains(toWorld.getName())) { - return; - } - // Did we move a block? - checkMove(event.getPlayer(), event.getFrom(), event.getTo(), uuid); + handleTransition(User.getInstance(e.getPlayer()), e.getTo(), e.getFrom()); } - */ - /** - * @param player - * @param from - * @param to - * @return false if the player can move into that area, true if not allowed - */ - /* - private boolean checkMove(Player player, Location from, Location to, UUID uuid) { - Greenhouse fromGreenhouse = null; - Greenhouse toGreenhouse= null; - if (plugin.getGreenhouses().isEmpty()) { - // No greenhouses yet - return false; - } - plugin.logger(4,"Checking greenhouses"); - plugin.logger(4,"From : " + from.toString()); - plugin.logger(4,"From: " + from.getBlockX() + "," + from.getBlockZ()); - plugin.logger(4,"To: " + to.getBlockX() + "," + to.getBlockZ()); - for (Greenhouse d: plugin.getPlayerGHouse(uuid)) { - plugin.logger(4,"Greenhouse (" + d.getPos1().getBlockX() + "," + d.getPos1().getBlockZ() + " : " + d.getPos2().getBlockX() + "," + d.getPos2().getBlockZ() + ")"); - if (d.insideGreenhouse(to)) { - plugin.logger(4,"To intersects d!"); - toGreenhouse = d; - } - if (d.insideGreenhouse(from)) { - plugin.logger(4,"From intersects d!"); - fromGreenhouse = d; - } - } - // No greenhouse interaction - if (fromGreenhouse == null && toGreenhouse == null) { - // Clear the greenhouse flag (the greenhouse may have been deleted while they were offline) - plugin.players.setInGreenhouse(player, null); - return false; - } else if (fromGreenhouse == toGreenhouse) { - // Set the greenhouse - needs to be done if the player teleports too (should be done on a teleport event) - plugin.players.setInGreenhouse(player, toGreenhouse); - return false; - } - if (fromGreenhouse != null && toGreenhouse == null) { - // leaving a greenhouse - if (!fromGreenhouse.getFarewellMessage().isEmpty()) { - player.sendMessage(fromGreenhouse.getFarewellMessage()); - } - plugin.players.setInGreenhouse(player, null); - //if (plugin.players.getNumberInGreenhouse(fromGreenhouse) == 0) { - // fromGreenhouse.Æ’(); - //} - } else if (fromGreenhouse == null && toGreenhouse != null){ - // Going into a greenhouse - if (!toGreenhouse.getEnterMessage().isEmpty()) { - player.sendMessage(toGreenhouse.getEnterMessage()); - - //plugin.visualize(toGreenhouse, player); - } - toGreenhouse.startBiome(false); - plugin.players.setInGreenhouse(player, toGreenhouse); - - } else if (fromGreenhouse != null && toGreenhouse != null){ - // Leaving one greenhouse and entering another greenhouse immediately - if (!fromGreenhouse.getFarewellMessage().isEmpty()) { - player.sendMessage(fromGreenhouse.getFarewellMessage()); - } - plugin.players.setInGreenhouse(player, toGreenhouse); - //if (plugin.players.getNumberInGreenhouse(fromGreenhouse) == 0) { - //fromGreenhouse.endBiome(); - //} - toGreenhouse.startBiome(false); - if (!toGreenhouse.getEnterMessage().isEmpty()) { - player.sendMessage(toGreenhouse.getEnterMessage()); - } - } - return false; - } - */ - /** * Checks is broken blocks cause the greenhouse to fail * @param e */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled=true) public void onBlockBreak(final BlockBreakEvent e) { - if (!Settings.worldName.contains(e.getPlayer().getWorld().getName())) { - return; - } - plugin.logger(3,"block break"); - // Get the greenhouse that this block is in (if any) - Greenhouse g = plugin.getInGreenhouse(e.getBlock().getLocation()); - - if (g == null) { - // Not in a greenhouse - plugin.logger(3,"not in greenhouse"); - return; - } - // Check to see if this causes the greenhouse to break - if ((e.getBlock().getLocation().getBlockY() == g.getHeightY()) || (g.isAWall(e.getBlock().getLocation()))) { - e.getPlayer().sendMessage(ChatColor.RED + Locale.eventbroke.replace("[biome]",Util.prettifyText(g.getOriginalBiome().toString()))); - e.getPlayer().sendMessage(ChatColor.RED + Locale.eventfix); - plugin.removeGreenhouse(g); - return; - } + User user = User.getInstance(e.getPlayer()); + plugin.getManager().getMap().getGreenhouse(e.getBlock().getLocation()).ifPresent(g -> { + // Check to see if wall or roof block broken + if ((e.getBlock().getLocation().getBlockY() == g.getCeilingHeight()) + || e.getBlock().getLocation().getBlockX() == g.getFootprint().getMinX() + || e.getBlock().getLocation().getBlockX() == g.getFootprint().getMaxX() + || e.getBlock().getLocation().getBlockZ() == g.getFootprint().getMinY() + || e.getBlock().getLocation().getBlockZ() == g.getFootprint().getMaxY() + ) { + user.sendMessage("greenhouses.broken"); + plugin.getManager().getMap().removeGreenhouse(g); + } + }); } /** @@ -253,67 +143,28 @@ public class GreenhouseEvents implements Listener { */ @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true) public void onPlayerBlockPlace(final BlockPlaceEvent e) { - if (!Settings.worldName.contains(e.getPlayer().getWorld().getName())) { - return; + if (checkBlockHeight(e.getBlock())) { + e.setCancelled(true); + User user = User.getInstance(e.getPlayer()); + user.sendMessage("greenhouses.error.cannot-place"); } - if (e.getPlayer().getWorld().getEnvironment().equals(Environment.NETHER)) { - return; - } - // If the offending block is not above a greenhouse, forget it! - Greenhouse g = plugin.aboveAGreenhouse(e.getBlock().getLocation()); - if (g == null) { - return; - } - e.getPlayer().sendMessage(ChatColor.RED + Locale.eventcannotplace); - e.getPlayer().sendMessage("Greenhouse is at " + g.getPos1() + " to " + g.getPos2()); - e.setCancelled(true); + } + + private boolean checkBlockHeight(Block block) { + return plugin.getManager().getMap().getGreenhouse(block.getLocation()) + .filter(g -> g.getCeilingHeight() < block.getY()) + .filter(g -> !block.getWorld().getEnvironment().equals(World.Environment.NETHER)) + .isPresent(); + } /** * Check to see if anyone is sneaking a block over a greenhouse by using a piston * @param e */ - @EventHandler + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true) public void onPistonPush(final BlockPistonExtendEvent e) { - if (!Settings.worldName.contains(e.getBlock().getWorld().getName())) { - return; - } - if (e.getBlock().getWorld().getEnvironment().equals(Environment.NETHER)) { - return; - } - // Check if piston is already extended to avoid the double event effect - - Location l = e.getBlock().getLocation(); - if (blockedPistons.contains(l)) { - // Cancel the double call - blockedPistons.remove(l); - e.setCancelled(true); - return; - } - plugin.logger(3,"Direction: " + e.getDirection()); - plugin.logger(3,"Location of piston block:" + l); - // Pistons can push up to 12 blocks - find the end block + 1 - for (int i = 0; i < 13; i++) { - l = l.getBlock().getRelative(e.getDirection()).getLocation(); - if (!l.getBlock().getType().isSolid()) { - break; - } - } - plugin.logger(3,"Location of end block + 1:" + l); - // The end block location is now l - if (plugin.aboveAGreenhouse(l) == null) { - return; - } - // Find out who is around the piston - for (Player p : plugin.getServer().getOnlinePlayers()) { - if (Settings.worldName.contains(p.getLocation().getWorld().getName())) { - if (p.getLocation().distanceSquared(e.getBlock().getLocation()) <= 25) { - p.sendMessage(ChatColor.RED + Locale.eventpistonerror); - e.setCancelled(true); - blockedPistons.add(e.getBlock().getLocation()); - } - } - } + e.setCancelled(e.getBlocks().stream().anyMatch(this::checkBlockHeight)); } } diff --git a/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseGuard.java b/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseGuard.java index dc8d585..5bfc4a6 100644 --- a/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseGuard.java +++ b/src/main/java/world/bentobox/greenhouses/listeners/GreenhouseGuard.java @@ -1,55 +1,55 @@ package world.bentobox.greenhouses.listeners; +import java.util.Optional; + import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockFromToEvent; import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.Settings; -import world.bentobox.greenhouses.greenhouse.Greenhouse; +import world.bentobox.greenhouses.data.Greenhouse; public class GreenhouseGuard implements Listener { private final Greenhouses plugin; public GreenhouseGuard(final Greenhouses plugin) { - this.plugin = plugin; + this.plugin = plugin; } // Stop lava flow or water into or out of a greenhouse @EventHandler(priority = EventPriority.NORMAL) public void onFlow(final BlockFromToEvent e) { - // Flow may be allowed anyway - if (Settings.allowFlowIn && Settings.allowFlowOut) { - return; - } - if (!Settings.worldName.isEmpty() && !Settings.worldName.contains(e.getBlock().getWorld().getName())) { - return; - } - // Get To and From Districts - Greenhouse to = plugin.getInGreenhouse(e.getToBlock().getLocation()); - Greenhouse from = plugin.getInGreenhouse(e.getBlock().getLocation()); - // Scenarios - // 1. inside district or outside - always ok - // 2. inside to outside - allowFlowOut determines - // 3. outside to inside - allowFlowIn determines - if (to == null && from == null) { - return; - } - if (to !=null && from != null && to.equals(from)) { - return; - } - // to or from or both are districts, NOT the same and flow is across a boundary - // if to is a district, flow in is allowed - if (to != null && Settings.allowFlowIn) { - return; - } - // if from is a district, flow may allowed - if (from != null && Settings.allowFlowOut) { - return; - } - // Otherwise cancel - the flow is not allowed - e.setCancelled(true); + // Flow may be allowed anyway + if (plugin.getSettings().isAllowFlowIn() && plugin.getSettings().isAllowFlowOut()) { + return; + } + if (!plugin.getActiveWorlds().contains(e.getBlock().getWorld())) { + return; + } + // Get To and From + Optional to = plugin.getManager().getMap().getGreenhouse(e.getToBlock().getLocation()); + Optional from = plugin.getManager().getMap().getGreenhouse(e.getBlock().getLocation()); + // Scenarios + // 1. inside district or outside - always ok + // 2. inside to outside - allowFlowOut determines + // 3. outside to inside - allowFlowIn determines + if (!to.isPresent() && !from.isPresent()) { + return; + } + if (to.isPresent() && from.isPresent() && to.equals(from)) { + return; + } + // to is a greenhouse + if (to.isPresent() && plugin.getSettings().isAllowFlowIn()) { + return; + } + // from is a greenhouse + if (from.isPresent() && plugin.getSettings().isAllowFlowOut()) { + return; + } + // Otherwise cancel - the flow is not allowed + e.setCancelled(true); } diff --git a/src/main/java/world/bentobox/greenhouses/listeners/JoinLeaveEvents.java b/src/main/java/world/bentobox/greenhouses/listeners/JoinLeaveEvents.java deleted file mode 100644 index 616163a..0000000 --- a/src/main/java/world/bentobox/greenhouses/listeners/JoinLeaveEvents.java +++ /dev/null @@ -1,54 +0,0 @@ -package world.bentobox.greenhouses.listeners; - -import java.util.List; -import java.util.UUID; - -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.PlayerCache; -import world.bentobox.greenhouses.ui.Locale; - -public class JoinLeaveEvents implements Listener { - private Greenhouses addon; - private PlayerCache players; - - public JoinLeaveEvents(Greenhouses greenhouses, PlayerCache onlinePlayers) { - this.addon = greenhouses; - this.players = onlinePlayers; - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerJoin(final PlayerJoinEvent event) { - Player p = event.getPlayer(); - final UUID playerUUID = p.getUniqueId(); - // Add player to the cache, and clear any greenhouses over their permitted limit - addon.players.addPlayer(p); - addon.logger(3,"Cached " + p.getName()); - // Load any messages for the player - final List messages = addon.getMessages(playerUUID); - if (!messages.isEmpty()) { - addon.getServer().getScheduler().runTaskLater(addon.getPlugin(), () -> { - event.getPlayer().sendMessage(ChatColor.AQUA + Locale.newsheadline); - int i = 1; - for (String message : messages) { - event.getPlayer().sendMessage(i++ + ": " + message); - } - }, 40L); - } - } - - @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerQuit(final PlayerQuitEvent event) { - players.removeOnlinePlayer(event.getPlayer()); - } -} \ No newline at end of file diff --git a/src/main/java/world/bentobox/greenhouses/listeners/SnowTracker.java b/src/main/java/world/bentobox/greenhouses/listeners/SnowTracker.java new file mode 100644 index 0000000..9176e9e --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/listeners/SnowTracker.java @@ -0,0 +1,135 @@ +package world.bentobox.greenhouses.listeners; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Hopper; +import org.bukkit.block.data.type.Snow; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitTask; + +import world.bentobox.greenhouses.Greenhouses; +import world.bentobox.greenhouses.data.Greenhouse; + +/** + * Monitors the greenhouses and grows things, adds weather etc. + * @author tastybento + * + */ +public class SnowTracker implements Listener { + private final Greenhouses addon; + private final static List SNOWBIOMES = Arrays.stream(Biome.values()).filter(b -> b.name().contains("COLD") || b.name().contains("ICE") || b.name().contains("FROZEN")).collect(Collectors.toList()); + private Map snowTasks; + + public SnowTracker(Greenhouses addon) { + this.addon = addon; + snowTasks = new HashMap<>(); + // Start snow if ongoing + addon.getActiveWorlds().stream().filter(World::isThundering) + .forEach(w -> snowTasks.putIfAbsent(w, Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> shakeGlobes(w), 0L, 100L))); + + } + + @EventHandler + public void onWeatherChangeEvent(final WeatherChangeEvent e) { + if (!addon.getActiveWorlds().contains(e.getWorld())) { + return; + } + if (e.toWeatherState()) { + // It's raining + //addon.logger(3,"It's raining!"); + startSnow(e.getWorld()); + } else { + // It's stopped raining! + //addon.logger(3,"Stopped raining!"); + stopSnow(e.getWorld()); + } + } + + private void stopSnow(World world) { + if (snowTasks.containsKey(world)) { + snowTasks.get(world).cancel(); + snowTasks.remove(world); + } + } + + private void startSnow(World world) { + // Start timer + snowTasks.putIfAbsent(world, Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> shakeGlobes(world), 0L, 100L)); // every 5 seconds + } + + private void shakeGlobes(World world) { + addon.getManager().getMap().getGreenhouses().stream().filter(g -> SNOWBIOMES.contains(g.getBiomeRecipe().getBiome())) + .filter(g -> g.getLocation().getWorld().equals(world)) + .filter(g -> !g.isBroken()) + .filter(g -> g.getRoofHopperLocation() != null) + .filter(g -> g.getRoofHopperLocation().getBlock().getType().equals(Material.HOPPER)) + .filter(g -> ((Hopper)g.getRoofHopperLocation().getBlock()).getInventory().contains(Material.WATER_BUCKET)) + .forEach(this::removeWaterBucketAndShake); + } + + private void removeWaterBucketAndShake(Greenhouse g) { + Hopper h = ((Hopper)g.getRoofHopperLocation().getBlock()); + h.getInventory().removeItem(new ItemStack(Material.WATER_BUCKET)); + h.getInventory().addItem(new ItemStack(Material.BUCKET)); + // Scatter snow + getAirBlocks(g); + } + + private List getAirBlocks(Greenhouse gh) { + List waterBlocks = new ArrayList<>(); + List result = new ArrayList<>(); + for (int x = (int)gh.getFootprint().getMinX() + 1; x < (int)gh.getFootprint().getMaxX(); x++) { + for (int z = (int)gh.getFootprint().getMinY() + 1; z < (int)gh.getFootprint().getMaxY(); z++) { + for (int y = gh.getCeilingHeight() - 1; y >= gh.getFloorHeight(); y--) { + Block b = gh.getLocation().getWorld().getBlockAt(x, y, z); + if (b.getType().equals(Material.AIR)) { + b.getWorld().spawnParticle(Particle.SNOWBALL, b.getLocation(), 5); + } else { + // Add snow + if (b.getType().equals(Material.WATER)) { + waterBlocks.add(b); + } else { + // Not water + if (Math.random() < addon.getSettings().getSnowDensity() && !b.isLiquid()) { + addSnow(b); + } + } + + break; + } + } + } + } + // Check if any water blocks can be turned to ice + int maxSize = waterBlocks.size() - (gh.getArea() / gh.getBiomeRecipe().getWaterCoverage()); + if (maxSize > 0) { + waterBlocks.stream().limit(maxSize).filter(b -> Math.random() < addon.getSettings().getSnowDensity()).forEach(b -> b.setType(Material.ICE)); + } + return result; + } + + private void addSnow(Block b) { + Block above = b.getRelative(BlockFace.UP); + if (above.getType().equals(Material.SNOW) || above.getType().equals(Material.AIR)) { + above.setType(Material.SNOW); + Snow snow = (Snow)above; + snow.setLayers(Math.min(snow.getMaximumLayers(), snow.getLayers() + 1)); + } + } + +} \ No newline at end of file diff --git a/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java b/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java new file mode 100644 index 0000000..1ad11a7 --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java @@ -0,0 +1,164 @@ +package world.bentobox.greenhouses.managers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Hopper; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitTask; + +import world.bentobox.greenhouses.Greenhouses; +import world.bentobox.greenhouses.data.Greenhouse; + +/** + * Runs the ecosystem for a greenhouse + * @author tastybento + * + */ +public class EcoSystemManager { + + private Greenhouses addon; + private GreenhouseManager g; + private BukkitTask plantTask; + private BukkitTask mobTask; + private BukkitTask blockTask; + private BukkitTask ecoTask; + + public EcoSystemManager(Greenhouses addon, GreenhouseManager greenhouseManager) { + this.addon = addon; + this.g = greenhouseManager; + setup(); + } + + private void setup() { + // Kick off flower growing + long plantTick = addon.getSettings().getPlantTick() * 60 * 20; // In minutes + if (plantTick > 0) { + addon.log("Kicking off flower growing scheduler every " + addon.getSettings().getPlantTick() + " minutes"); + plantTask = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { + g.getMap().getGreenhouses().forEach(gh -> growPlants(gh)); + }, 80L, plantTick); + + } else { + addon.log("Flower growth disabled."); + } + + // Kick block conversion growing + long blockTick = addon.getSettings().getBlockTick() * 60 * 20; // In minutes + + if (blockTick > 0) { + addon.log("Kicking off block conversion scheduler every " + addon.getSettings().getBlockTick() + " minutes"); + blockTask = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { + addon.log("Servicing greenhouse biome"); + + + }, 60L, blockTick); + } else { + addon.log("Block conversion disabled."); + } + // Kick off g/h verification + long ecoTick = addon.getSettings().getEcoTick() * 60 * 20; // In minutes + if (ecoTick > 0) { + addon.log("Kicking off greenhouse verify scheduler every " + addon.getSettings().getEcoTick() + " minutes"); + ecoTask = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { + // Todo + }, ecoTick, ecoTick); + + } else { + addon.log("Greenhouse verification disabled."); + } + // Kick off mob population + long mobTick = addon.getSettings().getMobTick() * 60 * 20; // In minutes + if (mobTick > 0) { + addon.log("Kicking off mob populator scheduler every " + addon.getSettings().getMobTick() + " minutes"); + mobTask = addon.getServer().getScheduler().runTaskTimer(addon.getPlugin(), () -> { + }, 120L, mobTick); + + } else { + addon.log("Mob disabled."); + } + + } + + /** + * Growns plants in the greenhouse + * @param gh - greenhouse + */ + private void growPlants(Greenhouse gh) { + int bonemeal = getBoneMeal(gh); + if (bonemeal > 0) { + // Get a list of all available blocks + setBoneMeal(gh, bonemeal - getAvailableBlocks(gh).stream().limit(bonemeal).mapToInt(bl -> gh.getBiomeRecipe().growPlant(bl) ? 1 : 0).sum()); + } + + } + + /** + * Set a hopper's bone meal to this value + * @param gh - greenhouse + * @param value - value to set + */ + private void setBoneMeal(Greenhouse gh, int value) { + Hopper hopper = getHopper(gh); + if (hopper != null) { + hopper.getInventory().remove(Material.BONE_MEAL); + hopper.getInventory().addItem(new ItemStack(Material.BONE_MEAL, value)); + } + + } + + /** + * Get a list of the highest block inside the greenhouse + * @param gh - greenhouse + * @return List of blocks + */ + private List getAvailableBlocks(Greenhouse gh) { + List result = new ArrayList<>(); + for (int x = (int)gh.getFootprint().getMinX() + 1; x < (int)gh.getFootprint().getMaxX(); x++) { + for (int z = (int)gh.getFootprint().getMinY() + 1; z < (int)gh.getFootprint().getMaxY(); z++) { + for (int y = gh.getCeilingHeight() - 1; y >= gh.getFloorHeight(); y--) { + Block b = gh.getLocation().getWorld().getBlockAt(x, y, z); + if (!b.getType().equals(Material.AIR)) { + result.add(b); + break; + } + } + } + } + return result; + } + + private int getBoneMeal(Greenhouse gh) { + Hopper hopper = getHopper(gh); + if (hopper == null || !hopper.getInventory().contains(Material.BONE_MEAL)) { + return 0; + } + return Arrays.stream(hopper.getInventory().getContents()).filter(Objects::nonNull) + .filter(i -> i.getType().equals(Material.BONE_MEAL)) + .mapToInt(ItemStack::getAmount).sum(); + } + + private Hopper getHopper(Greenhouse gh) { + if (gh.getRoofHopperLocation() == null) { + return null; + } + // Check if there are any bonemeal in the hopper + if (gh.getRoofHopperLocation().getBlock().getType() != Material.HOPPER) { + gh.setRoofHopperLocation(null); + return null; + } + return (Hopper)gh.getRoofHopperLocation().getBlock().getBlockData(); + } + + public void cancel() { + plantTask.cancel(); + mobTask.cancel(); + blockTask.cancel(); + ecoTask.cancel(); + } + +} diff --git a/src/main/java/world/bentobox/greenhouses/managers/GreenhouseFinder.java b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseFinder.java new file mode 100644 index 0000000..5dcc9d6 --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseFinder.java @@ -0,0 +1,188 @@ +package world.bentobox.greenhouses.managers; + +import java.awt.Rectangle; +import java.util.HashSet; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.World.Environment; + +import world.bentobox.greenhouses.data.Greenhouse; +import world.bentobox.greenhouses.greenhouse.Roof; +import world.bentobox.greenhouses.greenhouse.Walls; +import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; + +public class GreenhouseFinder { + + private Greenhouse gh; + private Set redGlass = new HashSet(); + + + public Set find(Location location) { + Set result = new HashSet<>(); + redGlass.clear(); + + // Find the roof + Roof roof = new Roof(location); + if (!roof.isRoofFound()) { + result.add(GreenhouseResult.FAIL_NO_ROOF); + return result; + } + // Find the walls + Walls walls = new Walls(roof); + + // Make the initial greenhouse + gh = new Greenhouse(location.getWorld(), new Rectangle(walls.getMinX(), walls.getMinZ(), walls.getMaxX(), walls.getMaxZ()), walls.getFloor(), roof.getHeight()); + // Set the original biome + gh.setOriginalBiome(location.getBlock().getBiome()); + + // Now check again to see if the floor really is the floor and the walls follow the rules + World world = roof.getLocation().getWorld(); + int minX = walls.getMinX(); + int minZ = walls.getMinZ(); + int maxX = walls.getMaxX(); + int maxZ = walls.getMaxZ(); + + // Counts + int wallDoors = 0; + // Hoppers + int ghHopper = 0; + // Air + boolean airHoles = false; + // Other blocks + boolean otherBlocks = false; + // Ceiling issue + boolean inCeiling = 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; + + int y = 0; + for (y = world.getMaxHeight() - 1; y >= walls.getFloor(); y--) { + int doorCount = 0; + int hopperCount = 0; + boolean airHole = false; + boolean otherBlock = 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()) { + // We are above the greenhouse + if ((world.getEnvironment().equals(Environment.NORMAL) || world.getEnvironment().equals(Environment.THE_END)) + && blockType != Material.AIR) { + result.add(GreenhouseResult.FAIL_BLOCKS_ABOVE); + redGlass.add(thisBlock); + } + } else { + // Check just the walls + if (y == roof.getHeight() || x == minX || x == maxX || z == minZ || z== maxZ) { + //Greenhouses.addon.logDebug("DEBUG: Checking " + x + " " + y + " " + z); + if ((y != roof.getHeight() && !Walls.WALL_BLOCKS.contains(blockType)) + || (y == roof.getHeight() && !Roof.ROOFBLOCKS.contains(blockType))) { + //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; + } + redGlass.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) { + redGlass.add(thisBlock); + } + } + if (blockType.equals(Material.HOPPER)) { + hopperCount++; + if (ghHopper > 0) { + // Problem! Add extra hoppers to the red glass list + redGlass.add(thisBlock); + } else { + // This is the first hopper + gh.setRoofHopperLocation(thisBlock); + } + } + } + } + } + } + } + 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; + } + } + } + } + //addon.logDebug("Floor is at height y = " + y); + // Check that the player is vertically in the greenhouse + if (roof.getLocation().getBlockY() <= y) { + result.add(GreenhouseResult.FAIL_BELOW); + } + // Show errors + if (airHoles & !inCeiling) { + result.add(GreenhouseResult.FAIL_HOLE_IN_WALL); + } else if (airHoles & inCeiling) { + result.add(GreenhouseResult.FAIL_HOLE_IN_ROOF); + } + //Greenhouses.addon.logDebug("DEBUG: otherBlockLayer = " + otherBlockLayer); + if (otherBlocks && otherBlockLayer == y + 1) { + // Walls must be even all the way around + result.add(GreenhouseResult.FAIL_UNEVEN_WALLS); + } else if (otherBlocks && otherBlockLayer == roof.getHeight()) { + // Roof blocks must be glass, glowstone, doors or a hopper. + result.add(GreenhouseResult.FAIL_BAD_ROOF_BLOCKS); + } else if (otherBlocks) { + // "Wall blocks must be glass, glowstone, doors or a hopper. + result.add(GreenhouseResult.FAIL_BAD_WALL_BLOCKS); + } + if (wallDoors > 8) { + result.add(GreenhouseResult.FAIL_TOO_MANY_DOORS); + } + if (ghHopper > 1) { + result.add(GreenhouseResult.FAIL_TOO_MANY_HOPPERS); + } + + return result; + } + + /** + * @return the gh + */ + public Greenhouse getGh() { + return gh; + } + + /** + * @return the redGlass + */ + public Set getRedGlass() { + return redGlass; + } + +} diff --git a/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java new file mode 100644 index 0000000..4a72942 --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseManager.java @@ -0,0 +1,195 @@ +package world.bentobox.greenhouses.managers; + +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; + +import world.bentobox.bentobox.database.Database; +import world.bentobox.greenhouses.Greenhouses; +import world.bentobox.greenhouses.data.Greenhouse; +import world.bentobox.greenhouses.greenhouse.BiomeRecipe; +import world.bentobox.greenhouses.managers.GreenhouseMap.AddResult; + +public class GreenhouseManager { + + // No result = success + public enum GreenhouseResult { + FAIL_NO_ROOF, + FAIL_BELOW, + FAIL_BLOCKS_ABOVE, + FAIL_HOLE_IN_WALL, + FAIL_HOLE_IN_ROOF, + FAIL_UNEVEN_WALLS, + FAIL_BAD_ROOF_BLOCKS, + FAIL_BAD_WALL_BLOCKS, + FAIL_TOO_MANY_DOORS, + FAIL_TOO_MANY_HOPPERS, + FAIL_NO_WATER, + FAIL_NO_LAVA, + FAIL_NO_ICE, + FAIL_INSUFFICIENT_WATER, + FAIL_INSUFFICIENT_LAVA, + FAIL_INSUFFICIENT_ICE + } + + private Greenhouses addon; + // Greenhouses + private GreenhouseMap map; + private Database handler; + + public GreenhouseManager(Greenhouses addon) { + this.addon = addon; + handler = new Database<>(addon, Greenhouse.class); + map = new GreenhouseMap(addon); + loadGreenhouses(); + // Start ecosystems + new EcoSystemManager(addon, this); + } + + public GreenhouseMap getMap() { + return map; + } + + /** + * Load all known greenhouses + */ + public void loadGreenhouses() { + addon.log("Loading greenhouses..."); + handler.loadObjects().forEach(g -> { + AddResult result = map.addGreenhouse(g); + switch (result) { + case FAIL_NO_ISLAND: + case FAIL_OVERLAPPING: + case NULL: + addon.logError(result.name()); + break; + case SUCCESS: + break; + default: + break; + + } + }); + addon.log("Loaded greenhouses."); + } + + /** + * Saves all the greenhouses to database + */ + public void saveGreenhouses() { + addon.log("Saving greenhouses..."); + map.getGreenhouses().forEach(handler::saveObject); + } + + /** + * Removes the greenhouse from the world and resets biomes + * @param g + */ + public void removeGreenhouse(Greenhouse g) { + map.removeGreenhouse(g); + addon.log("Returning biome to original state: " + g.getOriginalBiome().toString()); + if (g.getOriginalBiome().equals(Biome.NETHER) || g.getOriginalBiome().equals(Biome.DESERT) + || g.getOriginalBiome().equals(Biome.DESERT_HILLS)) { + for (int x = (int)g.getFootprint().getMinX(); x<= (int)g.getFootprint().getMaxX(); x++) { + for (int z = (int)g.getFootprint().getMinY(); z<= (int)g.getFootprint().getMinY(); z++) { + // Set back to the original biome + g.getLocation().getWorld().setBiome(x, z, g.getOriginalBiome()); + for (int y = g.getFloorHeight(); y< g.getCeilingHeight(); y++) { + Block b = g.getLocation().getWorld().getBlockAt(x, y, z); + // Remove any water + if (b.getType().equals(Material.WATER) || b.getType().equals(Material.BLUE_ICE) + || b.getType().equals(Material.FROSTED_ICE) + || 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); + b.getWorld().spawnParticle(Particle.SMOKE_LARGE, b.getLocation(), 5); + } + } + } + } + } + } + + + /** + * Checks that a greenhouse meets specs and makes it + * If type is stated then only this specific type will be checked + * @param user + * @param greenhouseRecipe + * @return + */ + public GhResult tryToMakeGreenhouse(Location location, BiomeRecipe greenhouseRecipe) { + addon.log("Player location is " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ()); + GreenhouseFinder finder = new GreenhouseFinder(); + Set resultSet = finder.find(location); + if (!resultSet.isEmpty()) { + // Failure! + return new GhResult().setFinder(finder).setResults(resultSet); + } + // Check if the greenhouse meets the requested recipe + if (greenhouseRecipe != null) { + resultSet = greenhouseRecipe.checkRecipe(finder.getGh()); + if (resultSet.isEmpty()) { + // Success - set recipe and add to map + finder.getGh().setBiomeRecipe(greenhouseRecipe); + map.addGreenhouse(finder.getGh()); + } + return new GhResult().setFinder(finder).setResults(resultSet); + } + // Try ordered recipes + addon.getRecipes().getBiomeRecipes().stream().sorted() + .filter(r -> r.checkRecipe(finder.getGh()).isEmpty()).findFirst() + .ifPresent(r -> { + // Success - set recipe and add to map + finder.getGh().setBiomeRecipe(r); + map.addGreenhouse(finder.getGh()); + }); + return new GhResult().setFinder(finder).setResults(resultSet); + } + + /** + * Result of the greenhouse make effort + * + */ + public class GhResult { + private Set results; + private GreenhouseFinder finder; + + /** + * @return the results + */ + public Set getResults() { + return results; + } + + /** + * @return the finder + */ + public GreenhouseFinder getFinder() { + return finder; + } + + /** + * @param results the results to set + */ + public GhResult setResults(Set results) { + this.results = results; + return this; + } + + /** + * @param finder the finder to set + */ + public GhResult setFinder(GreenhouseFinder finder) { + this.finder = finder; + return this; + } + + + } +} diff --git a/src/main/java/world/bentobox/greenhouses/managers/GreenhouseMap.java b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseMap.java new file mode 100644 index 0000000..37c7a9b --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/managers/GreenhouseMap.java @@ -0,0 +1,114 @@ +package world.bentobox.greenhouses.managers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.bukkit.Location; + +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.greenhouses.Greenhouses; +import world.bentobox.greenhouses.data.Greenhouse; + +public class GreenhouseMap { + + public enum AddResult { + SUCCESS, + FAIL_OVERLAPPING, + FAIL_NO_ISLAND, + NULL + } + private Greenhouses addon; + private Map> greenhouses = new HashMap<>(); + + /** + * @param addon - addon + */ + public GreenhouseMap(Greenhouses addon) { + this.addon = addon; + } + + /** + * Try to add a greenhouse + * @param greenhouse - greenhouse object + * @return {@link AddResult#SUCCESS}, {@link AddResult#FAIL_NO_ISLAND} or {@link AddResult#FAIL_OVERLAPPING} + */ + public AddResult addGreenhouse(Greenhouse greenhouse) { + if (greenhouse.getLocation() == null) { + return AddResult.NULL; + } + return addon.getIslands().getIslandAt(greenhouse.getLocation()).map(i -> { + greenhouses.putIfAbsent(i, new ArrayList<>()); + // Check if overlapping + if (!isOverlapping(greenhouse)) { + greenhouses.get(i).add(greenhouse); + return AddResult.SUCCESS; + } else { + return AddResult.FAIL_OVERLAPPING; + } + }).orElse(AddResult.FAIL_NO_ISLAND); + } + + /** + * Try to get greenhouse at location + * @param location - location + * @return Optional greenhouse or empty + */ + public Optional getGreenhouse(Location location) { + return getXZGreenhouse(location).filter(g -> location.getBlockY() <= g.getCeilingHeight() && location.getBlockY() >= g.getFloorHeight()); + } + + private Optional getXZGreenhouse(Location location) { + return addon.getIslands().getIslandAt(location).map(i -> { + greenhouses.putIfAbsent(i, new ArrayList<>()); + return greenhouses.get(i).stream().filter(g -> g.getFootprint().contains(location.getX(), location.getY())).findFirst(); + }).orElse(Optional.empty()); + } + + /** + * Check if location is inside a greenhouse + * @param location - location + * @return true if inside a greenhouse + */ + public boolean inGreenhouse(Location location) { + return getGreenhouse(location).isPresent(); + } + + /** + * Check if location is above a greenhouse + * @param location - location + * @return true if above a known greenhouse + */ + public boolean isAboveGreenhouse(Location location) { + return getXZGreenhouse(location).map(g -> location.getBlockY() > g.getCeilingHeight()).orElse(false); + } + + private boolean isOverlapping(Greenhouse greenhouse) { + return addon.getIslands().getIslandAt(greenhouse.getLocation()).map(i -> { + greenhouses.putIfAbsent(i, new ArrayList<>()); + return greenhouses.get(i).stream().anyMatch(g -> g.getFootprint().intersects(greenhouse.getFootprint())); + }).orElse(false); + + } + + /** + * Removes the greenhouse from the map + * @param greenhouse - greenhouse + */ + public void removeGreenhouse(Greenhouse greenhouse) { + addon.getIslands().getIslandAt(greenhouse.getLocation()).ifPresent(i -> { + greenhouses.putIfAbsent(i, new ArrayList<>()); + greenhouses.get(i).remove(greenhouse); + }); + } + + /** + * @return a list of all the Greenhouses + */ + public List getGreenhouses() { + return greenhouses.values().stream().flatMap(List::stream).collect(Collectors.toList()); + } +} diff --git a/src/main/java/world/bentobox/greenhouses/managers/RecipeManager.java b/src/main/java/world/bentobox/greenhouses/managers/RecipeManager.java new file mode 100644 index 0000000..41ad373 --- /dev/null +++ b/src/main/java/world/bentobox/greenhouses/managers/RecipeManager.java @@ -0,0 +1,186 @@ +package world.bentobox.greenhouses.managers; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.block.Biome; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.EntityType; + +import world.bentobox.greenhouses.Greenhouses; +import world.bentobox.greenhouses.greenhouse.BiomeRecipe; + +public class RecipeManager { + + private static final int MAXIMUM_INVENTORY_SIZE = 49; + private Greenhouses addon; + private List biomeRecipes = new ArrayList<>(); + + public RecipeManager(Greenhouses addon) { + this.addon = addon; + try { + loadBiomeRecipes(); + } catch (Exception e) { + addon.logError(e.getMessage()); + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Loads all the biome recipes from the file biomes.yml. + * @throws InvalidConfigurationException + * @throws IOException + * @throws FileNotFoundException + */ + public void loadBiomeRecipes() throws FileNotFoundException, IOException, InvalidConfigurationException { + biomeRecipes.clear(); + YamlConfiguration biomes = new YamlConfiguration(); + File biomeFile = new File(addon.getDataFolder(), "biomes.yml"); + if (!biomeFile.exists()) { + addon.logError("No biomes.yml file!"); + addon.saveResource("biomes.yml", true); + } + biomes.load(biomeFile); + ConfigurationSection biomeSection = biomes.getConfigurationSection("biomes"); + if (biomeSection == null) { + addon.logError("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()) { + 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(addon, 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 + ConfigurationSection reqContents = biomeRecipe.getConfigurationSection("contents"); + if (reqContents != null) { + for (String rq : reqContents.getKeys(false)) { + Material mat = Material.valueOf(rq.toUpperCase()); + if (mat != null) { + b.addReqBlocks(mat, reqContents.getInt(rq)); + } else { + addon.logError("Could not parse required block " + rq); + } + } + } + // Load plants + // # Plant Material: Probability in %:Block Material on what they grow + ConfigurationSection temp = biomes.getConfigurationSection("biomes." + type + ".plants"); + if (temp != null) { + HashMap plants = (HashMap)temp.getValues(false); + if (plants != null) { + for (String s: plants.keySet()) { + //logger(1, "Plant = " + s); + Material 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]); + + b.addPlants(plantMaterial, plantProbability, plantGrowOn); + } + } + } + // Load mobs! + // Mob EntityType: Probability:Spawn on Material + temp = biomes.getConfigurationSection("biomes." + type + ".mobs"); + if (temp != null) { + HashMap mobs = (HashMap)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]); + b.addMobs(mobType, mobProbability, mobSpawnOn); + } + } + } + // Load block conversions + ConfigurationSection conversionSec = biomeSection.getConfigurationSection(type + ".conversions"); + if (conversionSec != null) { + for (String oldMat : conversionSec.getKeys(false)) { + Material oldMaterial = Material.valueOf(oldMat); + if (oldMaterial == null) { + addon.logError("Could not parse " + oldMat); + break; + } + String conversions = conversionSec.getString(oldMat); + + //logger(3,"conversions = '" + conversions + "'"); + if (!conversions.isEmpty()) { + String[] split = conversions.split(":"); + int convChance = Integer.valueOf(split[0]); + Material newMaterial = Material.valueOf(split[1]); + Material localMaterial = Material.valueOf(split[2]); + b.addConvBlocks(oldMaterial, newMaterial, convChance, localMaterial); + } + } + } + + + // 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) { + addon.logWarning("Cannot load any more biome recipies - limit is 49!"); + break; + } + + } + addon.log("Loaded " + biomeRecipes.size() + " biome recipes."); + } + + /** + * @return the biomeRecipes + */ + public List getBiomeRecipes() { + return biomeRecipes; + } + + +} diff --git a/src/main/java/world/bentobox/greenhouses/ui/ControlPanel.java b/src/main/java/world/bentobox/greenhouses/ui/ControlPanel.java deleted file mode 100644 index 97d29b0..0000000 --- a/src/main/java/world/bentobox/greenhouses/ui/ControlPanel.java +++ /dev/null @@ -1,195 +0,0 @@ -package world.bentobox.greenhouses.ui; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; - -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.greenhouse.BiomeRecipe; -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.util.Util; -import world.bentobox.greenhouses.util.VaultHelper; - - -/** - * @author tastybento - * Provides a handy control panel - */ -public class ControlPanel implements Listener { - - private Greenhouses plugin; - - private HashMap> biomePanels = new HashMap>(); - /** - * @param store - */ - public ControlPanel(Greenhouses plugin) { - this.plugin = plugin; - } - - @EventHandler - public void onInventoryClick(InventoryClickEvent event) { - Player player = (Player) event.getWhoClicked(); // The player that clicked the item - Inventory inventory = event.getInventory(); // The inventory that was clicked in - int slot = event.getRawSlot(); - HashMap panel = biomePanels.get(player.getUniqueId()); - if (panel == null) { - // No panel, so just return - return; - } - // Check this is the Greenhouse Biome Panel - if (inventory.getName().equals(ChatColor.translateAlternateColorCodes('&', Locale.controlpaneltitle))) { - //String message = ""; - event.setCancelled(true); // Don't let them pick anything up - if (slot < 0) { - player.closeInventory(); - return; - } - if (slot == 0) { - player.performCommand("greenhouse info"); - player.closeInventory(); - return; - } - if (panel.containsKey(slot)) { - BiomeRecipe biomeRecipe = panel.get(slot); - // Sets up a greenhouse - Greenhouse oldg = plugin.players.getInGreenhouse(player); - // Check ownership - if (oldg != null && !oldg.getOwner().equals(player.getUniqueId())) { - player.sendMessage(Locale.errornotyours); - player.closeInventory(); - return; - } - if (oldg != null) { - // Player wants to try and change biome - //player.closeInventory(); // Closes the inventory - // error.exists - //player.sendMessage(ChatColor.RED + Locale.erroralreadyexists); - //return; - plugin.removeGreenhouse(oldg); - } - // Check if they are at their limit - if (plugin.players.isAtLimit(player)) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', Locale.infonomore)); - } else { - // Make greenhouse - Greenhouse g = plugin.tryToMakeGreenhouse(player, biomeRecipe); - if (g == null) { - player.closeInventory(); // Closes the inventory - //error.norecipe - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return; - } - player.closeInventory(); // Closes the inventory - } - //player.performCommand("greenhouse make"); - //player.sendMessage(message); - } - } - } - - /** - * Creates a player-specific biome panel based on permissions - * @param player - * @return - */ - public Inventory getPanel(Player player) { - HashMap store = new HashMap(); - // Index 0 is reserved for instructions - int index = 1; - // Run through biomes and add to the inventory if this player is allowed to use them - for (BiomeRecipe br : plugin.getBiomeRecipes()) { - // Gather the info - if (br.getPermission().isEmpty() || VaultHelper.checkPerm(player, br.getPermission())) { - // Add this biome recipe to the list - store.put(index++, br); - } - } - // Now create the panel - //int panelSize = store.size() + 9 - 1; - int panelSize = store.size() + 9; - panelSize -= ( panelSize % 9); - Inventory biomePanel = Bukkit.createInventory(player, panelSize, ChatColor.translateAlternateColorCodes('&', Locale.controlpaneltitle)); - // Add the instructions item - ItemStack item = new ItemStack(Material.THIN_GLASS); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(Locale.generalgreenhouses); - List lore = new ArrayList(); - lore.addAll(new ArrayList(Arrays.asList(Locale.infowelcome.split("\\|")))); - if (plugin.players.isAtLimit(player)) { - lore.add(ChatColor.translateAlternateColorCodes('&', Locale.infonomore)); - } else { - if (plugin.players.getRemainingGreenhouses(player) > 0) { - if (plugin.players.getRemainingGreenhouses(player) == 1) { - lore.addAll(new ArrayList(Arrays.asList(Locale.infoonemore.split("\\|")))); - } else { - String temp = Locale.infoyoucanbuild.replace("[number]", String.valueOf(plugin.players.getRemainingGreenhouses(player))); - lore.addAll(new ArrayList(Arrays.asList(temp.split("\\|")))); - } - } else { - lore.addAll(new ArrayList(Arrays.asList(Locale.infounlimited.split("\\|")))); - } - } - meta.setLore(lore); - item.setItemMeta(meta); - biomePanel.setItem(0, item); - // Now add the biomes - - index = 1; - for (BiomeRecipe br : store.values()) { - // Create an itemStack - item = new ItemStack(br.getIcon()); - meta = item.getItemMeta(); - if (br.getFriendlyName().isEmpty()) { - meta.setDisplayName(Util.prettifyText(br.getBiome().toString())); - } else { - meta.setDisplayName(br.getFriendlyName()); - } - lore.clear(); - List reqBlocks = br.getRecipeBlocks(); - if (reqBlocks.size() > 0) { - lore.add(ChatColor.YELLOW + Locale.recipeminimumblockstitle); - int i = 1; - for (String list : reqBlocks) { - lore.add(Locale.lineColor + (i++) + ": " + list); - } - } else { - lore.add(ChatColor.YELLOW + Locale.recipenootherblocks); - } - if (br.getWaterCoverage() == 0) { - lore.add(Locale.recipenowater); - } else if (br.getWaterCoverage() > 0) { - lore.add(Locale.recipewatermustbe.replace("[coverage]", String.valueOf(br.getWaterCoverage()))); - } - if (br.getIceCoverage() == 0) { - lore.add(Locale.recipenoice); - } else if (br.getIceCoverage() > 0) { - lore.add(Locale.recipeicemustbe.replace("[coverage]", String.valueOf(br.getIceCoverage()))); - } - if (br.getLavaCoverage() == 0) { - lore.add(Locale.recipenolava); - } else if (br.getLavaCoverage() > 0) { - lore.add(Locale.recipelavamustbe.replace("[coverage]", String.valueOf(br.getLavaCoverage()))); - } - meta.setLore(lore); - item.setItemMeta(meta); - biomePanel.setItem(index++,item); - } - // Stash the panel for later use when clicked - biomePanels.put(player.getUniqueId(), store); - return biomePanel; - } -} diff --git a/src/main/java/world/bentobox/greenhouses/ui/GreenhouseCmd.java b/src/main/java/world/bentobox/greenhouses/ui/GreenhouseCmd.java deleted file mode 100644 index a23042f..0000000 --- a/src/main/java/world/bentobox/greenhouses/ui/GreenhouseCmd.java +++ /dev/null @@ -1,248 +0,0 @@ - -package world.bentobox.greenhouses.ui; - -import java.util.List; -import java.util.UUID; - -import org.apache.commons.lang.math.NumberUtils; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.PlayerCache; -import world.bentobox.greenhouses.Settings; -import world.bentobox.greenhouses.greenhouse.BiomeRecipe; -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.util.Util; -import world.bentobox.greenhouses.util.VaultHelper; - -public class GreenhouseCmd implements CommandExecutor { - public boolean busyFlag = true; - private Greenhouses plugin; - private PlayerCache players; - - /** - * Constructor - * - * @param plugin - * @param players - */ - public GreenhouseCmd(Greenhouses plugin, PlayerCache players) { - - // Plugin instance - this.plugin = plugin; - this.players = players; - } - /* - * (non-Javadoc) - * - * @see - * org.bukkit.command.CommandExecutor#onCommand(org.bukkit.command.CommandSender - * , org.bukkit.command.Command, java.lang.String, java.lang.String[]) - */ - public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] split) { - if (!(sender instanceof Player)) { - return false; - } - final Player player = (Player) sender; - // Check we are in the right world - if (!Settings.worldName.contains(player.getWorld().getName())) { - // notavailable - player.sendMessage(ChatColor.RED + Locale.generalnotavailable); - return true; - } - // Basic permissions check to even use /greenhouse - if (!VaultHelper.checkPerm(player, "greenhouses.player")) { - player.sendMessage(ChatColor.RED + Locale.errornoPermission); - return true; - } - /* - * Grab data for this player - may be null or empty - * playerUUID is the unique ID of the player who issued the command - */ - final UUID playerUUID = player.getUniqueId(); - - switch (split.length) { - // /greenhouse command by itself - case 0: - final Greenhouse greenhouseInNow = players.getInGreenhouse(player); - if (greenhouseInNow==null || greenhouseInNow.getOwner().equals(playerUUID)) { - player.openInventory(plugin.getRecipeInv(player)); - return true; - } else { - player.sendMessage(ChatColor.RED + Locale.errornotowner); - return true; - } - case 1: - // /greenhouse - if (split[0].equalsIgnoreCase("help")) { - player.sendMessage(ChatColor.GREEN + Locale.generalgreenhouses +" " + plugin.getDescription().getVersion() + " " + Locale.helphelp + ":"); - player.sendMessage(ChatColor.YELLOW + "/" + label + " : " + ChatColor.WHITE + Locale.helpopengui); - player.sendMessage(ChatColor.YELLOW + "/" + label + " make: " + ChatColor.WHITE + Locale.helpmake); - player.sendMessage(ChatColor.YELLOW + "/" + label + " remove: " + ChatColor.WHITE + Locale.helpremove); - player.sendMessage(ChatColor.YELLOW + "/" + label + " info: " + ChatColor.WHITE + Locale.helpinfo); - player.sendMessage(ChatColor.YELLOW + "/" + label + " list: " + ChatColor.WHITE + Locale.helplist); - player.sendMessage(ChatColor.YELLOW + "/" + label + " recipe : " + ChatColor.WHITE + Locale.helprecipe); - return true; - } else if (split[0].equalsIgnoreCase("list")) { - // List all the biomes that can be made - player.sendMessage(ChatColor.GREEN + Locale.listtitle); - player.sendMessage(Locale.listinfo); - int index = 0; - for (BiomeRecipe br : plugin.getBiomeRecipes()) { - if (br.getFriendlyName().isEmpty()) { - player.sendMessage(ChatColor.YELLOW + Integer.toString(index++) + ": " + Util.prettifyText(br.getBiome().toString())); - } else { - player.sendMessage(ChatColor.YELLOW + Integer.toString(index++) + ": " + br.getFriendlyName()); - } - } - return true; - } else if (split[0].equalsIgnoreCase("remove")) { - final Greenhouse greenhouseNow = players.getInGreenhouse(player); - if (greenhouseNow != null) { - if (greenhouseNow.getOwner().equals(playerUUID)) { - player.sendMessage(ChatColor.RED + Locale.errorremoving); - plugin.removeGreenhouse(greenhouseNow); - return true; - } - player.sendMessage(ChatColor.RED + Locale.errornotyours); - } else { - player.sendMessage(ChatColor.RED + Locale.errornotinside); - } - return true; - } else if (split[0].equalsIgnoreCase("make")) { - // Sets up a greenhouse - final Greenhouse greenhouseN = players.getInGreenhouse(player); - if (greenhouseN != null) { - // alreadyexists - player.sendMessage(ChatColor.RED + Locale.erroralreadyexists); - return true; - } - // Check if they are at their limit - if (plugin.players.isAtLimit(player)) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', Locale.infonomore)); - } else { - // Try to make greenhouse - Greenhouse g = plugin.tryToMakeGreenhouse(player); - if (g == null) { - // norecipe - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - // Greenhouse is made - } - return true; - } else if (split[0].equalsIgnoreCase("info")) { - // Show some instructions on how to make greenhouses - player.sendMessage(ChatColor.GREEN + ChatColor.translateAlternateColorCodes('&', Locale.infotitle)); - for (String instructions : Locale.infoinstructions) { - player.sendMessage(ChatColor.GREEN + ChatColor.translateAlternateColorCodes('&', instructions)); - } - final Greenhouse greenhouseIn = players.getInGreenhouse(player); - if (greenhouseIn != null) { - player.sendMessage(ChatColor.GOLD + Locale.infoinfo); - // general.biome - player.sendMessage(ChatColor.GREEN + Locale.generalbiome + ": " + Util.prettifyText(greenhouseIn.getBiome().toString())); - if (greenhouseIn.getOwner() != null) { - Player owner = plugin.getServer().getPlayer(greenhouseIn.getOwner()); - if (owner != null) { - player.sendMessage(ChatColor.YELLOW + Locale.generalowner + ": " + owner.getDisplayName() + " (" + owner.getName() + ")"); - } else { - player.sendMessage(ChatColor.YELLOW + Locale.generalowner + ": " + greenhouseIn.getPlayerName()); - } - } - } - return true; - - } - break; - case 2: - if (split[0].equalsIgnoreCase("make")) { - // Sets up a greenhouse for a specific biome - if (players.getInGreenhouse(player) != null) { - // alreadyexists - player.sendMessage(ChatColor.RED + Locale.erroralreadyexists); - return true; - } - // Check if they are at their limit - if (plugin.players.isAtLimit(player)) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', Locale.infonomore)); - } else { - // Check we are in a greenhouse - try { - if (NumberUtils.isNumber(split[1])) { - int recipeNum = Integer.valueOf(split[1]); - List recipeList = plugin.getBiomeRecipes(); - if (recipeNum < 1 || recipeNum > recipeList.size()) { - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - if (plugin.tryToMakeGreenhouse(player,recipeList.get(recipeNum)) == null) { - // Failed for some reason - maybe permissions - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - } - } catch (Exception e) { - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - } - return true; - } else if (split[0].equalsIgnoreCase("recipe")) { - int recipeNumber = 0; - try { - recipeNumber = Integer.valueOf(split[1]); - } catch (Exception e) { - player.sendMessage(ChatColor.RED + Locale.recipehint); - return true; - } - List recipeList = plugin.getBiomeRecipes(); - if (recipeNumber <1 || recipeNumber > recipeList.size()) { - player.sendMessage(ChatColor.RED + Locale.recipewrongnumber.replace("[size]", String.valueOf(recipeList.size()))); - return true; - } - BiomeRecipe br = recipeList.get(recipeNumber-1); - if (br.getFriendlyName().isEmpty()) { - player.sendMessage(ChatColor.GREEN + "[" + Util.prettifyText(br.getBiome().toString()) + " recipe]"); - } else { - player.sendMessage(ChatColor.GREEN + "[" + br.getFriendlyName() + " recipe]"); - } - player.sendMessage(ChatColor.YELLOW + "Biome: " + Util.prettifyText(br.getBiome().toString())); - if (br.getWaterCoverage() == 0) { - player.sendMessage(Locale.recipenowater); - } else if (br.getWaterCoverage() > 0) { - player.sendMessage(Locale.recipewatermustbe.replace("[coverage]", String.valueOf(br.getWaterCoverage()))); - } - if (br.getIceCoverage() == 0) { - player.sendMessage(Locale.recipenoice); - } else if (br.getIceCoverage() > 0) { - player.sendMessage(Locale.recipeicemustbe.replace("[coverage]", String.valueOf(br.getIceCoverage()))); - } - if (br.getLavaCoverage() == 0) { - player.sendMessage(Locale.recipenolava); - } else if (br.getLavaCoverage() > 0) { - player.sendMessage(Locale.recipelavamustbe.replace("[coverage]", String.valueOf(br.getLavaCoverage()))); - } - List reqBlocks = br.getRecipeBlocks(); - if (reqBlocks.size() > 0) { - player.sendMessage(ChatColor.YELLOW + Locale.recipeminimumblockstitle); - int index = 1; - for (String list : reqBlocks) { - player.sendMessage(Locale.lineColor + (index++) + ": " + list); - } - } else { - player.sendMessage(ChatColor.YELLOW + Locale.recipenootherblocks); - } - return true; - } - - } - return false; - } - - -} \ No newline at end of file diff --git a/src/main/java/world/bentobox/greenhouses/ui/user/ListCommand.java b/src/main/java/world/bentobox/greenhouses/ui/user/ListCommand.java index 26fdd4d..a5c9477 100644 --- a/src/main/java/world/bentobox/greenhouses/ui/user/ListCommand.java +++ b/src/main/java/world/bentobox/greenhouses/ui/user/ListCommand.java @@ -5,14 +5,8 @@ package world.bentobox.greenhouses.ui.user; import java.util.List; -import org.bukkit.ChatColor; - import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.greenhouse.BiomeRecipe; -import world.bentobox.greenhouses.ui.Locale; -import world.bentobox.greenhouses.util.Util; /** * @author tastybento @@ -44,6 +38,7 @@ public class ListCommand extends CompositeCommand { */ @Override public boolean execute(User user, String label, List args) { + /* // List all the biomes that can be made user.sendMessage(ChatColor.GREEN + Locale.listtitle); user.sendMessage(Locale.listinfo); @@ -54,7 +49,7 @@ public class ListCommand extends CompositeCommand { } else { user.sendMessage(ChatColor.YELLOW + Integer.toString(index++) + ": " + br.getFriendlyName()); } - } + }*/ return true; } diff --git a/src/main/java/world/bentobox/greenhouses/ui/user/MakeCommand.java b/src/main/java/world/bentobox/greenhouses/ui/user/MakeCommand.java index 6466b81..9709fd8 100644 --- a/src/main/java/world/bentobox/greenhouses/ui/user/MakeCommand.java +++ b/src/main/java/world/bentobox/greenhouses/ui/user/MakeCommand.java @@ -5,14 +5,16 @@ package world.bentobox.greenhouses.ui.user; import java.util.List; -import org.apache.commons.lang.math.NumberUtils; -import org.bukkit.ChatColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.util.Vector; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; -import world.bentobox.greenhouses.greenhouse.BiomeRecipe; -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.ui.Locale; +import world.bentobox.greenhouses.Greenhouses; +import world.bentobox.greenhouses.managers.GreenhouseManager.GhResult; +import world.bentobox.greenhouses.managers.GreenhouseManager.GreenhouseResult; /** * @author tastybento @@ -27,7 +29,6 @@ public class MakeCommand extends CompositeCommand { */ public MakeCommand(CompositeCommand parent) { super(parent, "make"); - // TODO Auto-generated constructor stub } /* (non-Javadoc) @@ -44,62 +45,75 @@ public class MakeCommand extends CompositeCommand { */ @Override public boolean execute(User user, String label, List args) { - // Sets up a greenhouse - final Greenhouse greenhouseN = players.getInGreenhouse(player); - if (greenhouseN != null) { - // alreadyexists - player.sendMessage(ChatColor.RED + Locale.erroralreadyexists); + + // TODO Check permission + // Find the physical the greenhouse + Location location = user.getLocation().add(new Vector(0,1,0)); + // Check if there's a gh here already + if (((Greenhouses)this.getAddon()).getManager().getMap().getGreenhouse(location).isPresent()) { + user.sendRawMessage("You are in a greenhouse already!" ); return true; } - // Check if they are at their limit - if (plugin.players.isAtLimit(player)) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', Locale.infonomore)); - } else { - // Try to make greenhouse - Greenhouse g = plugin.tryToMakeGreenhouse(player); - if (g == null) { - // norecipe - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - // Greenhouse is made + GhResult result = ((Greenhouses)this.getAddon()).getManager().tryToMakeGreenhouse(location, null); + + if (result.getResults().isEmpty()) { + // Success + user.sendMessage("general.success"); + user.sendRawMessage(result.getFinder().getGh().getBiomeRecipe().getFriendlyName()); + return true; + } + result.getResults().forEach(r -> sendErrorMessage(user, r)); + if (!result.getFinder().getRedGlass().isEmpty()) { + // Show red glass + result.getFinder().getRedGlass().forEach(rg -> { + user.getPlayer().sendBlockChange(rg, Material.RED_STAINED_GLASS.createBlockData()); + }); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { + result.getFinder().getRedGlass().forEach(rg -> { + user.getPlayer().sendBlockChange(rg, rg.getBlock().getBlockData()); + }); + }, 120L); } return true; - - // Second arg - case 2: - if (split[0].equalsIgnoreCase("make")) { - // Sets up a greenhouse for a specific biome - if (players.getInGreenhouse(player) != null) { - // alreadyexists - player.sendMessage(ChatColor.RED + Locale.erroralreadyexists); - return true; - } - // Check if they are at their limit - if (plugin.players.isAtLimit(player)) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', Locale.infonomore)); - } else { - // Check we are in a greenhouse - try { - if (NumberUtils.isNumber(split[1])) { - int recipeNum = Integer.valueOf(split[1]); - List recipeList = plugin.getBiomeRecipes(); - if (recipeNum < 1 || recipeNum > recipeList.size()) { - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - if (plugin.tryToMakeGreenhouse(player,recipeList.get(recipeNum)) == null) { - // Failed for some reason - maybe permissions - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - } - } catch (Exception e) { - player.sendMessage(ChatColor.RED + Locale.errornorecipe); - return true; - } - } - return true; - } - } + + private void sendErrorMessage(User user, GreenhouseResult r) { + user.sendRawMessage(r.name()); + switch (r) { + case FAIL_BAD_ROOF_BLOCKS: + break; + case FAIL_BAD_WALL_BLOCKS: + break; + case FAIL_BELOW: + break; + case FAIL_BLOCKS_ABOVE: + break; + case FAIL_HOLE_IN_ROOF: + break; + case FAIL_HOLE_IN_WALL: + break; + case FAIL_NO_ROOF: + break; + case FAIL_TOO_MANY_DOORS: + break; + case FAIL_TOO_MANY_HOPPERS: + break; + case FAIL_UNEVEN_WALLS: + break; + case FAIL_INSUFFICIENT_ICE: + break; + case FAIL_INSUFFICIENT_LAVA: + break; + case FAIL_INSUFFICIENT_WATER: + break; + case FAIL_NO_ICE: + break; + case FAIL_NO_LAVA: + break; + case FAIL_NO_WATER: + break; + default: + break; + } + } +} diff --git a/src/main/java/world/bentobox/greenhouses/ui/user/RecipeCommand.java b/src/main/java/world/bentobox/greenhouses/ui/user/RecipeCommand.java index fcda6c7..93b620b 100644 --- a/src/main/java/world/bentobox/greenhouses/ui/user/RecipeCommand.java +++ b/src/main/java/world/bentobox/greenhouses/ui/user/RecipeCommand.java @@ -5,13 +5,8 @@ package world.bentobox.greenhouses.ui.user; import java.util.List; -import org.bukkit.ChatColor; - import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; -import world.bentobox.greenhouses.greenhouse.BiomeRecipe; -import world.bentobox.greenhouses.ui.Locale; -import world.bentobox.greenhouses.util.Util; /** * @author tastybento @@ -43,7 +38,7 @@ public class RecipeCommand extends CompositeCommand { */ @Override public boolean execute(User user, String label, List args) { - + /* // Second arg int recipeNumber = 0; try { @@ -88,7 +83,7 @@ public class RecipeCommand extends CompositeCommand { } } else { player.sendMessage(ChatColor.YELLOW + Locale.recipenootherblocks); - } + }*/ return true; } diff --git a/src/main/java/world/bentobox/greenhouses/ui/user/RemoveCommand.java b/src/main/java/world/bentobox/greenhouses/ui/user/RemoveCommand.java index 898484f..817fa60 100644 --- a/src/main/java/world/bentobox/greenhouses/ui/user/RemoveCommand.java +++ b/src/main/java/world/bentobox/greenhouses/ui/user/RemoveCommand.java @@ -5,13 +5,8 @@ package world.bentobox.greenhouses.ui.user; import java.util.List; -import org.bukkit.ChatColor; - import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; -import world.bentobox.greenhouses.Greenhouses; -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.ui.Locale; /** * @author tastybento @@ -43,6 +38,7 @@ public class RemoveCommand extends CompositeCommand { */ @Override public boolean execute(User user, String label, List args) { + /* final Greenhouse greenhouseNow = ((Greenhouses)getAddon()).getInGreenhouse(user); if (greenhouseNow != null) { if (greenhouseNow.getOwner().equals(user.getUniqueId())) { @@ -53,7 +49,7 @@ public class RemoveCommand extends CompositeCommand { user.sendMessage(ChatColor.RED + Locale.errornotyours); } else { user.sendMessage(ChatColor.RED + Locale.errornotinside); - } + }*/ return true; } diff --git a/src/main/java/world/bentobox/greenhouses/ui/user/GhCommand.java b/src/main/java/world/bentobox/greenhouses/ui/user/UserCommand.java similarity index 55% rename from src/main/java/world/bentobox/greenhouses/ui/user/GhCommand.java rename to src/main/java/world/bentobox/greenhouses/ui/user/UserCommand.java index fdb8833..229c946 100644 --- a/src/main/java/world/bentobox/greenhouses/ui/user/GhCommand.java +++ b/src/main/java/world/bentobox/greenhouses/ui/user/UserCommand.java @@ -5,26 +5,24 @@ package world.bentobox.greenhouses.ui.user; import java.util.List; -import org.bukkit.ChatColor; - import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; -import world.bentobox.greenhouses.greenhouse.Greenhouse; -import world.bentobox.greenhouses.ui.Locale; +import world.bentobox.greenhouses.Greenhouses; /** * @author tastybento * */ -public class GhCommand extends CompositeCommand { +public class UserCommand extends CompositeCommand { /** + * @param gh * @param parent * @param label * @param aliases */ - public GhCommand(CompositeCommand parent) { - super(parent, "greenhouse", "gh"); + public UserCommand(Greenhouses gh, CompositeCommand parent) { + super(gh, parent, "greenhouse", "gh"); } /* (non-Javadoc) @@ -37,11 +35,11 @@ public class GhCommand extends CompositeCommand { this.setParametersHelp("greenhouses.command.parameters"); this.setDescription("greenhouses.command.description"); - new InfoCommand(this); - new ListCommand(this); + //new InfoCommand(this); + //new ListCommand(this); new MakeCommand(this); - new RecipeCommand(this); - new RemoveCommand(this); + //new RecipeCommand(this); + //new RemoveCommand(this); } /* (non-Javadoc) @@ -49,14 +47,8 @@ public class GhCommand extends CompositeCommand { */ @Override public boolean execute(User user, String label, List args) { - final Greenhouse greenhouseInNow = players.getInGreenhouse(player); - if (greenhouseInNow==null || greenhouseInNow.getOwner().equals(playerUUID)) { - player.openInventory(plugin.getRecipeInv(player)); - return true; - } else { - player.sendMessage(ChatColor.RED + Locale.errornotowner); - return true; - } + this.showHelp(this, user); + return true; } } diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index 0cfe154..99e411a 100755 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -1,5 +1,5 @@ -name: WelcomeWarps -main: world.bentobox.warps.Warp +name: Greenhouses +main: world.bentobox.greenhouses.Greenhouses version: ${version} authors: tastybento @@ -7,16 +7,6 @@ authors: tastybento softdepend: AcidIsland, BSkyBlock permissions: - bskyblock.island.warp: - description: Player can use warp or warps commands + greenhouses.make: + description: Player can make a greenhouse default: true - bskyblock.island.addwarp: - description: Player can create a welcome warp sign - default: true - acidisland.island.warp: - description: Player can use warp or warps commands - default: true - acidisland.island.addwarp: - description: Player can create a welcome warp sign - default: true - diff --git a/src/main/resources/biomes.yml b/src/main/resources/biomes.yml index 19a4504..aaf7509 100644 --- a/src/main/resources/biomes.yml +++ b/src/main/resources/biomes.yml @@ -5,16 +5,16 @@ biomes: # The name of the icon. Can use & for color codes, e.g. &c friendlyname: "Beach" # The biome of the recipe. Allows multiple recipes for the same biome. - biome: BEACHES + biome: BEACH # The icon is shown in the panel. It must be a Bukkit Material icon: SAND # Priority is used if the greenhouse can be more than one biome. The highest # priority wins priority: 0 # Contents - The minimum requirement for this biome. - # Format is Material:Type/Durability (optional):Number of blocks - # So SAND:1:1 would require 1 block of red sand (durability of 1 = red sand) - contents: SAND:1 + # Format is Material: Number of blocks + contents: + SAND: 1 # The number of blocks in the greenhouse that must be water, ice or lava # Floor area * this % = number of blocks required watercoverage: 50 @@ -34,7 +34,7 @@ biomes: # Format: # Entity name: % chance:Block on which the mob will spawn mobs: - SQUID: 10:STATIONARY_WATER + SQUID: 10:WATER # The minimum number of blocks each mob requires. # Mobs will not spawn if there is more than 1 per this number of # blocks in the greenhouse. e.g., in this case only 2 mobs will spawn if the @@ -42,45 +42,51 @@ biomes: moblimit: 9 Snowy_beach: friendlyname: "Snowy beach" - biome: COLD_BEACH + biome: SNOWY_BEACH icon: SNOW_BLOCK priority: 21 - contents: SAND:1 + contents: + SAND: 1 watercoverage: 50 icecoverage: 10 ThreeWolfMoon: friendlyname: "Three Wolf Moon Forest" # Could do with more wolves, but the magic works with 3. - # If you are using 1.8 or earlier, this biome should be COLD_TAIGA - biome: TAIGA_COLD - icon: SAPLING + biome: TAIGA + icon: SPRUCE_SAPLING priority: 20 - contents: LOG:3 LEAVES:3 GRASS:3 + contents: + SPRUCE_LOG: 3 + SPRUCE_LEAVES: 3 + GRASS: 3 icecoverage: 10 plants: - LONG_GRASS:1: 10:GRASS + TALL_GRASS: 10:GRASS mobs: WOLF: 10:SNOW moblimit: 9 Cold_Rabbit: friendlyname: "Cold Taiga Forest" - # If you are using 1.8 or earlier, this biome should be COLD_TAIGA - biome: TAIGA_COLD - icon: SAPLING + biome: TAIGA_HILLS + icon: SPRUCE_SAPLING priority: 20 - contents: LOG:3 LEAVES:3 GRASS:3 + contents: + SPRUCE_LOG: 3 + SPRUCE_LEAVES: 3 + GRASS: 3 icecoverage: 10 plants: - LONG_GRASS:1: 10:GRASS + TALL_GRASS: 10:GRASS mobs: RABBIT: 10:SNOW moblimit: 9 DESERT: friendlyname: "Desert" - biome: "Desert" + biome: DESERT icon: DEAD_BUSH priority: 3 - contents: SAND:1 + contents: + SAND: 1 # No water allowed watercoverage: 0 # No ice allowed @@ -88,27 +94,33 @@ biomes: plants: DEAD_BUSH: 10:SAND CACTUS: 10:SAND - # Conversions (see below for another variation) + # Conversions # Format is: - # Original Block Material:Durability:Chance of change:New Block Material:Durability - # So, for below, regular dirt (durability 0) has a 30% chance of changing into regular sand. - conversions: DIRT:0:30:SAND:0 + # Original Block: % chance:New Block:Adjacent Block + # So, for below, dirt has a 30% chance of changing into SAND if it is next to SAND! + conversions: + DIRT: 30:SAND:SAND FOREST: friendlyname: "Flowery forest" biome: FOREST - icon: RED_ROSE + icon: ROSE_RED priority: 4 - contents: LOG:3 LEAVES:4 GRASS:4 + contents: + OAK_LOG: 3 + OAK_LEAVES: 4 + GRASS: 4 plants: - RED_ROSE:8: 2:GRASS - DOUBLE_PLANT:5: 4:GRASS - LONG_GRASS:1: 20:GRASS - HELL: + PINK_TULIP: 2:GRASS + ORANGE_TULIP: 2:GRASS + SUNFLOWER: 4:GRASS + TALL_GRASS: 20:GRASS + NETHER: friendlyname: "&cNether" - biome: HELL + biome: NETHER icon: LAVA_BUCKET priority: 5 - contents: NETHERRACK:1 + contents: + NETHERRACK: 1 # Lava required, no ice or water allowed lavacoverage: 21 icecoverage: 0 @@ -121,26 +133,30 @@ biomes: biome: JUNGLE icon: VINE priority: 6 - contents: GRASS:4 LOG:3:3 LEAVES:3:4 + contents: + GRASS: 4 + JUNGLE_LOG: 3 + JUNGLE_LEAVES: 4 plants: - YELLOW_FLOWER: 20:GRASS - MELON_BLOCK: 10:GRASS - RED_ROSE: 20:GRASS - DOUBLE_PLANT:3: 20:GRASS - LONG_GRASS:2: 20:GRASS - MUSHROOM_ISLAND: - friendlyname: "Mushroom Island" - biome: MUSHROOM_ISLAND + DANDELION: 20:GRASS + MELON: 10:GRASS + ROSE_BUSH: 20:GRASS + FERN: 20:GRASS + TALL_GRASS: 20:GRASS + MUSHROOM_FIELDS: + friendlyname: "Mushroom Fields" + biome: MUSHROOM_FIELDS icon: RED_MUSHROOM priority: 11 - contents: MYCEL:2 + contents: + MYCELIUM: 2 # Water required at 30% watercoverage: 30 plants: - BROWN_MUSHROOM: 10:MYCEL - RED_MUSHROOM: 10:MYCEL + BROWN_MUSHROOM: 10:MYCELIUM + RED_MUSHROOM: 10:MYCELIUM mobs: - MUSHROOM_COW: 10:MYCEL + MUSHROOM_COW: 10:MYCELIUM moblimit: 9 OCEAN: biome: OCEAN @@ -149,16 +165,17 @@ biomes: # Lots of water required! watercoverage: 95 mobs: - SQUID: 10:STATIONARY_WATER + SQUID: 10:WATER moblimit: 9 PLAINS: friendlyname: "Horse Plains" biome: PLAINS icon: GRASS priority: 1 - contents: GRASS:3 + contents: + GRASS: 3 plants: - LONG_GRASS:1: 10:GRASS + TALL_GRASS: 10:GRASS mobs: HORSE: 10:GRASS moblimit: 9 @@ -167,32 +184,41 @@ biomes: biome: RIVER icon: CLAY priority: 10 - contents: SAND:1 + contents: + SAND: 1 # 50% water required watercoverage: 50 # Conversions - in this case, an adjacent block is required to convert # Format is: - # Original Block:Durability:% chance:New Block:Durability:Adjacent Block:Durability + # Original Block: % chance:New Block:Adjacent Block # So, for below, dirt has a 50% chance of changing into clay if it is next to water! - conversions: DIRT:0:50:CLAY:0:STATIONARY_WATER:0 + conversions: + DIRT: 50:CLAY:WATER SAVANNA: biome: SAVANNA - icon: LEAVES + icon: ACACIA_LEAVES priority: 11 - contents: LOG_2:3 LEAVES_2:4 GRASS:4 + contents: + ACACIA_LOG: 3 + ACACIA_LEAVES: 4 + GRASS: 4 plants: - DOUBLE_PLANT:2: 10:GRASS - SWAMPLAND: + TALL_GRASS: 10:GRASS + SWAMP: friendlyname: "&2Slimy Swamp" - icon: WATER_LILY + biome: SWAMP + icon: LILY_PAD priority: 13 - contents: GRASS:4 LOG:3 LEAVES:4 + contents: + GRASS: 4 + OAK_LOG: 3 + OAK_LEAVES: 4 # 50% water coverage required watercoverage: 50 plants: RED_MUSHROOM: 20:GRASS BROWN_MUSHROOM: 20:GRASS - WATER_LILY: 5:STATIONARY_WATER + LILY_PAD: 5:WATER mobs: - SLIME: 5:STATIONARY_WATER + SLIME: 5:WATER moblimit: 3