Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Region priority #8

Merged
merged 8 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading