Basics there. Lots of bugs.

This commit is contained in:
tastybento 2019-01-21 15:44:01 -08:00
parent 075c9bcc78
commit 71383b0adb
29 changed files with 1842 additions and 3675 deletions

View File

@ -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/<project>=UTF-8

File diff suppressed because it is too large Load Diff

View File

@ -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<UUID, Players> playerCache = new HashMap<UUID, Players>();
private final Greenhouses plugin;
public PlayerCache(Greenhouses plugin) {
this.plugin = plugin;
playerCache.clear();
// Add any players currently online (handles the /reload condition)
final Collection<? extends Player> 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<Greenhouse> toBeRemoved = new ArrayList<Greenhouse>();
// 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;
}
}
}

View File

@ -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;
}
}

View File

@ -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<String> 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<String> 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<String> 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<String> 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;
}
}

View File

@ -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();
}
}

View File

@ -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<BiomeRecipe> {
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<Material, Integer> 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<GreenhouseResult> checkRecipe(Greenhouse gh) {
Set<GreenhouseResult> result = new HashSet<>();
long area = gh.getArea();
Map<Material, Integer> blockCount = new HashMap<>();
// Look through the greenhouse and count what is in there
for (int y = pos1.getBlockY(); y<pos2.getBlockY();y++) {
for (int x = pos1.getBlockX()+1;x<pos2.getBlockX();x++) {
for (int z = pos1.getBlockZ()+1;z<pos2.getBlockZ();z++) {
Block b = pos1.getWorld().getBlockAt(x, y, z);
for (int y = gh.getFloorHeight(); y< gh.getCeilingHeight();y++) {
for (int x = (int) (gh.getFootprint().getMinX()+1); x < gh.getFootprint().getMaxX(); x++) {
for (int z = (int) (gh.getFootprint().getMinY()+1); z < gh.getFootprint().getMaxY(); z++) {
Block b = gh.getWorld().getBlockAt(x, y, z);
if (!b.getType().equals(Material.AIR)) {
blockCount.putIfAbsent(b.getType(), 0);
blockCount.merge(b.getType(), 1, Integer::sum);
@ -161,64 +157,41 @@ public class BiomeRecipe {
|| en.getKey().equals(Material.PACKED_ICE))
.mapToInt(Map.Entry::getValue).sum();
double iceRatio = (double)ice/(double)area * 100;
plugin.logger(3,"water req=" + waterCoverage + " lava req=" + lavaCoverage + " ice req="+iceCoverage);
plugin.logger(3,"waterRatio=" + waterRatio + " lavaRatio=" + lavaRatio + " iceRatio="+iceRatio);
//plugin.logger(3,"water req=" + waterCoverage + " lava req=" + lavaCoverage + " ice req="+iceCoverage);
//plugin.logger(3,"waterRatio=" + waterRatio + " lavaRatio=" + lavaRatio + " iceRatio="+iceRatio);
// Check required ratios - a zero means none of these are allowed, e.g.desert has no water
if (waterCoverage == 0 && waterRatio > 0) {
if (player != null) {
player.sendMessage(ChatColor.RED + Locale.recipenowater);
}
pass=false;
result.add(GreenhouseResult.FAIL_NO_WATER);
}
if (lavaCoverage == 0 && lavaRatio > 0) {
if (player != null) {
player.sendMessage(ChatColor.RED + Locale.recipenolava);
}
pass=false;
result.add(GreenhouseResult.FAIL_NO_LAVA);
}
if (iceCoverage == 0 && iceRatio > 0) {
if (player != null) {
player.sendMessage(ChatColor.RED + Locale.recipenoice);
}
pass=false;
result.add(GreenhouseResult.FAIL_NO_ICE);
}
if (waterCoverage > 0 && waterRatio < waterCoverage) {
if (player != null) {
player.sendMessage(ChatColor.RED + Locale.recipewatermustbe.replace("[coverage]", String.valueOf(waterCoverage)));
}
pass=false;
result.add(GreenhouseResult.FAIL_INSUFFICIENT_WATER);
}
if (lavaCoverage > 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<Material, Integer> 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<Material, Integer> getMissingBlocks() {
return missingBlocks;
}
@Override
public int compareTo(BiomeRecipe o) {
return Integer.compare(o.getPriority(), this.getPriority());
}
}

View File

@ -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<Biome> 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<Greenhouse> snowGlobes = new ArrayList<Greenhouse>();
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<Greenhouse> toBeRemoved = new ArrayList<Greenhouse>();
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<Greenhouse> 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);
}
}

View File

@ -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<String,Object> flags = new HashMap<String,Object>();
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<String, Object> getFlags() {
return flags;
}
/**
* @param flags the flags to set
*/
public void setFlags(HashMap<String, Object> 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<Pair<Integer, Integer>> chunkCoords = new HashSet<>();
final Set<Chunk> chunks = new HashSet<Chunk>();
for (int x = pos1.getBlockX();x<pos2.getBlockX();x++) {
for (int z = pos1.getBlockZ();z<pos2.getBlockZ();z++) {
Block b = world.getBlockAt(x, groundY, z);
b.setBiome(biome);
if (teleport) {
chunks.add(b.getChunk());
}
if (plugin.getServer().getVersion().contains("(MC: 1.7")) {
chunkCoords.add(new Pair<Integer, Integer>(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<Pair> chunkSet = new HashSet<Pair>();
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<Block> waterToIceBlocks = new ArrayList<Block>();
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()<Settings.snowDensity) {
if (belowB.getType().equals(Material.WATER)) {
// If the recipe requires a certain amount of water, then we need to wait until later to make ice
if (biomeRecipe.getWaterCoverage() > 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()<Settings.flowerChance) {
plugin.logger(3,"Block is " + bl.getRelative(BlockFace.DOWN).getType().toString());
if (total > 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);
}
}

View File

@ -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<String> ROOFBLOCKS = Arrays.asList("GLASS","STAINED_GLASS","HOPPER","TRAP_DOOR","IRON_TRAPDOOR","GLOWSTONE");
public final static List<Material> 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 + "]";
}
}

View File

@ -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<Material> 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
*/

View File

@ -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<Location> blockedPistons = new ArrayList<Location>();
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<Greenhouse> to = plugin.getManager().getMap().getGreenhouse(toLoc);
Optional<Greenhouse> 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));
}
}

View File

@ -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<Greenhouse> to = plugin.getManager().getMap().getGreenhouse(e.getToBlock().getLocation());
Optional<Greenhouse> 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);
}

View File

@ -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<String> 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());
}
}

View File

@ -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<Biome> SNOWBIOMES = Arrays.stream(Biome.values()).filter(b -> b.name().contains("COLD") || b.name().contains("ICE") || b.name().contains("FROZEN")).collect(Collectors.toList());
private Map<World, BukkitTask> 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<Block> getAirBlocks(Greenhouse gh) {
List<Block> waterBlocks = new ArrayList<>();
List<Block> 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));
}
}
}

View File

@ -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<Block> getAvailableBlocks(Greenhouse gh) {
List<Block> 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();
}
}

View File

@ -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<Location> redGlass = new HashSet<Location>();
public Set<GreenhouseResult> find(Location location) {
Set<GreenhouseResult> 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<Location> getRedGlass() {
return redGlass;
}
}

View File

@ -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<Greenhouse> 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<GreenhouseResult> 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<GreenhouseResult> results;
private GreenhouseFinder finder;
/**
* @return the results
*/
public Set<GreenhouseResult> getResults() {
return results;
}
/**
* @return the finder
*/
public GreenhouseFinder getFinder() {
return finder;
}
/**
* @param results the results to set
*/
public GhResult setResults(Set<GreenhouseResult> results) {
this.results = results;
return this;
}
/**
* @param finder the finder to set
*/
public GhResult setFinder(GreenhouseFinder finder) {
this.finder = finder;
return this;
}
}
}

View File

@ -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<Island, List<Greenhouse>> 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<Greenhouse> getGreenhouse(Location location) {
return getXZGreenhouse(location).filter(g -> location.getBlockY() <= g.getCeilingHeight() && location.getBlockY() >= g.getFloorHeight());
}
private Optional<Greenhouse> 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<Greenhouse> getGreenhouses() {
return greenhouses.values().stream().flatMap(List::stream).collect(Collectors.toList());
}
}

View File

@ -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<BiomeRecipe> 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<String,Object> plants = (HashMap<String,Object>)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<String,Object> mobs = (HashMap<String,Object>)temp.getValues(false);
if (mobs != null) {
for (String s: mobs.keySet()) {
EntityType mobType = EntityType.valueOf(s);
String[] split = ((String)mobs.get(s)).split(":");
int mobProbability = Integer.valueOf(split[0]);
Material mobSpawnOn = Material.valueOf(split[1]);
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<BiomeRecipe> getBiomeRecipes() {
return biomeRecipes;
}
}

View File

@ -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<UUID, HashMap<Integer,BiomeRecipe>> biomePanels = new HashMap<UUID, HashMap<Integer,BiomeRecipe>>();
/**
* @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<Integer,BiomeRecipe> 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<Integer, BiomeRecipe> store = new HashMap<Integer,BiomeRecipe>();
// 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<String> lore = new ArrayList<String>();
lore.addAll(new ArrayList<String>(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<String>(Arrays.asList(Locale.infoonemore.split("\\|"))));
} else {
String temp = Locale.infoyoucanbuild.replace("[number]", String.valueOf(plugin.players.getRemainingGreenhouses(player)));
lore.addAll(new ArrayList<String>(Arrays.asList(temp.split("\\|"))));
}
} else {
lore.addAll(new ArrayList<String>(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<String> 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;
}
}

View File

@ -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 <command>
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 <number>: " + 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<BiomeRecipe> 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<BiomeRecipe> 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<String> 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;
}
}

View File

@ -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<String> 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;
}

View File

@ -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<String> 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<BiomeRecipe> 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;
}
}
}

View File

@ -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<String> 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;
}

View File

@ -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<String> 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;
}

View File

@ -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<String> 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;
}
}

View File

@ -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

View File

@ -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