From c150cb0396d6579aaecdfa72fc86b7090f3e03fa Mon Sep 17 00:00:00 2001 From: zyuiop Date: Fri, 6 Sep 2019 19:55:31 +0200 Subject: [PATCH 1/2] Make a new abstraction for claims --- .../java/net/zyuiop/rpmachine/RPMachine.java | 12 +- .../rpmachine/cities/CitiesManager.java | 55 +---- .../net/zyuiop/rpmachine/cities/City.java | 205 ++++++++++++------ .../plotsubcommands/CreateCommand.java | 5 +- .../commands/plotsubcommands/InfoCommand.java | 6 +- .../cities/listeners/CitiesListener.java | 129 ----------- .../net/zyuiop/rpmachine/claims/Claim.java | 63 ++++++ .../claims/ClaimCollectionRegistry.java | 24 ++ .../rpmachine/claims/ClaimRegistry.java | 43 ++++ .../net/zyuiop/rpmachine/claims/Claims.java | 51 +++++ .../rpmachine/claims/ClaimsListener.java | 164 ++++++++++++++ .../rpmachine/claims/CompoundClaim.java | 47 ++++ .../zyuiop/rpmachine/claims/DenyAllClaim.java | 50 +++++ .../zyuiop/rpmachine/claims/LeafClaim.java | 14 ++ .../net/zyuiop/rpmachine/common/Plot.java | 59 ++++- .../zyuiop/rpmachine/common/VirtualChunk.java | 20 +- .../rpmachine/projects/ProjectsManager.java | 10 +- .../net/zyuiop/rpmachine/utils/TimeUtils.java | 20 ++ 18 files changed, 723 insertions(+), 254 deletions(-) create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/Claim.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/ClaimCollectionRegistry.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/ClaimRegistry.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/Claims.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/ClaimsListener.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/DenyAllClaim.java create mode 100644 src/main/java/net/zyuiop/rpmachine/claims/LeafClaim.java create mode 100644 src/main/java/net/zyuiop/rpmachine/utils/TimeUtils.java diff --git a/src/main/java/net/zyuiop/rpmachine/RPMachine.java b/src/main/java/net/zyuiop/rpmachine/RPMachine.java index 89eb27d..11414d9 100755 --- a/src/main/java/net/zyuiop/rpmachine/RPMachine.java +++ b/src/main/java/net/zyuiop/rpmachine/RPMachine.java @@ -8,6 +8,8 @@ import net.zyuiop.rpmachine.cities.commands.CommandRuntaxes; import net.zyuiop.rpmachine.cities.commands.PlotCommand; import net.zyuiop.rpmachine.cities.listeners.CitiesListener; +import net.zyuiop.rpmachine.claims.Claims; +import net.zyuiop.rpmachine.claims.ClaimsListener; import net.zyuiop.rpmachine.commands.*; import net.zyuiop.rpmachine.common.PlayerHeadCraft; import net.zyuiop.rpmachine.common.listeners.PlayerListener; @@ -53,6 +55,7 @@ public class RPMachine extends JavaPlugin { private ShopsManager shopsManager; private MultiverseManager multiverseManager; private DiscordManager discordManager; + private Claims claims; public static RPMachine getInstance() { return instance; @@ -132,6 +135,8 @@ private void start() { this.multiverseManager = new MultiverseManager(); this.discordManager = new DiscordManager(getConfig().getString("discord.token")); + this.claims = new Claims(this); + // Load DB if (!loadDatabase()) { getLogger().severe("Cannot load DB, shutting down."); @@ -170,6 +175,7 @@ private void start() { Bukkit.getPluginManager().registerEvents(new SignsListener(), this); Bukkit.getPluginManager().registerEvents(new CitiesListener(citiesManager), this); Bukkit.getPluginManager().registerEvents(new PlayerHeadCraft(), this); + Bukkit.getPluginManager().registerEvents(new ClaimsListener(claims), this); // Bukkit.getPluginManager().registerEvents(new MendingListener(), this); @@ -285,10 +291,8 @@ public void onDisable() { super.onDisable(); } - public static Plot getPlotHere(Location location) { - City c = instance.citiesManager.getCityHere(location.getChunk()); - - return c == null ? instance.projectsManager.getZoneHere(location) : c.getPlotHere(location); + public Claims getClaims() { + return claims; } public ScoreboardManager getScoreboardManager() { diff --git a/src/main/java/net/zyuiop/rpmachine/cities/CitiesManager.java b/src/main/java/net/zyuiop/rpmachine/cities/CitiesManager.java index d29a650..13b2feb 100755 --- a/src/main/java/net/zyuiop/rpmachine/cities/CitiesManager.java +++ b/src/main/java/net/zyuiop/rpmachine/cities/CitiesManager.java @@ -2,6 +2,9 @@ import com.google.common.collect.ImmutableSet; import net.zyuiop.rpmachine.RPMachine; +import net.zyuiop.rpmachine.claims.Claim; +import net.zyuiop.rpmachine.claims.ClaimCollectionRegistry; +import net.zyuiop.rpmachine.claims.ClaimRegistry; import net.zyuiop.rpmachine.common.VirtualChunk; import net.zyuiop.rpmachine.database.filestorage.FileEntityStore; import net.zyuiop.rpmachine.entities.LegalEntityRepository; @@ -19,7 +22,7 @@ import java.util.function.DoubleFunction; import java.util.stream.Collectors; -public class CitiesManager extends FileEntityStore implements LegalEntityRepository { +public class CitiesManager extends FileEntityStore implements LegalEntityRepository, ClaimCollectionRegistry { public static final Set ALLOWED_COLORS = ImmutableSet.of( ChatColor.YELLOW, ChatColor.DARK_AQUA, ChatColor.AQUA, ChatColor.GREEN, ChatColor.DARK_GREEN, ChatColor.LIGHT_PURPLE, ChatColor.DARK_PURPLE, ChatColor.DARK_GRAY, ChatColor.GRAY, ChatColor.BLUE, ChatColor.GOLD @@ -133,51 +136,6 @@ public City getCityHere(Chunk chunk) { return null; } - public boolean canBuild(Player player, Location location) { - if (bypass.contains(player.getUniqueId())) - return true; - - if (location.getWorld().getName().equals("world")) { - City city = getCityHere(location.getChunk()); - - if (city == null) { - return RPMachine.getInstance().getProjectsManager().canBuild(player, location); - } - return city.canBuild(player, location); - } else { - return RPMachine.getInstance().getProjectsManager().canBuild(player, location); - } - } - - public boolean isProtected(Location location) { - if (location.getWorld().getName().equals("world")) { - City city = getCityHere(location.getChunk()); - - if (city == null) { - return RPMachine.getInstance().getProjectsManager().isProtected(location); - } - return true; - } else { - return false; - } - } - - public boolean canInteractWithBlock(Player player, Location location) { - if (bypass.contains(player.getUniqueId())) - return true; - - if (location.getWorld().getName().equals("world")) { - City city = getCityHere(location.getChunk()); - - if (city == null) { - return RPMachine.getInstance().getProjectsManager().canInteractWithBlock(player, location); - } - return city.canInteractWithBlock(player, location); - } else { - return RPMachine.getInstance().getProjectsManager().canInteractWithBlock(player, location); - } - } - public double getCreationPrice() { return f.roundedPrice(cities.size()); } @@ -240,6 +198,11 @@ public void saveCity(City city) { super.saveEntity(city); } + @Override + public Collection getClaims() { + return getCities(); + } + public class CreationPriceFunction { final DoubleFunction baseFunc; final double ROUND_NEAREST = 100D; diff --git a/src/main/java/net/zyuiop/rpmachine/cities/City.java b/src/main/java/net/zyuiop/rpmachine/cities/City.java index aa8cf86..0010c9b 100755 --- a/src/main/java/net/zyuiop/rpmachine/cities/City.java +++ b/src/main/java/net/zyuiop/rpmachine/cities/City.java @@ -1,25 +1,35 @@ package net.zyuiop.rpmachine.cities; import net.zyuiop.rpmachine.RPMachine; -import net.zyuiop.rpmachine.common.VirtualLocation; import net.zyuiop.rpmachine.cities.politics.PoliticalSystem; import net.zyuiop.rpmachine.cities.politics.StateOfRights; +import net.zyuiop.rpmachine.claims.Claim; +import net.zyuiop.rpmachine.claims.CompoundClaim; +import net.zyuiop.rpmachine.claims.LeafClaim; import net.zyuiop.rpmachine.common.Plot; import net.zyuiop.rpmachine.common.VirtualChunk; +import net.zyuiop.rpmachine.common.VirtualLocation; import net.zyuiop.rpmachine.database.StoredEntity; import net.zyuiop.rpmachine.entities.LegalEntity; import net.zyuiop.rpmachine.json.JsonExclude; import net.zyuiop.rpmachine.permissions.CityPermissions; import net.zyuiop.rpmachine.permissions.DelegatedPermission; import net.zyuiop.rpmachine.permissions.Permission; -import org.bukkit.*; +import net.zyuiop.rpmachine.utils.TimeUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; import javax.annotation.Nonnull; import java.util.*; import java.util.stream.Collectors; -public class City implements LegalEntity, StoredEntity { +public class City extends CompoundClaim implements LegalEntity, StoredEntity { private final Set chunks = new HashSet<>(); private final Map> councils = new HashMap<>(); private final Map plots = new HashMap<>(); @@ -51,14 +61,89 @@ public class City implements LegalEntity, StoredEntity { private boolean requireInvite; - private static boolean sameDay(Date target) { - GregorianCalendar date = new GregorianCalendar(); - date.setTime(new Date()); + /** + * The base claim for the city + */ + private class CityBaseClaim extends LeafClaim { + @Override + public boolean isInside(Location location) { + return City.this.isInside(location); + } + + @Override + public boolean canBuild(Player player, Location location) { + return hasPermission(player, CityPermissions.BUILD_IN_CITY); + } + + @Override + public boolean canInteractWithBlock(Player player, Block block, Action action) { + // A modifier et à rendre customisable. + return inhabitants.contains(player.getUniqueId()); + } + + @Override + public boolean canInteractWithEntity(Player player, Entity entity) { + // A modifier et à rendre customisable. + return inhabitants.contains(player.getUniqueId()); + } + + @Override + public boolean canDamageEntity(Player player, Entity entity) { + return canBuild(player, entity.getLocation()); // TODO: make customizable + } + } + + /** + * A wrapper for claims in the city, allowing permissions hijacks when needed + */ + private class CityPlotWrapper implements Claim { + private final Plot wrapped; + + private CityPlotWrapper(Plot wrapped) { + this.wrapped = wrapped; + } + + @Override + public boolean isInside(Location location) { + return wrapped.isInside(location); + } + + @Override + public boolean canBuild(Player player, Location location) { + if (wrapped.getOwner() == null || wrapped.getOwner().equalsIgnoreCase(tag())) + return hasPermission(player, CityPermissions.BUILD_IN_EMPTY_PLOTS); + else + return wrapped.canBuild(player, location) || hasPermission(player, CityPermissions.BUILD_IN_PLOTS); + } + + @Override + public boolean canInteractWithBlock(Player player, Block block, Action action) { + if (wrapped.getOwner() == null || wrapped.getOwner().equalsIgnoreCase(tag())) + return hasPermission(player, CityPermissions.INTERACT_IN_EMPTY_PLOTS); + else + return wrapped.canInteractWithBlock(player, block, action) || hasPermission(player, CityPermissions.INTERACT_IN_PLOTS); + } + + @Override + public boolean canInteractWithEntity(Player player, Entity entity) { + if (wrapped.getOwner() == null || wrapped.getOwner().equalsIgnoreCase(tag())) + return hasPermission(player, CityPermissions.INTERACT_IN_EMPTY_PLOTS); + else + return wrapped.canInteractWithEntity(player, entity) || hasPermission(player, CityPermissions.INTERACT_IN_PLOTS); + } - GregorianCalendar compare = new GregorianCalendar(); - compare.setTime(target); + @Override + public boolean canDamageEntity(Player player, Entity entity) { + if (wrapped.getOwner() == null || wrapped.getOwner().equalsIgnoreCase(tag())) + return hasPermission(player, CityPermissions.INTERACT_IN_EMPTY_PLOTS); + else + return wrapped.canDamageEntity(player, entity) || hasPermission(player, CityPermissions.INTERACT_IN_PLOTS); + } - return compare.get(Calendar.DAY_OF_MONTH) == date.get(Calendar.DAY_OF_MONTH) && date.get(Calendar.MONTH) == compare.get(Calendar.MONTH) && date.get(Calendar.YEAR) == compare.get(Calendar.YEAR); + @Override + public Collection getClaims() { + return wrapped.getClaims(); + } } public String getCityName() { @@ -157,21 +242,21 @@ public void setMayorWage(double mayorWage) { this.mayorWage = mayorWage; } - public int getJoinTax() { - return joinTax; - } + public int getJoinTax() { + return joinTax; + } - public void setJoinTax(int joinTax) { - this.joinTax = joinTax; - } + public void setJoinTax(int joinTax) { + this.joinTax = joinTax; + } - public int getTpTax() { - return tpTax; - } + public int getTpTax() { + return tpTax; + } - public void setTpTax(int tpTax) { - this.tpTax = tpTax; - } + public void setTpTax(int tpTax) { + this.tpTax = tpTax; + } public double getVat() { return vat; @@ -182,14 +267,14 @@ public void setVat(double vat) { } public double getPlotSellTaxRate() { - return plotSellTaxRate; - } + return plotSellTaxRate; + } - public void setPlotSellTaxRate(double plotSellTaxRate) { - this.plotSellTaxRate = Math.min(plotSellTaxRate, 1.0); - } + public void setPlotSellTaxRate(double plotSellTaxRate) { + this.plotSellTaxRate = Math.min(plotSellTaxRate, 1.0); + } - public UUID getMayor() { + public UUID getMayor() { return mayor; } @@ -255,19 +340,11 @@ public double countInhabitants() { public boolean isAdjacent(Chunk chunk) { VirtualChunk ch = new VirtualChunk(chunk); - int x = ch.getX(); - int z = ch.getZ(); - - return (chunks.contains(new VirtualChunk(x + 1, z)) || chunks.contains(new VirtualChunk(x - 1, z)) || chunks.contains(new VirtualChunk(x, z + 1)) || chunks.contains(new VirtualChunk(x, z - 1))); - } - - public Plot getPlotHere(Location location) { - for (Plot plot : plots.values()) { - if (plot.getArea().isInside(location)) - return plot; - } - return null; + return (chunks.contains(ch.add(1, 0)) || + chunks.contains(ch.add(-1, 0)) || + chunks.contains(ch.add(0, 1)) || + chunks.contains(ch.add(0, -1))); } public void payTaxes(LegalEntity payer, double amt) { @@ -294,7 +371,7 @@ public void requestTaxes(boolean force) { String owner = plot.ownerTag(); Date lastPaid = ownerData.getLastTaxes(getCityName()); - if (force || lastPaid == null || !sameDay(lastPaid)) { + if (force || lastPaid == null || !TimeUtils.sameDay(lastPaid)) { double toPay = plot.getArea().computeArea() * taxes; if (!ownerData.transfer(toPay, this)) { @@ -341,30 +418,11 @@ public double simulateTaxes() { return ret; } - public boolean canInteractWithBlock(Player player, Location location) { - Plot plot = getPlotHere(location); - - if (plot == null) { - // A voir, tous les habitants de la ville peuvent-t-ils vraiment intéragir dans toutes les parcelles ? - return inhabitants.contains(player.getUniqueId()); - } else { - if (plot.getOwner() == null || plot.getOwner().equalsIgnoreCase(tag())) - return hasPermission(player, CityPermissions.INTERACT_IN_EMPTY_PLOTS); - return hasPermission(player, CityPermissions.INTERACT_IN_PLOTS) || plot.canBuild(player, location); - } + @Override + public boolean isInside(Location location) { + return getChunks().contains(new VirtualChunk(location.getChunk())); } - public boolean canBuild(Player player, Location location) { - Plot plot = getPlotHere(location); - - if (plot == null) { - return hasPermission(player, CityPermissions.BUILD_IN_CITY); - } else { - if (plot.getOwner() == null || plot.getOwner().equalsIgnoreCase(tag())) - return hasPermission(player, CityPermissions.BUILD_IN_EMPTY_PLOTS); - return hasPermission(player, CityPermissions.BUILD_IN_PLOTS) || plot.canBuild(player, location); - } - } @Override public void setUnpaidTaxes(String city, double amount) { @@ -489,6 +547,29 @@ public void setAllowSpawn(boolean allowSpawn) { this.allowSpawn = allowSpawn; } + @Override + public Collection getClaims() { + return plots.values(); + } + + @Override + public Optional getClaimAt(Location loc) { + return super.getClaimAt(loc).map(c -> new CityPlotWrapper((Plot) c)); + } + + public Optional getPlotAt(Location loc) { + return super.getClaimAt(loc).map(c -> (Plot) c); + } + + + /** + * @deprecated use getPlotAt + */ + @Deprecated + public Plot getPlotHere(Location location) { + return getPlotAt(location).orElse(null); + } + public static class CityTaxPayer { private Map unpaidTaxes = new HashMap<>(); private Map lastPaidTaxes = new HashMap<>(); diff --git a/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/CreateCommand.java b/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/CreateCommand.java index af8960b..b4b6cd8 100755 --- a/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/CreateCommand.java +++ b/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/CreateCommand.java @@ -14,6 +14,7 @@ import org.bukkit.entity.Player; import javax.annotation.Nonnull; +import java.util.Optional; import java.util.stream.StreamSupport; public class CreateCommand implements CityMemberSubCommand { @@ -76,8 +77,8 @@ public boolean run(Player player, @Nonnull City city, String command, String sub return true; } - Plot check = city.getPlotHere(block.getLocation()); - if (check != null) { + Optional check = city.getPlotAt(block.getLocation()); + if (check.isPresent()) { player.sendMessage(ChatColor.RED + "Une partie de votre sélection fait partie d'une autre parcelle."); return true; } diff --git a/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/InfoCommand.java b/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/InfoCommand.java index a89b996..7c11f31 100755 --- a/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/InfoCommand.java +++ b/src/main/java/net/zyuiop/rpmachine/cities/commands/plotsubcommands/InfoCommand.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Player; import java.util.ArrayList; +import java.util.Optional; import java.util.UUID; public class InfoCommand implements SubCommand { @@ -37,10 +38,11 @@ public boolean run(Player player, String command, String subCommand, String[] ar if (city == null) { player.sendMessage(ChatColor.RED + "Vous ne vous trouvez pas dans une vile."); } else { - Plot plot = city.getPlotHere(player.getLocation()); - if (plot == null) { + Optional oPlot = city.getPlotAt(player.getLocation()); + if (!oPlot.isPresent()) { player.sendMessage(ChatColor.RED + "Vous ne vous trouvez pas dans une parcelle."); } else { + Plot plot = oPlot.get(); player.sendMessage(ChatColor.GOLD + "-----[ Informations Parcelle ]-----"); player.sendMessage(ChatColor.YELLOW + "Nom : " + plot.getPlotName()); player.sendMessage(ChatColor.YELLOW + "Ville : " + city.getCityName()); diff --git a/src/main/java/net/zyuiop/rpmachine/cities/listeners/CitiesListener.java b/src/main/java/net/zyuiop/rpmachine/cities/listeners/CitiesListener.java index 29d76c6..c33c85f 100755 --- a/src/main/java/net/zyuiop/rpmachine/cities/listeners/CitiesListener.java +++ b/src/main/java/net/zyuiop/rpmachine/cities/listeners/CitiesListener.java @@ -28,7 +28,6 @@ public class CitiesListener implements Listener { - private static final String FIRE_STARTER_KEY = "fireStarter"; private final CitiesManager manager; //private final HashSet checkInteract; @@ -64,47 +63,6 @@ public CitiesListener(CitiesManager manager) { checkInteract.add(Material.BEACON);*/ } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onInteract(PlayerInteractEvent event) { - //if (event.getAction() == Action.RIGHT_CLICK_AIR) - // return; - - if (event.getAction() == Action.PHYSICAL) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getClickedBlock().getLocation())); - return; - } - - if (event.getItem() != null) { - Material type = event.getItem().getType(); - if (type == Material.BUCKET || type == Material.WATER_BUCKET || type == Material.LAVA_BUCKET || type == Material.FLINT_AND_STEEL) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getClickedBlock().getLocation())); - return; - } - } - - if (event.getClickedBlock() == null || !event.getClickedBlock().getType().isInteractable()) - return; - - if (event.getClickedBlock().getBlockData() instanceof Sign) - return; // Signs are always interactable - - event.setCancelled(!manager.canInteractWithBlock(event.getPlayer(), event.getClickedBlock().getLocation())); - } - - @EventHandler - public void onJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - PlayerData data = RPMachine.database().getPlayerData(player.getUniqueId()); - for (Map.Entry entry : data.getUnpaidTaxes().entrySet()) { - double topay = entry.getValue(); - if (topay <= 0) - continue; - - player.sendMessage(ChatColor.RED + "ATTENTION ! Votre compte ne contient pas assez d'argent pour payer vos impots."); - player.sendMessage(ChatColor.RED + "Vous devez " + ChatColor.AQUA + topay + ChatColor.RED + " à la ville de " + ChatColor.AQUA + entry.getKey()); - player.sendMessage(ChatColor.RED + "Payez les rapidement avec " + ChatColor.AQUA + "/city paytaxes " + entry.getKey()); - } - } @EventHandler public void onGamemode(PlayerGameModeChangeEvent event) { @@ -114,64 +72,6 @@ public void onGamemode(PlayerGameModeChangeEvent event) { event.getPlayer().sendMessage(ChatColor.RED + "Vous n'avez pas le droit d'accéder au gamemode créatif."); } } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPlace(BlockPlaceEvent event) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getBlock().getLocation())); - } - - @EventHandler - public void onEntityExplodeEvent(EntityExplodeEvent entityExplodeEvent) { - entityExplodeEvent.blockList().clear(); - } - - @EventHandler - public void onBlockExplode(BlockExplodeEvent explodeEvent) { - explodeEvent.blockList().clear(); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBreak(BlockBreakEvent event) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getBlock().getLocation())); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onInteractEntity(PlayerInteractEntityEvent event) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getRightClicked().getLocation())); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onInteractEntity(PlayerInteractAtEntityEvent event) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getRightClicked().getLocation())); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onFillBucket(PlayerBucketFillEvent event) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getBlockClicked().getLocation())); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEmptyBucket(PlayerBucketEmptyEvent event) { - event.setCancelled(!manager.canBuild(event.getPlayer(), event.getBlockClicked().getLocation())); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onHangingEntity(HangingBreakByEntityEvent event) { - if (event.getRemover() instanceof Player) - event.setCancelled(!manager.canBuild((Player) event.getRemover(), event.getEntity().getLocation())); - else { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onEntityDamage(EntityDamageByEntityEvent event) { - if (event.getDamager() instanceof Player && !(event.getEntity() instanceof Monster)) - event.setCancelled(!manager.canBuild((Player) event.getDamager(), event.getEntity().getLocation())); - else if (event.getDamager() instanceof Monster && event.getEntity() instanceof Hanging) - event.setCancelled(true); - } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onMove(PlayerMoveEvent event) { UUID id = event.getPlayer().getUniqueId(); @@ -276,35 +176,6 @@ public void onChat(AsyncPlayerChatEvent event) { } } - @EventHandler - public void onFireSpread(BlockSpreadEvent ev) { - if (ev.getSource().getType() == Material.FIRE) { - if (ev.getBlock().hasMetadata(FIRE_STARTER_KEY)) { - Player p = ev.getBlock().getMetadata(FIRE_STARTER_KEY).stream() - .filter(r -> r.getOwningPlugin().equals(RPMachine.getInstance())) - .map(r -> (Player) r.value()) - .findFirst() - .orElse(null); - - if (p == null) { - ev.setCancelled(manager.isProtected(ev.getBlock().getLocation())); - } else { - ev.setCancelled(manager.canBuild(p, ev.getBlock().getLocation())); - ev.getBlock().setMetadata(FIRE_STARTER_KEY, new FixedMetadataValue(RPMachine.getInstance(), p)); - } - } else { - ev.setCancelled(manager.isProtected(ev.getBlock().getLocation())); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onFireStart(BlockPlaceEvent ev) { - if (ev.getBlock().getType() == Material.FIRE) { - ev.getBlock().setMetadata(FIRE_STARTER_KEY, new FixedMetadataValue(RPMachine.getInstance(), ev.getPlayer())); - } - } - boolean isSameChunk(Location l1, Location l2) { Chunk c1 = l1.getChunk(); Chunk c2 = l2.getChunk(); diff --git a/src/main/java/net/zyuiop/rpmachine/claims/Claim.java b/src/main/java/net/zyuiop/rpmachine/claims/Claim.java new file mode 100644 index 0000000..d2e1d7b --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/Claim.java @@ -0,0 +1,63 @@ +package net.zyuiop.rpmachine.claims; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; + +/** + * @author Louis Vialar + */ +public interface Claim extends ClaimCollectionRegistry { + + /** + * Checks that a given location is inside the claim + * + * @param location the location to check + * @return true if the location is in the claim, false if it is not + */ + boolean isInside(Location location); + + /** + * Checks if a given player can build at a location inside the claim. + * If the location is not inside the claim, the behaviour is undefined. + * + * @param player the player trying to build + * @param location the location where the player is trying to build + * @return true if the player can build there + */ + boolean canBuild(Player player, Location location); + + /** + * Checks if a given player can interact with a given block. It is assumed that the block is inside the claim, + * behaviour is undefined if it is not. + * + * @param player the player trying to interact + * @param block the block the player tries to interact with + * @param action the interact action + * @return true if the player is allowed to interact with that block + */ + boolean canInteractWithBlock(Player player, Block block, Action action); + + /** + * Checks if a given player can interact with a given entity. It is assumed that the entity location is inside the + * claim, behaviour is undefined if it is not. + * + * @param player the player trying to interact + * @param entity the entity the player is trying to interact with + * @return true if the player is allowed to interact with that entity + */ + boolean canInteractWithEntity(Player player, Entity entity); + + /** + * Checks if a given player can damage a given entity. It is assumed that the entity location is inside the + * claim, behaviour is undefined if it is not. + * + * @param player the player trying to interact + * @param entity the entity the player is trying to interact with + * @return true if the player is allowed to interact with that entity + */ + boolean canDamageEntity(Player player, Entity entity); + +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/ClaimCollectionRegistry.java b/src/main/java/net/zyuiop/rpmachine/claims/ClaimCollectionRegistry.java new file mode 100644 index 0000000..a312620 --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/ClaimCollectionRegistry.java @@ -0,0 +1,24 @@ +package net.zyuiop.rpmachine.claims; + +import java.util.Collection; +import java.util.Optional; + +/** + * @author Louis Vialar + */ +public interface ClaimCollectionRegistry extends ClaimRegistry { + /** + * Gets the claim at a given location + * + * @param loc the location to check + * @return an optional claim, depending on whether there is or not a claim there + */ + default Optional getClaimAt(org.bukkit.Location loc) { + return getClaims().parallelStream().filter(c -> c.isInside(loc)).findAny().map(c -> (Claim) c); + } + + /** + * Get the claims contained in the current claim + */ + Collection getClaims(); +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/ClaimRegistry.java b/src/main/java/net/zyuiop/rpmachine/claims/ClaimRegistry.java new file mode 100644 index 0000000..71e886a --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/ClaimRegistry.java @@ -0,0 +1,43 @@ +package net.zyuiop.rpmachine.claims; + +import org.bukkit.Location; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * @author Louis Vialar + */ +public interface ClaimRegistry { + /** + * Gets the claim at a given location + * + * @param loc the location to check + * @return an optional claim, depending on whether there is or not a claim there + */ + Optional getClaimAt(org.bukkit.Location loc); + + default List getClaimTreeAt(Location loc) { + Optional current = getClaimAt(loc); + List tree = new ArrayList<>(); + + while (current.isPresent()) { + tree.add(current.get()); + current = current.get().getClaimAt(loc); + } + + return tree; + } + + /** + * Get, at the given location, the last claim of the tree, i.e. the only one that has no other child + * @param loc the location + * @return an optional, empty if there is no claim here + */ + default Optional getLowestLevelClaimAt(Location loc) { + List tree = getClaimTreeAt(loc); + + return tree.isEmpty() ? Optional.empty() : Optional.of(tree.get(tree.size() - 1)); + } +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/Claims.java b/src/main/java/net/zyuiop/rpmachine/claims/Claims.java new file mode 100644 index 0000000..4e66dc6 --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/Claims.java @@ -0,0 +1,51 @@ +package net.zyuiop.rpmachine.claims; + +import net.zyuiop.rpmachine.RPMachine; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * @author Louis Vialar + */ +public final class Claims implements ClaimRegistry { + private final List registries = new ArrayList<>(); + + public Claims(RPMachine machine) { + registries.add(machine.getCitiesManager()); + registries.add(machine.getProjectsManager()); + } + + @Override + public Optional getClaimAt(Location loc) { + return registries.stream() + .map(r -> r.getClaimAt(loc)) + .reduce(Optional.empty(), (o1, o2) -> o1.isPresent() ? o1 : o2); + } + + public boolean canBuild(Player player, Location location) { + return getClaimAt(location).map(c -> c.canBuild(player, location)).orElse(true); + } + + public boolean canInteractWithBlock(Player player, Block block, Action action) { + return getClaimAt(block.getLocation()).map(c -> c.canInteractWithBlock(player, block, action)).orElse(true); + } + + public boolean canInteractWithEntity(Player player, Entity entity) { + return getClaimAt(entity.getLocation()).map(c -> c.canInteractWithEntity(player, entity)).orElse(true); + } + + public boolean canDamageEntity(Player player, Entity entity) { + return getClaimAt(entity.getLocation()).map(c -> c.canDamageEntity(player, entity)).orElse(true); + } + + public boolean isClaimed(Location location) { + return getClaimAt(location).isPresent(); + } +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/ClaimsListener.java b/src/main/java/net/zyuiop/rpmachine/claims/ClaimsListener.java new file mode 100644 index 0000000..ae36aca --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/ClaimsListener.java @@ -0,0 +1,164 @@ +package net.zyuiop.rpmachine.claims; + +import net.zyuiop.rpmachine.RPMachine; +import net.zyuiop.rpmachine.database.PlayerData; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.block.data.type.Sign; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.*; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.player.*; +import org.bukkit.metadata.FixedMetadataValue; + +import java.util.Map; + +/** + * @author Louis Vialar + */ +public class ClaimsListener implements Listener { + private static final String FIRE_STARTER_KEY = "fireStarter"; + private final Claims claims; + + public ClaimsListener(Claims claims) { + this.claims = claims; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onInteract(PlayerInteractEvent event) { + //if (event.getAction() == Action.RIGHT_CLICK_AIR) + // return; + + if (event.getAction() == Action.PHYSICAL) { + event.setCancelled(!claims.canInteractWithBlock(event.getPlayer(), event.getClickedBlock(), event.getAction())); + return; + } + + if (event.getItem() != null) { + Material type = event.getItem().getType(); + if (type == Material.BUCKET || type == Material.WATER_BUCKET || type == Material.LAVA_BUCKET || type == Material.FLINT_AND_STEEL) { + event.setCancelled(!claims.canBuild(event.getPlayer(), event.getClickedBlock().getLocation())); + return; + } + } + + if (event.getClickedBlock() == null || !event.getClickedBlock().getType().isInteractable()) + return; + + if (event.getClickedBlock().getBlockData() instanceof Sign) + return; // Signs are always interactable + + event.setCancelled(!claims.canInteractWithBlock(event.getPlayer(), event.getClickedBlock(), event.getAction())); + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + PlayerData data = RPMachine.database().getPlayerData(player.getUniqueId()); + for (Map.Entry entry : data.getUnpaidTaxes().entrySet()) { + double topay = entry.getValue(); + if (topay <= 0) + continue; + + player.sendMessage(ChatColor.RED + "ATTENTION ! Votre compte ne contient pas assez d'argent pour payer vos impots."); + player.sendMessage(ChatColor.RED + "Vous devez " + ChatColor.AQUA + topay + ChatColor.RED + " à la ville de " + ChatColor.AQUA + entry.getKey()); + player.sendMessage(ChatColor.RED + "Payez les rapidement avec " + ChatColor.AQUA + "/city paytaxes " + entry.getKey()); + } + } + + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlace(BlockPlaceEvent event) { + event.setCancelled(!claims.canBuild(event.getPlayer(), event.getBlock().getLocation())); + } + + @EventHandler + public void onEntityExplodeEvent(EntityExplodeEvent entityExplodeEvent) { + entityExplodeEvent.blockList().clear(); + } + + @EventHandler + public void onBlockExplode(BlockExplodeEvent explodeEvent) { + explodeEvent.blockList().clear(); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBreak(BlockBreakEvent event) { + event.setCancelled(!claims.canBuild(event.getPlayer(), event.getBlock().getLocation())); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onInteractEntity(PlayerInteractEntityEvent event) { + event.setCancelled(!claims.canInteractWithEntity(event.getPlayer(), event.getRightClicked())); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onInteractEntity(PlayerInteractAtEntityEvent event) { + event.setCancelled(!claims.canInteractWithEntity(event.getPlayer(), event.getRightClicked())); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onFillBucket(PlayerBucketFillEvent event) { + event.setCancelled(!claims.canBuild(event.getPlayer(), event.getBlockClicked().getLocation())); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onEmptyBucket(PlayerBucketEmptyEvent event) { + event.setCancelled(!claims.canBuild(event.getPlayer(), event.getBlockClicked().getLocation())); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onHangingEntity(HangingBreakByEntityEvent event) { + if (event.getRemover() instanceof Player) + event.setCancelled(!claims.canBuild((Player) event.getRemover(), event.getEntity().getLocation())); + else { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityDamage(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player && !(event.getEntity() instanceof Monster)) + event.setCancelled(!claims.canDamageEntity((Player) event.getDamager(), event.getEntity())); + else if (event.getDamager() instanceof Monster && event.getEntity() instanceof Hanging) + event.setCancelled(true); + } + + + @EventHandler + public void onFireSpread(BlockSpreadEvent ev) { + if (ev.getSource().getType() == Material.FIRE) { + if (ev.getBlock().hasMetadata(FIRE_STARTER_KEY)) { + Player p = ev.getBlock().getMetadata(FIRE_STARTER_KEY).stream() + .filter(r -> r.getOwningPlugin().equals(RPMachine.getInstance())) + .map(r -> (Player) r.value()) + .findFirst() + .orElse(null); + + if (p == null) { + ev.setCancelled(claims.isClaimed(ev.getBlock().getLocation())); + } else { + ev.setCancelled(claims.canBuild(p, ev.getBlock().getLocation())); + ev.getBlock().setMetadata(FIRE_STARTER_KEY, new FixedMetadataValue(RPMachine.getInstance(), p)); + } + } else { + ev.setCancelled(claims.isClaimed(ev.getBlock().getLocation())); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onFireStart(BlockPlaceEvent ev) { + if (ev.getBlock().getType() == Material.FIRE) { + ev.getBlock().setMetadata(FIRE_STARTER_KEY, new FixedMetadataValue(RPMachine.getInstance(), ev.getPlayer())); + } + } + +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java b/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java new file mode 100644 index 0000000..6eeeedc --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java @@ -0,0 +1,47 @@ +package net.zyuiop.rpmachine.claims; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; + +/** + * A claim that contains zero, one, or more claims underneath it. + * @author Louis Vialar + */ +public abstract class CompoundClaim implements Claim { + private Claim outsideBehaviour = DenyAllClaim.INSTANCE; + + /** + * Set a claim that will handle the interactions that are inside the claim but outside any of the children + * @param behaviour + */ + protected void setOutsideBehaviour(Claim behaviour) { + this.outsideBehaviour = behaviour; + } + + public Claim getClaimOrDefault(Location location) { + return getClaimAt(location).orElse(outsideBehaviour); + } + + @Override + public boolean canBuild(Player player, Location location) { + return getClaimOrDefault(location).canBuild(player, location); + } + + @Override + public boolean canInteractWithBlock(Player player, Block block, Action action) { + return getClaimOrDefault(block.getLocation()).canInteractWithBlock(player, block, action); + } + + @Override + public boolean canInteractWithEntity(Player player, Entity entity) { + return getClaimOrDefault(entity.getLocation()).canInteractWithEntity(player, entity); + } + + @Override + public boolean canDamageEntity(Player player, Entity entity) { + return getClaimOrDefault(entity.getLocation()).canDamageEntity(player, entity); + } +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/DenyAllClaim.java b/src/main/java/net/zyuiop/rpmachine/claims/DenyAllClaim.java new file mode 100644 index 0000000..9ead011 --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/DenyAllClaim.java @@ -0,0 +1,50 @@ +package net.zyuiop.rpmachine.claims; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; + +import java.util.Collection; +import java.util.Collections; + +/** + * @author Louis Vialar + */ +public final class DenyAllClaim implements Claim { + public static final Claim INSTANCE = new DenyAllClaim(); + + private DenyAllClaim() {} + + + @Override + public boolean isInside(Location location) { + return false; + } + + @Override + public boolean canBuild(Player player, Location location) { + return false; + } + + @Override + public boolean canInteractWithBlock(Player player, Block block, Action action) { + return false; + } + + @Override + public boolean canInteractWithEntity(Player player, Entity entity) { + return false; + } + + @Override + public boolean canDamageEntity(Player player, Entity entity) { + return false; + } + + @Override + public Collection getClaims() { + return Collections.emptySet(); + } +} diff --git a/src/main/java/net/zyuiop/rpmachine/claims/LeafClaim.java b/src/main/java/net/zyuiop/rpmachine/claims/LeafClaim.java new file mode 100644 index 0000000..d092237 --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/claims/LeafClaim.java @@ -0,0 +1,14 @@ +package net.zyuiop.rpmachine.claims; + +import java.util.Collection; +import java.util.Collections; + +/** + * @author Louis Vialar + */ +public abstract class LeafClaim implements Claim { + @Override + public Collection getClaims() { + return Collections.emptySet(); + } +} diff --git a/src/main/java/net/zyuiop/rpmachine/common/Plot.java b/src/main/java/net/zyuiop/rpmachine/common/Plot.java index 81f2c60..43f6917 100755 --- a/src/main/java/net/zyuiop/rpmachine/common/Plot.java +++ b/src/main/java/net/zyuiop/rpmachine/common/Plot.java @@ -1,5 +1,8 @@ package net.zyuiop.rpmachine.common; +import net.zyuiop.rpmachine.claims.Claim; +import net.zyuiop.rpmachine.claims.CompoundClaim; +import net.zyuiop.rpmachine.claims.LeafClaim; import net.zyuiop.rpmachine.common.regions.Region; import net.zyuiop.rpmachine.entities.LegalEntity; import net.zyuiop.rpmachine.entities.Ownable; @@ -7,15 +10,20 @@ import net.zyuiop.rpmachine.utils.Messages; import org.bukkit.ChatColor; import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; import javax.annotation.Nullable; import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; -public class Plot implements Ownable { +public class Plot extends CompoundClaim implements Ownable { private String plotName; private Region area; private String owner = null; @@ -23,6 +31,44 @@ public class Plot implements Ownable { private Date deletionDate = null; // TODO: replace with RoleToken private CopyOnWriteArrayList plotMembers = new CopyOnWriteArrayList<>(); + private PlotBaseClaim baseClaim = new PlotBaseClaim(); + + public Plot() { + setOutsideBehaviour(baseClaim); + } + + private class PlotBaseClaim extends LeafClaim { + @Override + public boolean isInside(Location location) { + return area.isInside(location); + } + + private boolean canAct(Player player) { + return plotMembers.contains(player.getUniqueId()) || // membre du plot + (owner != null && owner() != null && owner().hasDelegatedPermission(player, PlotPermissions.BUILD_ON_PLOTS)); // owner du plot + } + + // TOOD: make this updatable. + @Override + public boolean canBuild(Player player, Location location) { + return canAct(player); + } + + @Override + public boolean canInteractWithBlock(Player player, Block block, Action action) { + return canAct(player); + } + + @Override + public boolean canInteractWithEntity(Player player, Entity entity) { + return canAct(player); + } + + @Override + public boolean canDamageEntity(Player player, Entity entity) { + return canAct(player); + } + } public CopyOnWriteArrayList getPlotMembers() { return plotMembers; @@ -90,9 +136,9 @@ public boolean isDueForDeletion() { return this.deletionDate != null; } - public boolean canBuild(Player player, Location location) { - return plotMembers.contains(player.getUniqueId()) || // membre du plot - (owner != null && owner() != null && owner().hasDelegatedPermission(player, PlotPermissions.BUILD_ON_PLOTS)); // owner du plot + @Override + public boolean isInside(Location location) { + return false; } public void sendDeletionWarning(String cityName) { @@ -111,4 +157,9 @@ public void sendDeletionWarning(String cityName) { public String ownerTag() { return getOwner(); } + + @Override + public Collection getClaims() { + return Collections.emptySet(); // TODO: make it possible to create subplots + } } diff --git a/src/main/java/net/zyuiop/rpmachine/common/VirtualChunk.java b/src/main/java/net/zyuiop/rpmachine/common/VirtualChunk.java index b956276..4673113 100755 --- a/src/main/java/net/zyuiop/rpmachine/common/VirtualChunk.java +++ b/src/main/java/net/zyuiop/rpmachine/common/VirtualChunk.java @@ -5,6 +5,7 @@ import org.bukkit.Chunk; public class VirtualChunk { + private String world = "world"; private int x; private int z; @@ -15,15 +16,17 @@ public VirtualChunk() { public VirtualChunk(Chunk chunk) { setX(chunk.getX()); setZ(chunk.getZ()); + setWorld(chunk.getWorld().getName()); } - public VirtualChunk(int x, int z) { + public VirtualChunk(String world, int x, int z) { this.x = x; this.z = z; + this.world = world; } public Chunk getLocation() { - return Bukkit.getWorld("world").getChunkAt(x, z); + return Bukkit.getWorld(world).getChunkAt(x, z); } public void setX(int x) { @@ -42,8 +45,16 @@ public int getZ() { return z; } + public String getWorld() { + return world; + } + + public void setWorld(String world) { + this.world = world; + } + public VirtualChunk add(int x, int z) { - return new VirtualChunk(this.x + x, this.z + z); + return new VirtualChunk(world, this.x + x, this.z + z); } public Line line(int startX, int startZ, int endX, int endZ) { @@ -55,6 +66,7 @@ public VirtualChunk(String string) { String[] parts = string.split("/"); x = Integer.parseInt(parts[0]); z = Integer.parseInt(parts[1]); + world = parts.length > 2 ? parts[2] : "world"; } @Override @@ -77,6 +89,6 @@ public int hashCode() { } public String toString() { - return x + "/" + z; + return x + "/" + z + "/" + world; } } diff --git a/src/main/java/net/zyuiop/rpmachine/projects/ProjectsManager.java b/src/main/java/net/zyuiop/rpmachine/projects/ProjectsManager.java index cb933ef..776a96e 100644 --- a/src/main/java/net/zyuiop/rpmachine/projects/ProjectsManager.java +++ b/src/main/java/net/zyuiop/rpmachine/projects/ProjectsManager.java @@ -1,6 +1,9 @@ package net.zyuiop.rpmachine.projects; import net.zyuiop.rpmachine.RPMachine; +import net.zyuiop.rpmachine.claims.Claim; +import net.zyuiop.rpmachine.claims.ClaimCollectionRegistry; +import net.zyuiop.rpmachine.claims.ClaimRegistry; import net.zyuiop.rpmachine.database.filestorage.FileEntityStore; import net.zyuiop.rpmachine.entities.LegalEntityRepository; import org.bukkit.Chunk; @@ -15,7 +18,7 @@ /** * @author zyuiop */ -public class ProjectsManager extends FileEntityStore implements LegalEntityRepository { +public class ProjectsManager extends FileEntityStore implements LegalEntityRepository, ClaimCollectionRegistry { private double globalVat; private double globalTax; private double globalSaleTax; @@ -115,4 +118,9 @@ public double getGlobalTax() { public double getGlobalSaleTax() { return globalSaleTax; } + + @Override + public Collection getClaims() { + return getZones().values(); + } } diff --git a/src/main/java/net/zyuiop/rpmachine/utils/TimeUtils.java b/src/main/java/net/zyuiop/rpmachine/utils/TimeUtils.java new file mode 100644 index 0000000..14f924d --- /dev/null +++ b/src/main/java/net/zyuiop/rpmachine/utils/TimeUtils.java @@ -0,0 +1,20 @@ +package net.zyuiop.rpmachine.utils; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * @author Louis Vialar + */ +public class TimeUtils { + public static boolean sameDay(Date target) { + GregorianCalendar date = new GregorianCalendar(); + date.setTime(new Date()); + + GregorianCalendar compare = new GregorianCalendar(); + compare.setTime(target); + + return compare.get(Calendar.DAY_OF_MONTH) == date.get(Calendar.DAY_OF_MONTH) && date.get(Calendar.MONTH) == compare.get(Calendar.MONTH) && date.get(Calendar.YEAR) == compare.get(Calendar.YEAR); + } +} From 3f58acc91d03e4bce6c0c0ce81e1af6ce85c12fb Mon Sep 17 00:00:00 2001 From: zyuiop Date: Sat, 7 Sep 2019 16:17:17 +0200 Subject: [PATCH 2/2] Improve actual implementation on plots --- .../rpmachine/claims/CompoundClaim.java | 13 +--- .../net/zyuiop/rpmachine/common/Plot.java | 59 ++++++++----------- .../zyuiop/rpmachine/projects/Project.java | 5 +- .../net/zyuiop/rpmachine/utils/Messages.java | 3 + 4 files changed, 33 insertions(+), 47 deletions(-) diff --git a/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java b/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java index 6eeeedc..109ce64 100644 --- a/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java +++ b/src/main/java/net/zyuiop/rpmachine/claims/CompoundClaim.java @@ -1,5 +1,6 @@ package net.zyuiop.rpmachine.claims; +import net.zyuiop.rpmachine.json.JsonExclude; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; @@ -11,18 +12,8 @@ * @author Louis Vialar */ public abstract class CompoundClaim implements Claim { - private Claim outsideBehaviour = DenyAllClaim.INSTANCE; - - /** - * Set a claim that will handle the interactions that are inside the claim but outside any of the children - * @param behaviour - */ - protected void setOutsideBehaviour(Claim behaviour) { - this.outsideBehaviour = behaviour; - } - public Claim getClaimOrDefault(Location location) { - return getClaimAt(location).orElse(outsideBehaviour); + return getClaimAt(location).orElse(DenyAllClaim.INSTANCE); } @Override diff --git a/src/main/java/net/zyuiop/rpmachine/common/Plot.java b/src/main/java/net/zyuiop/rpmachine/common/Plot.java index 43f6917..4c92d1f 100755 --- a/src/main/java/net/zyuiop/rpmachine/common/Plot.java +++ b/src/main/java/net/zyuiop/rpmachine/common/Plot.java @@ -2,10 +2,10 @@ import net.zyuiop.rpmachine.claims.Claim; import net.zyuiop.rpmachine.claims.CompoundClaim; -import net.zyuiop.rpmachine.claims.LeafClaim; import net.zyuiop.rpmachine.common.regions.Region; import net.zyuiop.rpmachine.entities.LegalEntity; import net.zyuiop.rpmachine.entities.Ownable; +import net.zyuiop.rpmachine.json.JsonExclude; import net.zyuiop.rpmachine.permissions.PlotPermissions; import net.zyuiop.rpmachine.utils.Messages; import org.bukkit.ChatColor; @@ -29,45 +29,38 @@ public class Plot extends CompoundClaim implements Ownable { private String owner = null; private PlotSettings plotSettings = new PlotSettings(); private Date deletionDate = null; + // TODO: allow subplots // TODO: replace with RoleToken private CopyOnWriteArrayList plotMembers = new CopyOnWriteArrayList<>(); - private PlotBaseClaim baseClaim = new PlotBaseClaim(); - public Plot() { - setOutsideBehaviour(baseClaim); + private boolean hasPlotPermission(Player player) { + return plotMembers.contains(player.getUniqueId()) || // membre du plot + hasOwnerPermission(player); // owner du plot } - private class PlotBaseClaim extends LeafClaim { - @Override - public boolean isInside(Location location) { - return area.isInside(location); - } - - private boolean canAct(Player player) { - return plotMembers.contains(player.getUniqueId()) || // membre du plot - (owner != null && owner() != null && owner().hasDelegatedPermission(player, PlotPermissions.BUILD_ON_PLOTS)); // owner du plot - } + protected boolean hasOwnerPermission(Player player) { + return owner != null && owner() != null && owner().hasDelegatedPermission(player, PlotPermissions.BUILD_ON_PLOTS); + } - // TOOD: make this updatable. - @Override - public boolean canBuild(Player player, Location location) { - return canAct(player); - } + // TODO: allow customization for external players + @Override + public boolean canBuild(Player player, Location location) { + return super.canBuild(player, location) || hasPlotPermission(player); + } - @Override - public boolean canInteractWithBlock(Player player, Block block, Action action) { - return canAct(player); - } + @Override + public boolean canInteractWithBlock(Player player, Block block, Action action) { + return super.canInteractWithBlock(player, block, action) || hasPlotPermission(player); + } - @Override - public boolean canInteractWithEntity(Player player, Entity entity) { - return canAct(player); - } + @Override + public boolean canInteractWithEntity(Player player, Entity entity) { + return super.canInteractWithEntity(player, entity) || hasPlotPermission(player); + } - @Override - public boolean canDamageEntity(Player player, Entity entity) { - return canAct(player); - } + @Override + public boolean canDamageEntity(Player player, Entity entity) { + return super.canDamageEntity(player, entity) || hasPlotPermission(player); } public CopyOnWriteArrayList getPlotMembers() { @@ -138,7 +131,7 @@ public boolean isDueForDeletion() { @Override public boolean isInside(Location location) { - return false; + return area.isInside(location); } public void sendDeletionWarning(String cityName) { @@ -158,7 +151,7 @@ public String ownerTag() { return getOwner(); } - @Override + @Override @JsonExclude public Collection getClaims() { return Collections.emptySet(); // TODO: make it possible to create subplots } diff --git a/src/main/java/net/zyuiop/rpmachine/projects/Project.java b/src/main/java/net/zyuiop/rpmachine/projects/Project.java index 9e1b51b..0100359 100644 --- a/src/main/java/net/zyuiop/rpmachine/projects/Project.java +++ b/src/main/java/net/zyuiop/rpmachine/projects/Project.java @@ -216,9 +216,8 @@ else if (admins.containsKey(player.getUniqueId())) } @Override - public boolean canBuild(Player player, Location location) { - return getPlotMembers().contains(player.getUniqueId()) || - (ownerTag() != null && owner() != null && owner().hasDelegatedPermission(player, ProjectPermissions.BUILD_ON_PROJECT)); + protected boolean hasOwnerPermission(Player player) { + return ownerTag() != null && owner() != null && owner().hasDelegatedPermission(player, ProjectPermissions.BUILD_ON_PROJECT); } public void removeAdmin(UUID id) { diff --git a/src/main/java/net/zyuiop/rpmachine/utils/Messages.java b/src/main/java/net/zyuiop/rpmachine/utils/Messages.java index ef350b9..36d6be8 100644 --- a/src/main/java/net/zyuiop/rpmachine/utils/Messages.java +++ b/src/main/java/net/zyuiop/rpmachine/utils/Messages.java @@ -29,6 +29,9 @@ public static void credit(LegalEntity entity, double amount, String reason) { } public static void sendMessage(LegalEntity entity, String message) { + if (entity == null) + return; + entity.getOnlineAdministrators().forEach(pl -> pl.sendMessage(entityPrefix(pl, entity) + message)); entity.getOfflineAdministrators().forEach(adm -> RPMachine.getInstance().getDiscordManager()