Skip to content

Commit

Permalink
Region priority (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
T14D3 authored Jan 19, 2025
2 parents cced0ee + 7b16b5a commit 13b7d7a
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 81 deletions.
50 changes: 33 additions & 17 deletions src/main/java/de/t14d3/zones/PermissionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.util.BoundingBox;

import java.util.Map;
import java.util.UUID;
Expand Down Expand Up @@ -34,6 +33,12 @@ public void setRegionManager(RegionManager regionManager) {
* @return True if the player can interact with the region, false otherwise.
*/
public boolean canInteract(Location location, UUID playerUUID, Actions action, String type) {

// Skip checking if player has global bypass permission
Player player = Bukkit.getPlayer(playerUUID);
if (player != null && player.hasPermission("zones.bypass.claimed")) {
return true;
}
if (interactionCache.containsKey(playerUUID)) {
ConcurrentLinkedQueue<CacheEntry> entries = interactionCache.get(playerUUID);
for (CacheEntry entry : entries) {
Expand All @@ -42,19 +47,35 @@ public boolean canInteract(Location location, UUID playerUUID, Actions action, S
}
}
}
for (Map.Entry<String, Region> entry : regionManager.regions().entrySet()) {
Region region = entry.getValue();
BoundingBox box = BoundingBox.of(region.getMin(), region.getMax());

if (box.contains(location.toVector())) {
Result hasPermission = hasPermission(playerUUID.toString(), action.name(), type, region);
interactionCache.computeIfAbsent(playerUUID, k -> new ConcurrentLinkedQueue<>()).add(new CacheEntry(location, action.name(), type, hasPermission));

return hasPermission.equals(Result.TRUE);
if (!regionManager.getRegionsAt(location).isEmpty()) {
Result result = Result.UNDEFINED;
int priority = Integer.MIN_VALUE;

for (Region region : regionManager.getRegionsAt(location)) {

// Only check regions with a higher priority than the current value
if (region.getPriority() > priority) {
Result hasPermission = hasPermission(playerUUID.toString(), action.name(), type, region);
if (!hasPermission.equals(Result.UNDEFINED)) {
result = hasPermission;
priority = region.getPriority();
continue;
}
}
// If same priority, both have to be true, otherwise will assume false
else if (region.getPriority() == priority) {
Result hasPermission = hasPermission(playerUUID.toString(), action.name(), type, region);
if (hasPermission.equals(Result.FALSE) || result.equals(Result.FALSE)) {
result = hasPermission;
priority = region.getPriority();
continue;
}
}
}
}

Player player = Bukkit.getPlayer(playerUUID);
return result.equals(Result.TRUE);
}
// If no region found, check for unclaimed bypass perm and return false if not found
return player != null && player.hasPermission("zones.bypass.unclaimed");
}

Expand Down Expand Up @@ -164,11 +185,6 @@ private Result calculatePermission(String who, String permission, String type, R
} catch (IllegalArgumentException ignored) {
}

// Check if player has a global bypass permission
if (player != null && player.hasPermission("zones.bypass.claimed")) {
return Result.TRUE;
}

Result result = Result.UNDEFINED; // Initialize result as null

// Check if player is an admin, but only if not checking
Expand Down
45 changes: 29 additions & 16 deletions src/main/java/de/t14d3/zones/Region.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,46 @@ public class Region {
private Map<String, Map<String, String>> members;
private String key;
private String parent;
private int priority;

// Constructor
/**
* Constructs a new region with the given name, minimum and maximum locations, members and parent.
* @param name The name of the region (not unique).
* @param min The minimum location of the region.
* @param max The maximum location of the region.
* @param members The members of the region.
* @param key The key of the region.
* @param parent The parent (if any) of the region.
*
* @see #Region(String, Location, Location, Map, String)
* @param name The name of the region (not unique).
* @param min The minimum location of the region.
* @param max The maximum location of the region.
* @param members The members of the region.
* @param key The key of the region.
* @param parent The parent (if any) of the region.
* @param priority The priority of the region.
* @see #Region(String, Location, Location, Map, String, int)
*/
Region(@NotNull String name, @NotNull Location min, @NotNull Location max, Map<String, Map<String, String>> members, @NotNull String key, @Nullable String parent) {
Region(@NotNull String name, @NotNull Location min, @NotNull Location max, Map<String, Map<String, String>> members, @NotNull String key, @Nullable String parent, int priority) {
this.name = name;
this.min = min;
this.max = max;
this.members = (members != null) ? members : new HashMap<>();
this.key = key;
this.parent = parent;
this.priority = priority;
}

// Constructor overload for regions without parent
/**
* Constructs a new region with the given name, minimum and maximum locations, and members.
* @param name The name of the region (not unique).
* @param min The minimum location of the region.
* @param max The maximum location of the region.
* @param members The members of the region.
* @param key The key of the region.
*
* @see #Region(String, Location, Location, Map, String)
* @param name The name of the region (not unique).
* @param min The minimum location of the region.
* @param max The maximum location of the region.
* @param members The members of the region.
* @param key The key of the region.
* @param priority The priority of the region.
*
* @see #Region(String, Location, Location, Map, String, int)
*/
Region(String name, Location min, Location max, Map<String, Map<String, String>> members, String key) {
this(name, min, max, members, key, null);
Region(String name, Location min, Location max, Map<String, Map<String, String>> members, String key, int priority) {
this(name, min, max, members, key, null, priority);
}

// Getters and Setters
Expand Down Expand Up @@ -240,6 +245,14 @@ void addMemberPermission(UUID uuid, String permission, String value, RegionManag
return null;
}

public int getPriority() {
return priority;
}

public void setPriority(int priority) {
this.priority = priority;
}


JsonObject getAsJson() {
JsonObject json = new JsonObject();
Expand Down
40 changes: 31 additions & 9 deletions src/main/java/de/t14d3/zones/RegionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.util.BoundingBox;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -80,12 +81,13 @@ public Future<Void> loadRegions() {
loadedRegions.clear();
for (String key : Objects.requireNonNull(regionsConfig.getConfigurationSection("regions")).getKeys(false)) {
String name = regionsConfig.getString("regions." + key + ".name");
int priority = regionsConfig.getInt("regions." + key + ".priority");
Location min = loadLocation("regions." + key + ".min");
Location max = loadLocation("regions." + key + ".max");
String parent = regionsConfig.getString("regions." + key + ".parent");

Map<String, Map<String, String>> members = loadMembers(key);
Region region = new Region(name != null ? name : "Invalid Name", min, max, members, key, parent);
Region region = new Region(name != null ? name : "Invalid Name", min, max, members, key, parent, 0);
loadedRegions.put(key, region);
}
regionCache.clear();
Expand Down Expand Up @@ -120,6 +122,7 @@ private Map<String, Map<String, String>> loadMembers(String key) {
// Save a region to the YAML file
public void saveRegion(String key, Region region) {
regionsConfig.set("regions." + key + ".name", region.getName());
regionsConfig.set("regions." + key + ".priority", region.getPriority());
saveLocation("regions." + key + ".min", region.getMin());
saveLocation("regions." + key + ".max", region.getMax());
if (region.getParent() != null) {
Expand Down Expand Up @@ -186,7 +189,7 @@ public String createNewRegion(String name, Location min, Location max, UUID play
} while (regions().containsKey(regionKey));

Map<String, Map<String, String>> members = new HashMap<>();
Region newRegion = new Region(name, min, max, members, regionKey);
Region newRegion = new Region(name, min, max, members, regionKey, 0);

ownerPermissions.forEach((permission, value) -> {
newRegion.addMemberPermission(playerUUID, permission, value, this);
Expand Down Expand Up @@ -223,8 +226,8 @@ public void createNewRegion(String name, Location min, Location max, UUID player
* @param members The members of the new region.
* @return The newly created region.
*/
public Region createNewRegion(String key, String name, Location min, Location max, Map<String, Map<String, String>> members) {
Region region = new Region(name, min, max, members, key);
public Region createNewRegion(String key, String name, Location min, Location max, Map<String, Map<String, String>> members, int priority) {
Region region = new Region(name, min, max, members, key, priority);
saveRegion(key, region);
return region;
}
Expand Down Expand Up @@ -261,7 +264,7 @@ public void createSubRegion(String name, Location min, Location max, UUID player
} while (regions().containsKey(regionKey));

Map<String, Map<String, String>> members = new HashMap<>();
Region newRegion = new Region(name, min, max, members, regionKey, parentRegion.getKey());
Region newRegion = new Region(name, min, max, members, regionKey, parentRegion.getKey(), 0);

ownerPermissions.forEach((permission, value) -> {
newRegion.addMemberPermission(playerUUID, permission, value, this);
Expand Down Expand Up @@ -386,16 +389,35 @@ public List<Region> getRegionsAt(Location location) {
return foundRegions;
}
for (Region region : regions().values()) {
BoundingBox regionBox = BoundingBox.of(region.getMin(), region.getMax());
// Check if the location's bounding box overlaps with the region's bounding box
if (regionBox.contains(location.toVector())) {
if (region.contains(location)) {
foundRegions.add(region);
regionCache.computeIfAbsent(location, k -> new ArrayList<>()).add(region.getKey());
}
}


return foundRegions;
}

/**
* Gets the region with the highest priority at the given location
*
* @param location Location to check
* @return Region at location, or null if no region found
*/
public @Nullable Region getEffectiveRegionAt(Location location) {
List<Region> regions = getRegionsAt(location);
int priority = Integer.MIN_VALUE;
Region effectiveRegion = null;
for (Region region : regions) {
if (region.getPriority() > priority) {
effectiveRegion = region;
priority = region.getPriority();
}
}
return effectiveRegion;
}

/**
* Gets Regions at location async
*
Expand Down Expand Up @@ -473,7 +495,7 @@ public Map<String, String> getMemberPermissions(UUID uuid, Region region) {

/**
* Adds a region to the loaded regions map.
* Requires an existing region object, to create a new region use {@link #createNewRegion(String, String, Location, Location, Map)}.
* Requires an existing region object, to create a new region use {@link #createNewRegion(String, String, Location, Location, Map, int)}.
*
* @param region The region to add.
*
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/de/t14d3/zones/Zones.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public final class Zones extends JavaPlugin {

Expand All @@ -31,7 +32,7 @@ public final class Zones extends JavaPlugin {
private BeaconUtils beaconUtils;
private ParticleHandler particleHandler;
public Map<UUID, Pair<Location, Location>> selection = new HashMap<>();
public Map<UUID, BoundingBox> particles = new HashMap<>();
public ConcurrentHashMap<UUID, BoundingBox> particles = new ConcurrentHashMap<>();
private Types types;
private Messages messages;
private static Zones instance;
Expand Down
36 changes: 18 additions & 18 deletions src/main/java/de/t14d3/zones/commands/CommandExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -300,21 +300,21 @@ public void handleListCommand(CommandSender sender) {
player = (Player) sender;
}
boolean perm = sender.hasPermission("zones.info.other");
for (Map.Entry<String, Region> entry : regions.entrySet()) {
if (!perm && (player != null && !entry.getValue().isMember(player.getUniqueId()))) {
for (Region region : regions.values()) {
if (!perm && (player != null && !region.isMember(player.getUniqueId()))) {
continue;
}

Component hoverText = regionInfo(
entry,
region,
(perm ||
(player != null && this.plugin.getPermissionManager().isAdmin(player.getUniqueId().toString(), regions.get(entry.getKey())))))
(player != null && this.plugin.getPermissionManager().isAdmin(player.getUniqueId().toString(), region))))
.join();
var mm = MiniMessage.miniMessage();

Component comp = mm.deserialize(messages.get("region.info.name"), parsed("name", entry.getValue().getName()), parsed("key", entry.getKey()));
Component comp = mm.deserialize(messages.get("region.info.name"), parsed("name", region.getName()), parsed("key", region.getKey()));
HoverEvent<Component> hover = hoverText.asHoverEvent();
ClickEvent click = ClickEvent.runCommand("/zone info " + entry.getKey());
ClickEvent click = ClickEvent.runCommand("/zone info " + region.getKey());
comp = comp.hoverEvent(hover);
comp = comp.clickEvent(click);
sender.sendMessage(comp);
Expand Down Expand Up @@ -347,7 +347,8 @@ public void handleInfoCommand(CommandSender sender, String[] args) {
sender.sendMessage(miniMessage.deserialize(messages.get("commands.no-permission")));
return;
}
regionInfo(regions.entrySet().stream().filter(entry -> entry.getKey().equals(regionKey)).findFirst().get(), regions.get(regionKey).isAdmin(player.getUniqueId()))
Region region = regions.get(regionKey);
regionInfo(region, region.isAdmin(player.getUniqueId()))
.thenAccept(sender::sendMessage);

}
Expand Down Expand Up @@ -460,9 +461,8 @@ public void handleSelectCommand(CommandSender sender, String[] args) {
if (sender instanceof Player player) {
Region region;
if (args.length == 1) {
try {
region = regionManager.getRegionsAt(player.getLocation()).get(0);
} catch (IndexOutOfBoundsException e) {
region = regionManager.getEffectiveRegionAt(player.getLocation());
if (region == null) {
plugin.particles.remove(player.getUniqueId());
player.sendMessage(miniMessage.deserialize(messages.get("commands.select.deselected")));
return;
Expand Down Expand Up @@ -515,21 +515,21 @@ private void handleModeCommand(CommandSender sender, String[] args) {
}
}

private CompletableFuture<Component> regionInfo(Map.Entry<String, Region> entry, boolean showMembers) {
private CompletableFuture<Component> regionInfo(Region region, boolean showMembers) {
var mm = MiniMessage.miniMessage();
Component comp = Component.text("");
comp = comp.append(mm.deserialize(messages.get("region.info.name"), parsed("name", entry.getValue().getName())));
comp = comp.append(mm.deserialize(messages.get("region.info.name"), parsed("name", region.getName())));
comp = comp.appendNewline();
if (entry.getValue().getParent() != null) {
comp = comp.append(mm.deserialize(messages.get("region.info.parent"), parsed("parent", entry.getValue().getParent())));
if (region.getParent() != null) {
comp = comp.append(mm.deserialize(messages.get("region.info.parent"), parsed("parent", region.getParent())));
}
comp = comp.append(mm.deserialize(messages.get("region.info.min"), parsed("min", entry.getValue().getMinString())));
comp = comp.append(mm.deserialize(messages.get("region.info.min"), parsed("min", region.getMinString())));
comp = comp.appendNewline();
comp = comp.append(mm.deserialize(messages.get("region.info.max"), parsed("max", entry.getValue().getMaxString())));
comp = comp.append(mm.deserialize(messages.get("region.info.max"), parsed("max", region.getMaxString())));

if (showMembers) {
// Iterate over members to format permissions
for (Map.Entry<String, Map<String, String>> member : entry.getValue().getMembers().entrySet()) {
for (Map.Entry<String, Map<String, String>> member : region.getMembers().entrySet()) {
String playerName = null;
try {
playerName = Bukkit.getOfflinePlayer(UUID.fromString(member.getKey())).getName();
Expand Down Expand Up @@ -583,7 +583,7 @@ private CompletableFuture<Component> regionInfo(Map.Entry<String, Region> entry,
.append(permissionsComponent);
}
}
comp = comp.append(mm.deserialize(messages.get("region.info.key"), parsed("key", entry.getKey())));
comp = comp.append(mm.deserialize(messages.get("region.info.key"), parsed("key", region.getKey())));

return CompletableFuture.completedFuture(comp);
}
Expand Down
Loading

0 comments on commit 13b7d7a

Please sign in to comment.