diff --git a/bukkit/build.gradle b/bukkit/build.gradle index 60faae1..79557fc 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -44,6 +44,10 @@ repositories { name = 'bstats' url = 'https://repo.codemc.org/repository/maven-public' } + maven { + name = 'dynmap-repo' + url = 'http://repo.mikeprimm.com' + } maven { name = 'essentials' url = 'https://ci.ender.zone/plugin/repository/everything/' @@ -60,6 +64,10 @@ repositories { name = 'permissionsex' url = 'https://repo.glaremasters.me/repository/permissionsex' } + maven { + name = 'placeholderapi' + url = 'http://repo.extendedclip.com/content/repositories/placeholderapi' + } maven { name = 'sk89q' url = 'https://maven.sk89q.com/repo' @@ -102,9 +110,11 @@ dependencies { compileOnly "org.bukkit:bukkit:$spigotVersion" compileOnly "org.spigotmc:spigot:$spigotVersion" // Plugins + compileOnly "ca.stellardrift.permissionsex:permissionsex-bukkit:2.0-SNAPSHOT" + compileOnly "me.clip:placeholderapi:2.10.4" compileOnly "net.ess3:EssentialsX:2.17.1" compileOnly "net.milkbowl.vault:VaultAPI:1.7" - compileOnly "ca.stellardrift.permissionsex:permissionsex-bukkit:2.0-SNAPSHOT" + compileOnly "us.dynmap:dynmap-api:3.0-SNAPSHOT" // Libs compileOnly "aopalliance:aopalliance:1.0" compileOnly "co.aikar:acf-core:0.5.0-SNAPSHOT" diff --git a/bukkit/src/main/java/com/griefdefender/GDCore.java b/bukkit/src/main/java/com/griefdefender/GDCore.java index 1b2c452..d1b43a1 100644 --- a/bukkit/src/main/java/com/griefdefender/GDCore.java +++ b/bukkit/src/main/java/com/griefdefender/GDCore.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; @@ -44,6 +45,8 @@ import com.griefdefender.api.data.PlayerData; import com.griefdefender.api.permission.flag.Flag; import com.griefdefender.cache.PermissionHolderCache; +import com.griefdefender.claim.GDClaim; +import com.griefdefender.storage.BaseStorage; @Singleton public class GDCore implements Core { @@ -81,6 +84,13 @@ public Optional getPlayerData(UUID worldUniqueId, UUID playerUniqueI @Override public List getAllPlayerClaims(UUID playerUniqueId) { List claimList = new ArrayList<>(); + if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) { + final World world = Bukkit.getWorlds().get(0); + final ClaimManager claimManager = this.getClaimManager(world.getUID()); + claimList.addAll(claimManager.getPlayerClaims(playerUniqueId)); + return ImmutableList.copyOf(claimList); + } + for (World world : Bukkit.getServer().getWorlds()) { claimList.addAll(this.getClaimManager(world.getUID()).getPlayerClaims(playerUniqueId)); } diff --git a/bukkit/src/main/java/com/griefdefender/GDPlayerData.java b/bukkit/src/main/java/com/griefdefender/GDPlayerData.java index 914f993..8918b76 100644 --- a/bukkit/src/main/java/com/griefdefender/GDPlayerData.java +++ b/bukkit/src/main/java/com/griefdefender/GDPlayerData.java @@ -684,6 +684,13 @@ public boolean inPvpCombat(World world) { return true; } + public void onClaimDelete() { + this.lastShovelLocation = null; + this.eventResultCache = null; + this.claimResizing = null; + this.claimSubdividing = null; + } + public void onDisconnect() { this.visualBlocks.clear(); this.claimMode = false; diff --git a/bukkit/src/main/java/com/griefdefender/GriefDefenderPlugin.java b/bukkit/src/main/java/com/griefdefender/GriefDefenderPlugin.java index 6fc8710..f89e61d 100644 --- a/bukkit/src/main/java/com/griefdefender/GriefDefenderPlugin.java +++ b/bukkit/src/main/java/com/griefdefender/GriefDefenderPlugin.java @@ -185,9 +185,11 @@ import com.griefdefender.permission.GDPermissionUser; import com.griefdefender.permission.flag.GDCustomFlagDefinition; import com.griefdefender.permission.flag.GDFlags; +import com.griefdefender.provider.DynmapProvider; import com.griefdefender.provider.EssentialsProvider; import com.griefdefender.provider.LuckPermsProvider; import com.griefdefender.provider.PermissionProvider; +import com.griefdefender.provider.PlaceholderProvider; import com.griefdefender.provider.VaultProvider; import com.griefdefender.registry.ChatTypeRegistryModule; import com.griefdefender.registry.ClaimTypeRegistryModule; @@ -255,6 +257,7 @@ public class GriefDefenderPlugin { public BaseStorage dataStore; + private DynmapProvider dynmapProvider; private EssentialsProvider essentialsProvider; private WorldEditProvider worldEditProvider; private WorldGuardProvider worldGuardProvider; @@ -453,6 +456,17 @@ public void onEnable() { if (Bukkit.getPluginManager().getPlugin("Essentials") != null) { this.essentialsProvider = new EssentialsProvider(); } + + if (Bukkit.getPluginManager().getPlugin("dynmap") != null) { + this.dynmapProvider = new DynmapProvider(); + } + + if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null){ + this.getLogger().info("Detected PlaceholderAPI. Enabling GD PlaceholderAPI expansion..."); + new PlaceholderProvider(); + this.getLogger().info("GriefDefender PlaceholderAPI expansion enabled!"); + } + if (this.dataStore == null) { try { this.dataStore = new FileStorage(); @@ -1069,6 +1083,9 @@ public boolean isEconomyModeEnabled() { return false; } + public DynmapProvider getDynmapProvider() { + return this.dynmapProvider; + } public EssentialsProvider getEssentialsProvider() { return this.essentialsProvider; diff --git a/bukkit/src/main/java/com/griefdefender/claim/GDClaim.java b/bukkit/src/main/java/com/griefdefender/claim/GDClaim.java index 414e798..11d05ee 100644 --- a/bukkit/src/main/java/com/griefdefender/claim/GDClaim.java +++ b/bukkit/src/main/java/com/griefdefender/claim/GDClaim.java @@ -84,6 +84,7 @@ import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; +import net.kyori.text.serializer.plain.PlainComponentSerializer; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; import org.bukkit.Bukkit; @@ -365,6 +366,14 @@ public Optional getName() { return this.claimData.getName(); } + public String getFriendlyName() { + final Component claimName = this.claimData.getName().orElse(null); + if (claimName == null) { + return "none"; + } + return PlainComponentSerializer.INSTANCE.serialize(claimName); + } + public Component getFriendlyNameType() { return this.getFriendlyNameType(false); } @@ -518,6 +527,20 @@ public Component getOwnerName() { return TextComponent.of(this.getOwnerPlayerData().getPlayerName()); } + public String getOwnerFriendlyName() { + if (this.isAdminClaim()) { + return "administrator"; + } + if (this.isWilderness()) { + return "wilderness"; + } + final GDPlayerData playerData = this.ownerPlayerData; + if (playerData == null) { + return "[unknown]"; + } + return playerData.getPlayerName(); + } + @Override public boolean contains(Vector3i pos, boolean excludeChildren) { return this.contains(pos.getX(), pos.getY(), pos.getZ(), excludeChildren, null, false); diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandon.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandon.java index 30318c2..d90299c 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandon.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandon.java @@ -175,6 +175,7 @@ private static Consumer createConfirmationConsumer(Player player, return; } + playerData.onClaimDelete(); // remove all context permissions PermissionUtil.getInstance().clearPermissions(claim); playerData.revertActiveVisual(player); diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandonAll.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandonAll.java index dd51b3f..d8a16d8 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandonAll.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimAbandonAll.java @@ -151,6 +151,7 @@ private static Consumer createConfirmationConsumer(GDPermissionUs playerData.useRestoreSchematic = event.isRestoring(); GriefDefenderPlugin.getInstance().dataStore.abandonClaimsForPlayer(user, allowedClaims); playerData.useRestoreSchematic = false; + playerData.onClaimDelete(); if (GriefDefenderPlugin.getInstance().isEconomyModeEnabled()) { final Economy economy = GriefDefenderPlugin.getInstance().getVaultProvider().getApi(); diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimContract.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimContract.java index ee0de5b..d25fd3f 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimContract.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimContract.java @@ -111,6 +111,12 @@ public void execute(Player player, int amount, @Optional String direction) { } else if (face == BlockFace.SOUTH) { point1 = new Vector3i(lesser.getX(), lesser.getY(), lesser.getZ()); point2 = new Vector3i(greater.getX(), greater.getY(), greater.getZ() - amount); + } else if (face == BlockFace.UP) { + point1 = new Vector3i(lesser.getX(), lesser.getY() - amount, lesser.getZ()); + point2 = new Vector3i(greater.getX(), greater.getY(), greater.getZ() + amount); + } else if (face == BlockFace.DOWN) { + point1 = new Vector3i(lesser.getX(), lesser.getY(), lesser.getZ()); + point2 = new Vector3i(greater.getX(), greater.getY() - amount, greater.getZ() + amount); } } else { point1 = new Vector3i( diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimDelete.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimDelete.java index b076b86..30e1256 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimDelete.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimDelete.java @@ -106,6 +106,7 @@ private static Consumer createConfirmationConsumer(Player player, return; } + playerData.onClaimDelete(); PermissionUtil.getInstance().clearPermissions((GDClaim) claim); playerData.revertActiveVisual(player); diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAll.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAll.java index 4b49eb1..3c46925 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAll.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAll.java @@ -102,6 +102,7 @@ private static Consumer createConfirmationConsumer(Player src, Of } GriefDefenderPlugin.getInstance().dataStore.deleteClaimsForPlayer(otherPlayer.getUniqueId()); + playerData.onClaimDelete(); if (src != null) { final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.DELETE_ALL_PLAYER_SUCCESS, ImmutableMap.of( "player", TextComponent.of(otherPlayer.getName()).color(TextColor.AQUA))); diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAllAdmin.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAllAdmin.java index dc7ce0a..e2fbae1 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAllAdmin.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimDeleteAllAdmin.java @@ -86,7 +86,8 @@ private static Consumer createConfirmationConsumer(Player player) GriefDefenderPlugin.sendMessage(player, GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.DELETE_ALL_TYPE_SUCCESS, ImmutableMap.of("type", TextComponent.of("ADMIN").color(TextColor.RED)))); - GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(player.getWorld(), player.getUniqueId()); + final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(player.getWorld(), player.getUniqueId()); + playerData.onClaimDelete(); playerData.revertActiveVisual(player); }; } diff --git a/bukkit/src/main/java/com/griefdefender/command/CommandClaimExpand.java b/bukkit/src/main/java/com/griefdefender/command/CommandClaimExpand.java index bda0b63..e66cd8b 100644 --- a/bukkit/src/main/java/com/griefdefender/command/CommandClaimExpand.java +++ b/bukkit/src/main/java/com/griefdefender/command/CommandClaimExpand.java @@ -111,6 +111,12 @@ public void execute(Player player, int amount, @Optional String direction) { } else if (face == BlockFace.SOUTH) { point1 = new Vector3i(lesser.getX(), lesser.getY(), lesser.getZ()); point2 = new Vector3i(greater.getX(), greater.getY(), greater.getZ() + amount); + } else if (face == BlockFace.UP) { + point1 = new Vector3i(lesser.getX(), lesser.getY(), lesser.getZ()); + point2 = new Vector3i(greater.getX(), greater.getY() + amount, greater.getZ() + amount); + } else if (face == BlockFace.DOWN) { + point1 = new Vector3i(lesser.getX(), lesser.getY() - amount, lesser.getZ()); + point2 = new Vector3i(greater.getX(), greater.getY(), greater.getZ() + amount); } } else { point1 = new Vector3i( diff --git a/bukkit/src/main/java/com/griefdefender/configuration/category/DynmapCategory.java b/bukkit/src/main/java/com/griefdefender/configuration/category/DynmapCategory.java new file mode 100644 index 0000000..cc45312 --- /dev/null +++ b/bukkit/src/main/java/com/griefdefender/configuration/category/DynmapCategory.java @@ -0,0 +1,77 @@ +/* + * This file is part of GriefDefender, licensed under the MIT License (MIT). + * + * Copyright (c) bloodmc + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.griefdefender.configuration.category; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ninja.leaping.configurate.objectmapping.Setting; +import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; + +@ConfigSerializable +public class DynmapCategory { + + @Setting("owner-styles") + public Map ownerStyles = new HashMap<>(); + + @Setting + public int minzoom = 0; + + @Setting("layer-priority") + public int layerPriority = 10; + + @Setting("layer-hide-by-default") + public boolean layerHideByDefault = false; + + @Setting("use-3d-regions") + public boolean use3dRegions = false; + + @Setting("hidden-regions") + public List hiddenRegions = new ArrayList<>(); + + @Setting("visible-regions") + public List visibleRegions = new ArrayList<>(); + + @Setting("info-window-basic") + public String infoWindowBasic = "
" + + "Name: %claimname%
" + + "Owner: %owner%
" + + "Type: %gdtype%
" + + "Last Seen: %lastseen%
" + + "Permission Trust: %managers%
" + + "Trust: %builders%
" + + "Container Trust: %containers%
" + + "Access Trust: %accessors%
"; + + @Setting("info-window-admin") + public String infoWindowAdmin = "
" + + "Administrator Claim
" + + "Permission Trust: %managers%
" + + "Trust: %builders%
" + + "Container Trust: %containers%
" + + "Access Trust: %accessors%
"; +} diff --git a/bukkit/src/main/java/com/griefdefender/configuration/category/DynmapOwnerStyleCategory.java b/bukkit/src/main/java/com/griefdefender/configuration/category/DynmapOwnerStyleCategory.java new file mode 100644 index 0000000..5ae16f0 --- /dev/null +++ b/bukkit/src/main/java/com/griefdefender/configuration/category/DynmapOwnerStyleCategory.java @@ -0,0 +1,50 @@ +/* + * This file is part of GriefDefender, licensed under the MIT License (MIT). + * + * Copyright (c) bloodmc + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.griefdefender.configuration.category; + +import ninja.leaping.configurate.objectmapping.Setting; +import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable; + +@ConfigSerializable +public class DynmapOwnerStyleCategory { + + @Setting("stroke-color") + public String strokeColor = "#FF0000"; + + @Setting("stroke-opacity") + public double strokeOpacity = 0.8d; + + @Setting("stroke-weight") + public int strokeWeight = 3; + + @Setting("fill-color") + public String fillColor = "#FF0000"; + + @Setting("fill-opacity") + public double fillOpacity = 0.35d; + + @Setting("label") + public String label = "none"; +} diff --git a/bukkit/src/main/java/com/griefdefender/configuration/type/GlobalConfig.java b/bukkit/src/main/java/com/griefdefender/configuration/type/GlobalConfig.java index 038627c..009ea69 100644 --- a/bukkit/src/main/java/com/griefdefender/configuration/type/GlobalConfig.java +++ b/bukkit/src/main/java/com/griefdefender/configuration/type/GlobalConfig.java @@ -26,6 +26,7 @@ import com.griefdefender.configuration.category.CustomFlagGroupDefinitionCategory; import com.griefdefender.configuration.category.DefaultPermissionCategory; +import com.griefdefender.configuration.category.DynmapCategory; import com.griefdefender.configuration.category.EconomyCategory; import com.griefdefender.configuration.category.MessageCategory; import com.griefdefender.configuration.category.MigratorCategory; @@ -64,6 +65,8 @@ public class GlobalConfig extends ConfigBase { + "\nThese contexts may change, See https://github.com/bloodmc/GriefDefender/wiki for latest information.") public CustomFlagGroupDefinitionCategory customFlags = new CustomFlagGroupDefinitionCategory(); @Setting + public DynmapCategory dynmap = new DynmapCategory(); + @Setting public EconomyCategory economy = new EconomyCategory(); @Setting public PlayerDataCategory playerdata = new PlayerDataCategory(); diff --git a/bukkit/src/main/java/com/griefdefender/listener/PlayerEventHandler.java b/bukkit/src/main/java/com/griefdefender/listener/PlayerEventHandler.java index a6e3b08..a8ff281 100644 --- a/bukkit/src/main/java/com/griefdefender/listener/PlayerEventHandler.java +++ b/bukkit/src/main/java/com/griefdefender/listener/PlayerEventHandler.java @@ -716,7 +716,10 @@ public void onPlayerInteractBlockSecondary(PlayerInteractEvent event) { return; } final GDClaim claim = this.dataStore.getClaimAt(location); - final TrustType trustType = event.isBlockInHand() && event.getAction() != Action.PHYSICAL ? TrustTypes.BUILDER : TrustTypes.ACCESSOR; + TrustType trustType = event.isBlockInHand() && event.getAction() != Action.PHYSICAL ? TrustTypes.BUILDER : TrustTypes.ACCESSOR; + if (clickedBlock != null && clickedBlock.getType().toString().contains("DOOR")) { + trustType = TrustTypes.ACCESSOR; + } if (GDFlags.INTERACT_BLOCK_SECONDARY && playerData != null) { String permission = GDPermissions.INTERACT_BLOCK_SECONDARY; if (event.getAction() == Action.PHYSICAL) { diff --git a/bukkit/src/main/java/com/griefdefender/migrator/GriefPreventionMigrator.java b/bukkit/src/main/java/com/griefdefender/migrator/GriefPreventionMigrator.java index 5eaa057..9be5f24 100644 --- a/bukkit/src/main/java/com/griefdefender/migrator/GriefPreventionMigrator.java +++ b/bukkit/src/main/java/com/griefdefender/migrator/GriefPreventionMigrator.java @@ -528,6 +528,10 @@ private static void createClaim(World world, File file, boolean parentsOnly) { e1.printStackTrace(); return; } + if (region.getChildrenMap().isEmpty()) { + GriefDefenderPlugin.getInstance().getLogger().info("Detected corrupted claim file '" + file + "'. Skipping..."); + return; + } if (parentsOnly && region.getChildrenMap().get("Parent Claim ID").getInt() != -1) { return; } diff --git a/bukkit/src/main/java/com/griefdefender/provider/DynmapProvider.java b/bukkit/src/main/java/com/griefdefender/provider/DynmapProvider.java new file mode 100644 index 0000000..c18b7e7 --- /dev/null +++ b/bukkit/src/main/java/com/griefdefender/provider/DynmapProvider.java @@ -0,0 +1,362 @@ +/* + * This file is part of GriefDefender, licensed under the MIT License (MIT). + * + * Copyright (c) bloodmc + * Copyright (c) Dockter + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.griefdefender.provider; + +import com.flowpowered.math.vector.Vector3i; +import com.griefdefender.GDBootstrap; +import com.griefdefender.GriefDefenderPlugin; +import com.griefdefender.api.GriefDefender; +import com.griefdefender.api.claim.Claim; +import com.griefdefender.api.claim.ClaimManager; +import com.griefdefender.api.claim.ClaimTypes; +import com.griefdefender.api.claim.TrustTypes; +import com.griefdefender.api.event.ChangeClaimEvent; +import com.griefdefender.api.event.CreateClaimEvent; +import com.griefdefender.api.event.RemoveClaimEvent; +import com.griefdefender.claim.GDClaim; +import com.griefdefender.configuration.category.DynmapOwnerStyleCategory; +import com.griefdefender.configuration.category.DynmapCategory; +import com.griefdefender.util.PlayerUtil; + +import net.kyori.event.method.annotation.Subscribe; +import net.kyori.text.serializer.plain.PlainComponentSerializer; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.scheduler.BukkitRunnable; +import org.dynmap.DynmapCommonAPI; +import org.dynmap.DynmapCommonAPIListener; +import org.dynmap.markers.AreaMarker; +import org.dynmap.markers.MarkerAPI; +import org.dynmap.markers.MarkerSet; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Logger; + +public class DynmapProvider { + + private final Logger logger; + private DynmapCommonAPI dynmap; + private MarkerAPI markerapi; + private DynmapCategory cfg; + private DynmapOwnerStyleCategory defaultStyle = new DynmapOwnerStyleCategory(); + private MarkerSet set; + private boolean disabled = false; + private boolean reload = false; + + public DynmapProvider() { + this.logger = GriefDefenderPlugin.getInstance().getLogger(); + logger.info("Initializing GriefDefender Dynmap provider..."); + DynmapCommonAPIListener.register(new DynmapCommonAPIListener() { + @Override + public void apiEnabled(DynmapCommonAPI api) { + dynmap = api; + cfg = GriefDefenderPlugin.getGlobalConfig().getConfig().dynmap; + activate(); + } + }); + if (this.markerapi == null) { + this.logger.severe("Error loading Dynmap Provider! Could not locate Marker API."); + return; + } + GriefDefender.getEventManager().register(this); + } + + private Map areaMarkers = new HashMap(); + + private String getWindowInfo(Claim claim, AreaMarker marker) { + String info; + if (claim.isAdminClaim()) { + info = "
" + this.cfg.infoWindowAdmin + "
"; + } else { + info = "
" + this.cfg.infoWindowBasic + "
"; + } + info = info.replace("%owner%", ((GDClaim) claim).getOwnerFriendlyName()); + info = info.replace("%area%", Integer.toString(claim.getArea())); + info = info.replace("%claimname%", + claim.getData().getName().isPresent() + ? PlainComponentSerializer.INSTANCE.serialize(claim.getName().get()) + : "none"); + info = info.replace("%lastseen%", claim.getData().getDateLastActive().toString()); + info = info.replace("%gdtype%", claim.getType().toString()); + + final List builderList = claim.getUserTrusts(TrustTypes.BUILDER); + final List containerList = claim.getUserTrusts(TrustTypes.CONTAINER); + final List accessorList = claim.getUserTrusts(TrustTypes.ACCESSOR); + final List managerList = claim.getUserTrusts(TrustTypes.MANAGER); + + String trusted = ""; + for (int i = 0; i < builderList.size(); i++) { + if (i > 0) { + trusted += ", "; + } + final UUID uuid = builderList.get(i); + final String userName = PlayerUtil.getInstance().getUserName(uuid); + if (userName.equalsIgnoreCase("unknown")) { + trusted += uuid.toString(); + } else { + trusted += userName; + } + } + info = info.replace("%builders%", trusted); + + trusted = ""; + for (int i = 0; i < containerList.size(); i++) { + if (i > 0) { + trusted += ", "; + } + final UUID uuid = containerList.get(i); + final String userName = PlayerUtil.getInstance().getUserName(uuid); + if (userName.equalsIgnoreCase("unknown")) { + trusted += uuid.toString(); + } else { + trusted += userName; + } + } + info = info.replace("%containers%", trusted); + + trusted = ""; + for (int i = 0; i < accessorList.size(); i++) { + if (i > 0) { + trusted += ", "; + } + final UUID uuid = accessorList.get(i); + final String userName = PlayerUtil.getInstance().getUserName(uuid); + if (userName.equalsIgnoreCase("unknown")) { + trusted += uuid.toString(); + } else { + trusted += userName; + } + } + info = info.replace("%accessors%", trusted); + + trusted = ""; + for (int i = 0; i < managerList.size(); i++) { + if (i > 0) { + trusted += ", "; + } + final UUID uuid = managerList.get(i); + final String userName = PlayerUtil.getInstance().getUserName(uuid); + if (userName.equalsIgnoreCase("unknown")) { + trusted += uuid.toString(); + } else { + trusted += userName; + } + } + info = info.replace("%managers%", trusted); + + return info; + } + + private boolean isVisible(String owner, String worldname) { + if (!this.cfg.visibleRegions.isEmpty()) { + if (!this.cfg.visibleRegions.contains(owner) && !this.cfg.visibleRegions.contains("world:" + worldname) + && !this.cfg.visibleRegions.contains(worldname + "/" + owner)) { + return false; + } + } + if (!this.cfg.hiddenRegions.isEmpty()) { + if (this.cfg.hiddenRegions.contains(owner) || this.cfg.hiddenRegions.contains("world:" + worldname) + || this.cfg.hiddenRegions.contains(worldname + "/" + owner)) + return false; + } + return true; + } + + private void addOwnerStyle(String owner, String worldid, AreaMarker marker, Claim claim) { + DynmapOwnerStyleCategory ownerStyle = null; + + if (!this.cfg.ownerStyles.isEmpty()) { + ownerStyle = this.cfg.ownerStyles.get(owner.toLowerCase()); + } + + if (ownerStyle == null) { + ownerStyle = this.defaultStyle; + } + + int sc = 0xFF0000; + int fc = 0xFF0000; + + if (claim.getType().equals(ClaimTypes.ADMIN)) { + sc = 0xFF0000; + fc = 0xFF0000; + } else if (claim.getType().equals(ClaimTypes.BASIC)) { + sc = 0xFFFF00; + fc = 0xFFFF00; + } else if (claim.getType().equals(ClaimTypes.TOWN)) { + sc = 0x00FF00; + fc = 0x00FF00; + } else if (claim.getType().equals(ClaimTypes.SUBDIVISION)) { + sc = 0xFF9C00; + fc = 0xFF9C00; + } + + marker.setLineStyle(ownerStyle.strokeWeight, ownerStyle.strokeOpacity, sc); + marker.setFillStyle(ownerStyle.fillOpacity, fc); + if (ownerStyle.label != null) { + marker.setLabel(ownerStyle.label); + } + } + + private void updateClaimMarker(Claim claim, Map markerMap) { + final World world = Bukkit.getWorld(claim.getWorldUniqueId()); + if (world == null) { + return; + } + final String worldName = world.getName(); + final String owner = ((GDClaim) claim).getOwnerFriendlyName(); + if (isVisible(owner, worldName)) { + final Vector3i lesserPos = claim.getLesserBoundaryCorner(); + final Vector3i greaterPos = claim.getGreaterBoundaryCorner(); + final double[] x = new double[4]; + final double[] z = new double[4]; + x[0] = lesserPos.getX(); + z[0] = lesserPos.getZ(); + x[1] = lesserPos.getX(); + z[1] = greaterPos.getZ() + 1.0; + x[2] = greaterPos.getX() + 1.0; + z[2] = greaterPos.getZ() + 1.0; + x[3] = greaterPos.getX() + 1.0; + z[3] = lesserPos.getZ(); + final UUID id = claim.getUniqueId(); + final String markerid = "GD_" + id; + AreaMarker marker = this.areaMarkers.remove(markerid); + if (marker == null) { + marker = this.set.createAreaMarker(markerid, owner, false, worldName, x, z, false); + if (marker == null) { + return; + } + } else { + marker.setCornerLocations(x, z); + marker.setLabel(owner); + } + if (this.cfg.use3dRegions) { + marker.setRangeY(greaterPos.getY() + 1.0, lesserPos.getY()); + } + + addOwnerStyle(owner, worldName, marker, claim); + String desc = getWindowInfo(claim, marker); + marker.setDescription(desc); + markerMap.put(markerid, marker); + } + } + + private void updateClaims() { + Map newmap = new HashMap(); + Bukkit.getServer().getWorlds().stream().map(w -> GriefDefender.getCore().getClaimManager(w.getUID())) + .map(ClaimManager::getWorldClaims).forEach(claims -> { + claims.forEach(claim -> updateClaimMarker(claim, newmap)); + }); + + for (AreaMarker oldm : this.areaMarkers.values()) { + oldm.deleteMarker(); + } + + this.areaMarkers = newmap; + } + + private void activate() { + this.markerapi = this.dynmap.getMarkerAPI(); + if (this.markerapi == null) { + return; + } + if (this.reload) { + GriefDefenderPlugin.getInstance().loadConfig(); + if (this.set != null) { + this.set.deleteMarkerSet(); + this.set = null; + } + this.areaMarkers.clear(); + } else { + this.reload = true; + } + + this.set = this.markerapi.getMarkerSet("griefdefender.markerset"); + if (this.set == null) { + this.set = this.markerapi.createMarkerSet("griefdefender.markerset", GriefDefenderPlugin.MOD_ID, null, false); + } else { + this.set.setMarkerSetLabel(GriefDefenderPlugin.MOD_ID); + } + if (this.set == null) { + this.logger.severe("Error creating marker set"); + return; + } + + int minzoom = this.cfg.minzoom; + if (minzoom > 0) { + this.set.setMinZoom(minzoom); + } + + this.set.setLayerPriority(this.cfg.layerPriority); + this.set.setHideByDefault(this.cfg.layerHideByDefault); + + new GriefDefenderUpdate(40L); + this.logger.info("Dynmap provider is activated"); + } + + public void onDisable() { + if (this.set != null) { + this.set.deleteMarkerSet(); + this.set = null; + } + this.areaMarkers.clear(); + this.disabled = true; + } + + private class GriefDefenderUpdate extends BukkitRunnable { + + public GriefDefenderUpdate(long delay) { + this.runTaskLater(GDBootstrap.getInstance(), delay); + } + + @Override + public void run() { + if (!disabled) { + updateClaims(); + } else { + this.cancel(); + } + } + } + + @Subscribe + public void onClaimCreate(CreateClaimEvent event) { + new GriefDefenderUpdate(20L); + } + + @Subscribe + public void onClaimDelete(RemoveClaimEvent event) { + new GriefDefenderUpdate(20L); + } + + @Subscribe + public void onClaimChange(ChangeClaimEvent event) { + new GriefDefenderUpdate(20L); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/griefdefender/provider/PlaceholderProvider.java b/bukkit/src/main/java/com/griefdefender/provider/PlaceholderProvider.java new file mode 100644 index 0000000..55d3a48 --- /dev/null +++ b/bukkit/src/main/java/com/griefdefender/provider/PlaceholderProvider.java @@ -0,0 +1,260 @@ +/* + * This file is part of GriefDefender, licensed under the MIT License (MIT). + * + * Copyright (c) bloodmc + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.griefdefender.provider; + +import java.util.List; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import com.griefdefender.GDBootstrap; +import com.griefdefender.GDPlayerData; +import com.griefdefender.GriefDefenderPlugin; +import com.griefdefender.api.GriefDefender; +import com.griefdefender.api.Subject; +import com.griefdefender.api.claim.Claim; +import com.griefdefender.api.claim.ClaimType; +import com.griefdefender.api.claim.ClaimTypes; +import com.griefdefender.api.claim.TrustTypes; +import com.griefdefender.claim.GDClaim; +import com.griefdefender.internal.util.VecHelper; +import com.griefdefender.permission.GDPermissionUser; +import com.griefdefender.util.PlayerUtil; + +import me.clip.placeholderapi.expansion.PlaceholderExpansion; + +public class PlaceholderProvider { + + public PlaceholderProvider() { + if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null){ + new GDPlaceholderExpansion().register(); + } + } + + private class GDPlaceholderExpansion extends PlaceholderExpansion { + + public GDPlaceholderExpansion() { + + } + + @Override + public String onPlaceholderRequest(Player player, String identifier){ + return onRequest(player, identifier); + } + + @Override + public String onRequest(OfflinePlayer user, String identifier) { + final Player player = user instanceof Player ? (Player) user : null; + final Subject subject = GriefDefender.getCore().getSubject(user.getUniqueId().toString()); + GDPlayerData playerData = null; + Claim claim = null; + if (player != null) { + final World world = player.getWorld(); + claim = GriefDefender.getCore().getClaimManager(world.getUID()).getClaimAt(VecHelper.toVector3i(player.getLocation())); + playerData = (GDPlayerData) GriefDefender.getCore().getPlayerData(world.getUID(), player.getUniqueId()).get(); + } else { + playerData = (GDPlayerData) GriefDefender.getCore().getPlayerData(Bukkit.getWorlds().get(0).getUID(), user.getUniqueId()).get(); + } + switch (identifier) { + case "claim_admin" : + return this.getAdminClaimsInside(player, claim); + case "claim_basic" : + return this.getPlayerClaimsInside(player, claim, ClaimTypes.BASIC); + case "claim_subdivision" : + return this.getPlayerClaimsInside(player, claim, ClaimTypes.SUBDIVISION); + case "claim_town" : + return this.getPlayerClaimsInside(player, claim, ClaimTypes.TOWN); + case "claims_admin" : + return this.getAllAdminClaims(player); + case "claims_basic" : + return this.getAllPlayerClaims(playerData, ClaimTypes.BASIC); + case "claims_subdivision" : + return this.getAllPlayerClaims(playerData, ClaimTypes.SUBDIVISION); + case "claims_town" : + return this.getAllPlayerClaims(playerData, ClaimTypes.TOWN); + case "claims_town_basic" : + return this.getAllTownChildrenClaims(playerData, ClaimTypes.BASIC); + case "claims_town_subdivision" : + return this.getAllTownChildrenClaims(playerData, ClaimTypes.SUBDIVISION); + case "claim_for_sale" : + if (claim == null) { + return "false"; + } + return String.valueOf(claim.getEconomyData().isForSale()); + case "claim_name" : + if (claim == null) { + return "none"; + } + return ((GDClaim) claim).getFriendlyName(); + case "claim_owner" : + if (claim == null) { + return "none"; + } + if (claim.isWilderness()) { + return "wilderness"; + } + return ((GDClaim) claim).getOwnerFriendlyName(); + case "claim_trust" : + if (claim == null) { + return "[unknown]"; + } + return String.valueOf(claim.isUserTrusted(player.getUniqueId(), TrustTypes.ACCESSOR)); + case "claim_type" : + if (claim == null) { + return "none"; + } + return claim.getType().getName(); + case "pvp" : + if (claim == null) { + return "[unknown]"; + } + return String.valueOf(PlayerUtil.getInstance().canPlayerPvP((GDClaim) claim, ((GDPermissionUser) subject))); + case "blocks_total" : + final int initial = playerData.getInitialClaimBlocks(); + final int accrued = playerData.getAccruedClaimBlocks(); + final int bonus = playerData.getBonusClaimBlocks(); + return String.valueOf(initial + accrued + bonus); + case "blocks_left" : + return String.valueOf(playerData.getRemainingClaimBlocks()); + case "blocks_accrued_rate" : + return String.valueOf(playerData.getBlocksAccruedPerHour()); + case "blocks_accrued_max" : + return String.valueOf(playerData.getMaxAccruedClaimBlocks()); + default : + return null; + } + } + + @Override + public boolean canRegister(){ + return true; + } + + @Override + public String getIdentifier() { + return GriefDefenderPlugin.MOD_ID.toLowerCase(); + } + + @Override + public String getVersion() { + return "0.1"; + } + + @Override + public String getAuthor(){ + return GDBootstrap.getInstance().getDescription().getAuthors().toString(); + } + + /** + * Because this is an internal class, + * you must override this method to let PlaceholderAPI know to not unregister your expansion class when + * PlaceholderAPI is reloaded + * + * @return true to persist through reloads + */ + @Override + public boolean persist(){ + return true; + } + + private String getAdminClaimsInside(Player player, Claim currentClaim) { + if (player == null) { + return "0"; + } + int count = 0; + if (currentClaim.isWilderness()) { + return this.getAllAdminClaims(player); + } + for (Claim claim : currentClaim.getChildren(true)) { + if (claim.isAdminClaim()) { + count++; + } + } + return String.valueOf(count); + } + + private String getAllAdminClaims(Player player) { + if (player == null) { + return "0"; + } + final World world = player == null ? Bukkit.getWorlds().get(0) : player.getWorld(); + int count = 0; + final Set claimList = GriefDefender.getCore().getClaimManager(world.getUID()).getWorldClaims(); + for (Claim claim : claimList) { + if (claim.isAdminClaim()) { + count++; + } + } + return String.valueOf(count); + } + + private String getPlayerClaimsInside(Player player, Claim currentClaim, ClaimType type) { + if (player == null || currentClaim == null) { + return "0"; + } + int count = 0; + if (currentClaim.isWilderness()) { + return String.valueOf(GriefDefender.getCore().getAllPlayerClaims(player.getUniqueId()).size()); + } + for (Claim claim : currentClaim.getChildren(true)) { + if (claim.getType() == type) { + count++; + } + } + return String.valueOf(count); + } + + private String getAllPlayerClaims(GDPlayerData playerData, ClaimType type) { + if (playerData == null) { + return "0"; + } + int count = 0; + final List claimList = GriefDefender.getCore().getAllPlayerClaims(playerData.playerID); + for (Claim claim : claimList) { + if (claim.getType() == type) { + count++; + } + } + return String.valueOf(count); + } + + private String getAllTownChildrenClaims(GDPlayerData playerData, ClaimType subType) { + if (playerData == null) { + return "0"; + } + int count = 0; + final List claimList = GriefDefender.getCore().getAllPlayerClaims(playerData.playerID); + for (Claim claim : claimList) { + if (!claim.isTown() && claim.isInTown() && claim.getType() == subType) { + count++; + } + } + return String.valueOf(count); + } + } +} diff --git a/bukkit/src/main/java/com/griefdefender/util/PlayerUtil.java b/bukkit/src/main/java/com/griefdefender/util/PlayerUtil.java index 2ddc67d..0fa86ff 100644 --- a/bukkit/src/main/java/com/griefdefender/util/PlayerUtil.java +++ b/bukkit/src/main/java/com/griefdefender/util/PlayerUtil.java @@ -25,12 +25,16 @@ package com.griefdefender.util; import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; import com.griefdefender.GDPlayerData; import com.griefdefender.GriefDefenderPlugin; +import com.griefdefender.api.Tristate; import com.griefdefender.api.claim.ClaimType; import com.griefdefender.api.claim.ClaimTypes; import com.griefdefender.api.claim.ShovelType; import com.griefdefender.api.claim.ShovelTypes; +import com.griefdefender.api.permission.flag.Flags; +import com.griefdefender.api.permission.option.Options; import com.griefdefender.api.permission.option.type.CreateModeTypes; import com.griefdefender.cache.PermissionHolderCache; import com.griefdefender.claim.GDClaim; @@ -38,6 +42,7 @@ import com.griefdefender.internal.util.NMSUtil; import com.griefdefender.internal.visual.ClaimVisual; import com.griefdefender.internal.visual.GDClaimVisualType; +import com.griefdefender.permission.GDPermissionManager; import com.griefdefender.permission.GDPermissionUser; import net.kyori.text.Component; @@ -54,6 +59,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.HashSet; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; @@ -217,4 +223,28 @@ public boolean isSafeLocation(Location location) { } return true; } + + public boolean canPlayerPvP(GDClaim claim, GDPermissionUser source) { + final Player sourcePlayer = source.getOnlinePlayer(); + + Tristate sourceResult = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Tristate.class), source, Options.PVP, claim); + if (sourceResult == Tristate.UNDEFINED) { + sourceResult = Tristate.fromBoolean(claim.getWorld().getPVP()); + } + + if (sourceResult == Tristate.FALSE) { + return false; + } + + final GDClaim sourceClaim = GriefDefenderPlugin.getInstance().dataStore.getClaimAtPlayer(source.getInternalPlayerData(), sourcePlayer.getLocation()); + if (!sourceClaim.isPvpEnabled()) { + return false; + } + if (!claim.isPvpEnabled()) { + return false; + } + + final Tristate flagResult = GDPermissionManager.getInstance().getActiveFlagPermissionValue(claim, source, Flags.ENTITY_DAMAGE, source, "minecraft:player", new HashSet<>()); + return flagResult.asBoolean(); + } }