From 33ddb8ae888c530be55244184a074dfc6e618663 Mon Sep 17 00:00:00 2001 From: Thijs Wiefferink Date: Thu, 5 Oct 2017 16:53:42 +0200 Subject: [PATCH] Fix `%volume%` for polygon regions - WorldGuard does not implement volume() for Polygon regions, always returns 0 - Volume result is cached, calculating it for polygon regions could be slow --- .../areashop/regions/GeneralRegion.java | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java b/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java index 840a3c1..e03d944 100644 --- a/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java +++ b/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java @@ -1,6 +1,9 @@ package me.wiefferink.areashop.regions; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import me.wiefferink.areashop.AreaShop; import me.wiefferink.areashop.events.NotifyRegionEvent; @@ -45,6 +48,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl YamlConfiguration config; private boolean saveRequired = false; private boolean deleted = false; + private long volume = -1; private Map, RegionFeature> features; @@ -579,7 +583,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl case AreaShop.tagLandlordUUID: return getLandlord(); case AreaShop.tagVolume: - return getRegion().volume(); + return getVolume(); // Date/time case AreaShop.tagEpoch: @@ -1459,6 +1463,76 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl } runCommands(Bukkit.getConsoleSender(), commands); } + + /** + * Get the volume of the region (number of blocks inside it). + * @return Number of blocks in the region + */ + public long getVolume() { + // Cache volume, important for polygon regions + if(volume < 0) { + volume = calculateVolume(); + } + + return volume; + } + + /** + * Calculate the volume of the region (could be expensive for polygon regions). + * @return Number of blocks in the region + */ + private long calculateVolume() { + // Use own calculation for polygon regions, as WorldGuard does not implement it and returns 0 + ProtectedRegion region = getRegion(); + if(region instanceof ProtectedPolygonalRegion) { + BlockVector min = region.getMinimumPoint(); + BlockVector max = region.getMaximumPoint(); + + // Exact, but slow algorithm + if(getWidth() * getDepth() < 100) { + long surface = 0; + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + if (region.contains(x, min.getBlockY(), z)) { + surface++; + } + } + } + return surface * getHeight(); + } + // Estimate, but quick algorithm + else { + List points = region.getPoints(); + int numPoints = points.size(); + if(numPoints < 3) { + return 0; + } + + double area = 0; + int x1, x2, z1, z2; + for(int i = 0; i <= numPoints - 2; i++) { + x1 = points.get(i).getBlockX(); + z1 = points.get(i).getBlockZ(); + + x2 = points.get(i + 1).getBlockX(); + z2 = points.get(i + 1).getBlockZ(); + + area = area + ((z1 + z2) * (x1 - x2)); + } + + x1 = points.get(numPoints - 1).getBlockX(); + z1 = points.get(numPoints - 1).getBlockZ(); + x2 = points.get(0).getBlockX(); + z2 = points.get(0).getBlockZ(); + + area = area + ((z1 + z2) * (x1 - x2)); + area = Math.ceil(Math.abs(area) / 2); + return (long)(area * getHeight()); + } + } else { + return region.volume(); + } + } }