package io.github.flemmli97.flan.claim; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import io.github.flemmli97.flan.Flan; import io.github.flemmli97.flan.api.data.IPermissionContainer; import io.github.flemmli97.flan.api.permission.ClaimPermission; import io.github.flemmli97.flan.api.permission.PermissionRegistry; import io.github.flemmli97.flan.config.Config; import io.github.flemmli97.flan.config.ConfigHandler; import io.github.flemmli97.flan.platform.ClaimPermissionCheck; import io.github.flemmli97.flan.platform.CrossPlatformStuff; import io.github.flemmli97.flan.platform.integration.webmap.WebmapCalls; import io.github.flemmli97.flan.player.LogoutTracker; import io.github.flemmli97.flan.player.PlayerClaimData; import io.github.flemmli97.flan.player.display.ClaimDisplayBox; import io.github.flemmli97.flan.player.display.DisplayBox; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionResult; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.phys.AABB; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; public class Claim implements IPermissionContainer { private boolean dirty; private int minX, minZ, maxX, maxZ, minY; private UUID owner; private UUID claimID; private String claimName = ""; private BlockPos homePos; private final Map globalPerm = new HashMap<>(); private final Map> permissions = new HashMap<>(); private final Map playersGroups = new HashMap<>(); private final Set fakePlayers = new HashSet<>(); private final List subClaims = new ArrayList<>(); private UUID parent; private Claim parentClaim; /** * Flag for players tracking this claim */ private boolean removed; private final ServerLevel world; private final Map potions = new HashMap<>(); public Component enterTitle, enterSubtitle, leaveTitle, leaveSubtitle; private Claim(ServerLevel world) { this.world = world; } //New claim public Claim(BlockPos pos1, BlockPos pos2, ServerPlayer creator) { this(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ(), Math.min(pos1.getY(), pos2.getY()), creator.getUUID(), creator.serverLevel(), PlayerClaimData.get(creator).playerDefaultGroups().isEmpty()); PlayerClaimData.get(creator).playerDefaultGroups().forEach((s, m) -> m.forEach((perm, bool) -> this.editPerms(null, s, perm, bool ? 1 : 0, true))); Collection all = ClaimStorage.get(creator.serverLevel()).allClaimsFromPlayer(creator.getUUID()); String name = String.format(ConfigHandler.config.defaultClaimName, creator.getName(), all.size()); if (!name.isEmpty()) { for (Claim claim : all) { if (claim.claimName.equals(name)) { name = name + " #" + all.size(); break; } } } this.claimName = name; if (!ConfigHandler.config.defaultEnterMessage.isEmpty()) this.enterTitle = Component.literal(String.format(ConfigHandler.config.defaultEnterMessage, this.claimName)); if (!ConfigHandler.config.defaultLeaveMessage.isEmpty()) this.leaveTitle = Component.literal(String.format(ConfigHandler.config.defaultLeaveMessage, this.claimName)); } public Claim(BlockPos pos1, BlockPos pos2, UUID creator, ServerLevel world) { this(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ(), Math.min(pos1.getY(), pos2.getY()), creator, world); } //Griefprevention parsing public Claim(int x1, int x2, int z1, int z2, int minY, UUID creator, ServerLevel world) { this(x1, x2, z1, z2, minY, creator, world, true); } public Claim(int x1, int x2, int z1, int z2, int minY, UUID creator, ServerLevel world, boolean setDefaultGroups) { this.minX = Math.min(x1, x2); this.minZ = Math.min(z1, z2); this.maxX = Math.max(x1, x2); this.maxZ = Math.max(z1, z2); this.minY = Math.max(world.getMinBuildHeight(), minY); this.owner = creator; this.world = world; this.homePos = this.getInitCenterPos(); this.setDirty(true); PermissionRegistry.getPerms().stream().filter(perm -> perm.defaultVal).forEach(perm -> this.globalPerm.put(perm, true)); ConfigHandler.config.getGloballyDefinedVals(world).forEach(e -> this.globalPerm.put(e.getKey(), e.getValue().getValue())); if (setDefaultGroups) ConfigHandler.config.defaultGroups.forEach((s, m) -> m.forEach((perm, bool) -> this.editPerms(null, s, perm, bool ? 1 : 0, true))); } public static Claim fromJson(JsonObject obj, UUID owner, ServerLevel world) { Claim claim = new Claim(world); claim.readJson(obj, owner); ClaimUpdater.updateClaim(claim); return claim; } private BlockPos getInitCenterPos() { BlockPos center = BlockPos.containing(this.minX + (this.maxX - this.minX) * 0.5, 0, this.minZ + (this.maxZ - this.minZ) * 0.5); int y = this.world.getChunk(center.getX() >> 4, center.getZ() >> 4, ChunkStatus.FULL).getHeight(Heightmap.Types.MOTION_BLOCKING, center.getX() & 15, center.getZ() & 15); return new BlockPos(center.getX(), y + 1, center.getZ()); } private BlockPos getDefaultCenterPos() { BlockPos center = BlockPos.containing(this.minX + (this.maxX - this.minX) * 0.5, 0, this.minZ + (this.maxZ - this.minZ) * 0.5); return new BlockPos(center.getX(), 255, center.getZ()); } public void setClaimID(UUID uuid) { this.claimID = uuid; this.setDirty(true); } public void extendDownwards(BlockPos pos) { this.minY = pos.getY(); this.setDirty(true); } public UUID getClaimID() { return this.claimID; } public String getClaimName() { return this.claimName; } public void setClaimName(String name) { this.claimName = name; this.setDirty(true); WebmapCalls.changeClaimName(this); } public UUID getOwner() { return this.owner; } public Optional getOwnerPlayer() { if (this.getOwner() != null) return Optional.ofNullable(this.world.getServer().getPlayerList().getPlayer(this.getOwner())); return Optional.empty(); } public ServerLevel getWorld() { return this.world; } public Claim parentClaim() { if (this.parent == null) return null; if (this.parentClaim == null) { ClaimStorage storage = ClaimStorage.get(this.world); this.parentClaim = storage.getFromUUID(this.parent); } return this.parentClaim; } public void copySizes(Claim claim) { this.minX = claim.minX; this.maxX = claim.maxX; this.minZ = claim.minZ; this.maxZ = claim.maxZ; this.minY = claim.minY; this.removed = false; this.setDirty(true); } public void toggleAdminClaim(ServerPlayer player, boolean flag) { if (!flag) this.transferOwner(player.getUUID()); else { this.owner = null; this.subClaims.forEach(claim -> claim.owner = null); } this.setDirty(true); } public boolean isAdminClaim() { return this.owner == null; } public void transferOwner(UUID player) { this.owner = player; this.subClaims.forEach(claim -> claim.owner = player); this.setDirty(true); } public int getPlane() { return (this.maxX - this.minX + 1) * (this.maxZ - this.minZ + 1); } /** * @return The claims dimension in order: x, X, z, Z, y */ public int[] getDimensions() { return new int[]{this.minX, this.maxX, this.minZ, this.maxZ, this.minY}; } public boolean insideClaim(BlockPos pos) { return this.minX <= pos.getX() && this.maxX >= pos.getX() && this.minZ <= pos.getZ() && this.maxZ >= pos.getZ() && this.minY <= pos.getY(); } public boolean intersects(Claim other) { return this.minX <= other.maxX && this.maxX >= other.minX && this.minZ <= other.maxZ && this.maxZ >= other.minZ; } public boolean intersects(AABB box) { return this.minX < box.maxX && this.maxX + 1 > box.minX && this.minZ < box.maxZ && this.maxZ + 1 > box.minZ && box.maxY >= this.minY; } public boolean isCorner(BlockPos pos) { return (pos.getX() == this.minX && pos.getZ() == this.minZ) || (pos.getX() == this.minX && pos.getZ() == this.maxZ) || (pos.getX() == this.maxX && pos.getZ() == this.minZ) || (pos.getX() == this.maxX && pos.getZ() == this.maxZ); } public void remove() { this.removed = true; } public boolean isRemoved() { return this.removed; } @Override public boolean canInteract(ServerPlayer player, ClaimPermission perm, BlockPos pos, boolean message) { boolean realPlayer = player != null && player.getClass().equals(ServerPlayer.class); message = message && realPlayer; //dont send messages to fake players //Delegate interaction to FAKEPLAYER perm if a fake player if (player != null && !realPlayer) { //Some mods use the actual user/placer/owner whatever of the fakeplayer. E.g. ComputerCraft //For those mods we dont pass them as fake players if (this.fakePlayers.contains(player.getUUID())) return true; if (!player.getUUID().equals(this.owner) && !this.playersGroups.containsKey(player.getUUID())) { perm = PermissionRegistry.FAKEPLAYER; } } InteractionResult res = ClaimPermissionCheck.INSTANCE.check(player, perm, pos); if (res != InteractionResult.PASS) return res != InteractionResult.FAIL; if (perm != null) { ClaimPermission.PermissionFlag flag = perm.test.test(this, player, pos); if (flag != ClaimPermission.PermissionFlag.PASS) { if (flag == ClaimPermission.PermissionFlag.NO) { if (message) player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("noPermissionSimple"), ChatFormatting.DARK_RED), true); if (perm == PermissionRegistry.FAKEPLAYER) this.getOwnerPlayer().ifPresent(p -> PlayerClaimData.get(p).notifyFakePlayerInteraction(player, pos, this)); return false; } return true; } } if (!this.isAdminClaim()) { Config.GlobalType global = ConfigHandler.config.getGlobal(this.world, perm); if (!global.canModify()) { if (global.getValue() || (player != null && this.isAdminIgnore(player))) return true; if (message) player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("noPermissionSimple"), ChatFormatting.DARK_RED), true); if (perm == PermissionRegistry.FAKEPLAYER) this.getOwnerPlayer().ifPresent(p -> PlayerClaimData.get(p).notifyFakePlayerInteraction(player, pos, this)); return false; } if (ConfigHandler.config.offlineProtectActivation != -1 && (LogoutTracker.getInstance(this.world.getServer()).justLoggedOut(this.getOwner()) || this.getOwnerPlayer().isPresent())) { return global == Config.GlobalType.NONE || global.getValue(); } } if (PermissionRegistry.globalPerms().contains(perm)) { for (Claim claim : this.subClaims) { if (claim.insideClaim(pos)) { return claim.canInteract(player, perm, pos, message); } } if (this.hasPerm(perm)) return true; if (message) player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("noPermissionSimple"), ChatFormatting.DARK_RED), true); if (perm == PermissionRegistry.FAKEPLAYER) this.getOwnerPlayer().ifPresent(p -> PlayerClaimData.get(p).notifyFakePlayerInteraction(player, pos, this)); return false; } if (this.isAdminIgnore(player) || player.getUUID().equals(this.owner)) return true; if (perm != PermissionRegistry.EDITCLAIM && perm != PermissionRegistry.EDITPERMS) for (Claim claim : this.subClaims) { if (claim.insideClaim(pos)) { return claim.canInteract(player, perm, pos, message); } } if (this.playersGroups.containsKey(player.getUUID())) { Map map = this.permissions.get(this.playersGroups.get(player.getUUID())); if (map != null && map.containsKey(perm)) { if (map.get(perm)) return true; if (message) player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("noPermissionSimple"), ChatFormatting.DARK_RED), true); if (perm == PermissionRegistry.FAKEPLAYER) this.getOwnerPlayer().ifPresent(p -> PlayerClaimData.get(p).notifyFakePlayerInteraction(player, pos, this)); return false; } } if (this.hasPerm(perm)) return true; if (message) player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("noPermissionSimple"), ChatFormatting.DARK_RED), true); if (perm == PermissionRegistry.FAKEPLAYER) this.getOwnerPlayer().ifPresent(p -> PlayerClaimData.get(p).notifyFakePlayerInteraction(player, pos, this)); return false; } private boolean isAdminIgnore(ServerPlayer player) { return player == null || ((this.isAdminClaim() && player.hasPermissions(2)) || PlayerClaimData.get(player).isAdminIgnoreClaim()); } /** * @return -1 for default, 0 for false, 1 for true */ public int permEnabled(ClaimPermission perm) { return !this.globalPerm.containsKey(perm) ? -1 : this.globalPerm.get(perm) ? 1 : 0; } private boolean hasPerm(ClaimPermission perm) { if (this.parentClaim() == null) return this.permEnabled(perm) == 1; if (this.permEnabled(perm) == -1) return this.parentClaim().permEnabled(perm) == 1; return this.permEnabled(perm) == 1; } private UUID generateUUID() { UUID uuid = UUID.randomUUID(); for (Claim claim : this.subClaims) if (claim.claimID.equals(uuid)) { return this.generateUUID(); } return uuid; } public Set tryCreateSubClaim(BlockPos pos1, BlockPos pos2) { //No sub sub claims if (this.parentClaim() != null) return Set.of(this.parentClaim()); Claim sub = new Claim(pos1, new BlockPos(pos2.getX(), 0, pos2.getZ()), this.owner, this.world); sub.setClaimID(this.generateUUID()); Set conflicts = new HashSet<>(); for (Claim other : this.subClaims) if (sub.intersects(other)) { conflicts.add(other); } if (conflicts.isEmpty()) { sub.parent = this.claimID; sub.parentClaim = this; this.subClaims.add(sub); //Copy parent claims perms sub.permissions.clear(); sub.permissions.putAll(this.permissions); sub.playersGroups.clear(); sub.playersGroups.putAll(this.playersGroups); sub.potions.clear(); sub.potions.putAll(this.potions); this.setDirty(true); } return conflicts; } public void addSubClaimGriefprevention(Claim claim) { claim.setClaimID(this.generateUUID()); claim.parent = this.claimID; claim.parentClaim = this; this.subClaims.add(claim); this.setDirty(true); } public Claim getSubClaim(BlockPos pos) { for (Claim claim : this.subClaims) if (claim.insideClaim(pos)) return claim; return null; } public boolean deleteSubClaim(Claim claim) { claim.remove(); this.setDirty(true); return this.subClaims.remove(claim); } public List getAllSubclaims() { return ImmutableList.copyOf(this.subClaims); } public Set resizeSubclaim(Claim claim, BlockPos from, BlockPos to) { int[] dims = claim.getDimensions(); BlockPos opposite = new BlockPos(dims[0] == from.getX() ? dims[1] : dims[0], dims[4], dims[2] == from.getZ() ? dims[3] : dims[2]); Claim newClaim = new Claim(opposite, to, claim.claimID, this.world); Set conflicts = new HashSet<>(); for (Claim other : this.subClaims) if (!claim.equals(other) && newClaim.intersects(other)) conflicts.add(other); if (conflicts.isEmpty()) { claim.copySizes(newClaim); this.setDirty(true); } return conflicts; } public boolean setPlayerGroup(UUID player, String group, boolean force) { if (player.equals(this.owner)) return false; if (group == null) { this.playersGroups.remove(player); this.setDirty(true); return true; } if (!this.playersGroups.containsKey(player) || force) { this.playersGroups.put(player, group); this.setDirty(true); return true; } return false; } public boolean modifyFakePlayerUUID(UUID uuid, boolean remove) { if (remove) return this.fakePlayers.remove(uuid); return this.fakePlayers.add(uuid); } public List playersFromGroup(MinecraftServer server, String group) { List l = new ArrayList<>(); this.playersGroups.forEach((uuid, g) -> { if (g.equals(group)) l.add(uuid); }); List names = new ArrayList<>(); l.forEach(uuid -> server.getProfileCache().get(uuid).ifPresent(prof -> names.add(prof.getName()))); names.sort(null); return names; } public List getAllowedFakePlayerUUID() { return this.fakePlayers.stream().map(UUID::toString).toList(); } public boolean editGlobalPerms(ServerPlayer player, ClaimPermission toggle, int mode) { if ((player != null && !this.canInteract(player, PermissionRegistry.EDITPERMS, player.blockPosition())) || (!this.isAdminClaim() && ConfigHandler.config.globallyDefined(this.world, toggle))) return false; if (mode > 1) mode = -1; if (mode == -1) this.globalPerm.remove(toggle); else this.globalPerm.put(toggle, mode == 1); this.setDirty(true); return true; } public boolean editPerms(ServerPlayer player, String group, ClaimPermission perm, int mode) { return this.editPerms(player, group, perm, mode, false); } /** * Edit the permissions for a group. If not defined for the group creates a new default permission map for that group * * @param mode -1 = makes it resort to the global perm, 0 = deny perm, 1 = allow perm * @return If editing was successful or not */ public boolean editPerms(ServerPlayer player, String group, ClaimPermission perm, int mode, boolean alwaysCan) { if (PermissionRegistry.globalPerms().contains(perm) || (!this.isAdminClaim() && ConfigHandler.config.globallyDefined(this.world, perm))) return false; if (alwaysCan || this.canInteract(player, PermissionRegistry.EDITPERMS, player.blockPosition())) { if (mode > 1) mode = -1; boolean has = this.permissions.containsKey(group); Map perms = has ? this.permissions.get(group) : new HashMap<>(); if (mode == -1) perms.remove(perm); else perms.put(perm, mode == 1); if (!has) this.permissions.put(group, perms); this.setDirty(true); return true; } return false; } public boolean removePermGroup(ServerPlayer player, String group) { if (this.canInteract(player, PermissionRegistry.EDITPERMS, player.blockPosition())) { this.permissions.remove(group); List toRemove = new ArrayList<>(); this.playersGroups.forEach((uuid, g) -> { if (g.equals(group)) toRemove.add(uuid); }); toRemove.forEach(this.playersGroups::remove); this.setDirty(true); return true; } return false; } public int groupHasPerm(String rank, ClaimPermission perm) { if (!this.permissions.containsKey(rank) || !this.permissions.get(rank).containsKey(perm)) return -1; return this.permissions.get(rank).get(perm) ? 1 : 0; } public List groups() { List l = new ArrayList<>(this.permissions.keySet()); l.sort(null); return l; } public boolean setHomePos(BlockPos homePos) { if (this.insideClaim(homePos)) { this.homePos = homePos; this.setDirty(true); return true; } return false; } public void addPotion(MobEffect effect, int amplifier) { this.potions.put(effect, amplifier); this.setDirty(true); } public void removePotion(MobEffect effect) { this.potions.remove(effect); this.setDirty(true); } public Map getPotions() { return this.potions; } public void applyEffects(ServerPlayer player) { if (player.level().getGameTime() % 80 == 0) this.potions.forEach((effect, amp) -> player.forceAddEffect(new MobEffectInstance(effect, effect == MobEffects.NIGHT_VISION ? 400 : 200, amp - 1, true, false), null)); } public BlockPos getHomePos() { return this.homePos; } public void setEnterTitle(Component title, Component sub) { if (title != null && title.getString().equals("$empty")) title = null; if (sub != null && sub.getString().equals("$empty")) sub = null; this.enterTitle = title; this.enterSubtitle = sub; this.setDirty(true); } public void setLeaveTitle(Component title, Component sub) { if (title != null && title.getString().equals("$empty")) title = null; if (sub != null && sub.getString().equals("$empty")) sub = null; this.leaveTitle = title; this.leaveSubtitle = sub; this.setDirty(true); } private void displayTitleMessage(ServerPlayer player, @Nullable Component title, @Nullable Component subtitle) { if (title == null) return; if (ConfigHandler.config.claimDisplayActionBar) { if (subtitle != null) { MutableComponent message = title.copy().append(Component.literal(" | ").setStyle(Style.EMPTY.withColor(ChatFormatting.WHITE))).append(subtitle); player.displayClientMessage(message, true); return; } player.displayClientMessage(title, true); return; } player.connection.send(new ClientboundSetTitleTextPacket(title)); if (subtitle != null) { player.connection.send(new ClientboundSetSubtitleTextPacket(subtitle)); } } public void displayEnterTitle(ServerPlayer player) { this.displayTitleMessage(player, this.enterTitle, this.enterSubtitle); } public void displayLeaveTitle(ServerPlayer player) { this.displayTitleMessage(player, this.leaveTitle, this.leaveSubtitle); } /** * Only marks non sub claims */ public void setDirty(boolean flag) { if (this.parentClaim() != null) this.parentClaim().setDirty(flag); else this.dirty = flag; } public boolean isDirty() { return this.dirty; } public void readJson(JsonObject obj, UUID uuid) { try { this.claimID = UUID.fromString(obj.get("ID").getAsString()); this.claimName = ConfigHandler.fromJson(obj, "Name", ""); JsonArray pos = obj.getAsJsonArray("PosxXzZY"); this.minX = pos.get(0).getAsInt(); this.maxX = pos.get(1).getAsInt(); this.minZ = pos.get(2).getAsInt(); this.maxZ = pos.get(3).getAsInt(); this.minY = pos.get(4).getAsInt(); JsonArray home = ConfigHandler.arryFromJson(obj, "Home"); if (home.size() != 3) this.homePos = this.getDefaultCenterPos(); else { this.homePos = new BlockPos(home.get(0).getAsInt(), home.get(1).getAsInt(), home.get(2).getAsInt()); } String message = ConfigHandler.fromJson(obj, "EnterTitle", ""); if (!message.isEmpty()) this.enterTitle = Component.Serializer.fromJson(message); else this.enterTitle = null; message = ConfigHandler.fromJson(obj, "EnterSubtitle", ""); if (!message.isEmpty()) this.enterSubtitle = Component.Serializer.fromJson(message); else this.enterSubtitle = null; message = ConfigHandler.fromJson(obj, "LeaveTitle", ""); if (!message.isEmpty()) this.leaveTitle = Component.Serializer.fromJson(message); else this.leaveTitle = null; message = ConfigHandler.fromJson(obj, "LeaveSubtitle", ""); if (!message.isEmpty()) this.leaveSubtitle = Component.Serializer.fromJson(message); else this.leaveSubtitle = null; JsonObject potion = ConfigHandler.fromJson(obj, "Potions"); potion.entrySet().forEach(e -> this.potions.put(CrossPlatformStuff.INSTANCE.registryStatusEffects().getFromId(new ResourceLocation(e.getKey())), e.getValue().getAsInt())); if (ConfigHandler.fromJson(obj, "AdminClaim", false)) this.owner = null; else this.owner = uuid; this.globalPerm.clear(); this.permissions.clear(); this.subClaims.clear(); if (obj.has("Parent")) this.parent = UUID.fromString(obj.get("Parent").getAsString()); if (obj.has("GlobalPerms")) { if (this.parent == null) { obj.getAsJsonArray("GlobalPerms").forEach(perm -> { try { this.globalPerm.put(PermissionRegistry.get(perm.getAsString()), true); } catch (NullPointerException e) { Flan.logger.error("Error reading permission {} from json for claim {} belonging to {}. No such permission exist", perm.getAsString(), this.claimID, this.owner); } }); } else { obj.getAsJsonObject("GlobalPerms").entrySet().forEach(entry -> { try { this.globalPerm.put(PermissionRegistry.get(entry.getKey()), entry.getValue().getAsBoolean()); } catch (NullPointerException e) { Flan.logger.error("Error reading permission {} from json for claim {} belonging to {}. No such permission exist", entry.getKey(), this.claimID, this.owner); } }); } } ConfigHandler.fromJson(obj, "PermGroup").entrySet().forEach(key -> { Map map = new HashMap<>(); JsonObject group = key.getValue().getAsJsonObject(); group.entrySet().forEach(gkey -> { try { map.put(PermissionRegistry.get(gkey.getKey()), gkey.getValue().getAsBoolean()); } catch (NullPointerException e) { Flan.logger.error("Error reading permission {} from json for claim {} belonging to {}. No such permission exist", gkey.getKey(), this.claimID, this.owner); } }); this.permissions.put(key.getKey(), map); }); ConfigHandler.fromJson(obj, "PlayerPerms").entrySet() .forEach(key -> this.playersGroups.put(UUID.fromString(key.getKey()), key.getValue().getAsString())); ConfigHandler.arryFromJson(obj, "SubClaims") .forEach(sub -> this.subClaims.add(Claim.fromJson(sub.getAsJsonObject(), this.owner, this.world))); ConfigHandler.arryFromJson(obj, "FakePlayers") .forEach(e -> { try { this.fakePlayers.add(UUID.fromString(e.getAsString())); } catch (IllegalArgumentException ignored) { } }); } catch (Exception e) { throw new IllegalStateException("Error reading claim data for claim " + uuid); } } public JsonObject toJson(JsonObject obj) { obj.addProperty("ID", this.claimID.toString()); obj.addProperty("Name", this.claimName); JsonArray pos = new JsonArray(); pos.add(this.minX); pos.add(this.maxX); pos.add(this.minZ); pos.add(this.maxZ); pos.add(this.minY); obj.add("PosxXzZY", pos); JsonArray home = new JsonArray(); home.add(this.homePos.getX()); home.add(this.homePos.getY()); home.add(this.homePos.getZ()); obj.add("Home", home); obj.addProperty("EnterTitle", this.enterTitle == null ? "" : Component.Serializer.toJson(this.enterTitle)); obj.addProperty("EnterSubtitle", this.enterSubtitle == null ? "" : Component.Serializer.toJson(this.enterSubtitle)); obj.addProperty("LeaveTitle", this.leaveTitle == null ? "" : Component.Serializer.toJson(this.leaveTitle)); obj.addProperty("LeaveSubtitle", this.leaveSubtitle == null ? "" : Component.Serializer.toJson(this.leaveSubtitle)); JsonObject potions = new JsonObject(); this.potions.forEach((effect, amp) -> potions.addProperty(CrossPlatformStuff.INSTANCE.registryStatusEffects().getIDFrom(effect).toString(), amp)); obj.add("Potions", potions); if (this.parent != null) obj.addProperty("Parent", this.parent.toString()); if (!this.globalPerm.isEmpty()) { JsonElement gPerm; if (this.parent == null) { gPerm = new JsonArray(); this.globalPerm.forEach((perm, bool) -> { if (bool) ((JsonArray) gPerm).add(perm.id); }); } else { gPerm = new JsonObject(); this.globalPerm.forEach((perm, bool) -> ((JsonObject) gPerm).addProperty(perm.id, bool)); } obj.add("GlobalPerms", gPerm); } if (!this.permissions.isEmpty()) { JsonObject perms = new JsonObject(); this.permissions.forEach((s, pmap) -> { JsonObject group = new JsonObject(); pmap.forEach((perm, bool) -> group.addProperty(perm.id, bool)); perms.add(s, group); }); obj.add("PermGroup", perms); } if (!this.playersGroups.isEmpty()) { JsonObject pl = new JsonObject(); this.playersGroups.forEach((uuid, s) -> pl.addProperty(uuid.toString(), s)); obj.add("PlayerPerms", pl); } if (!this.subClaims.isEmpty()) { JsonArray list = new JsonArray(); this.subClaims.forEach(p -> list.add(p.toJson(new JsonObject()))); obj.add("SubClaims", list); } if (!this.fakePlayers.isEmpty()) { JsonArray list = new JsonArray(); this.fakePlayers.forEach(uuid -> list.add(uuid.toString())); obj.add("FakePlayers", list); } return obj; } @Override public int hashCode() { return this.claimID == null ? Arrays.hashCode(this.getDimensions()) : this.claimID.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof Claim other) { if (this.claimID == null && other.claimID == null) return Arrays.equals(this.getDimensions(), ((Claim) obj).getDimensions()); if (this.claimID != null) return this.claimID.equals(((Claim) obj).claimID); } return false; } @Override public String toString() { return String.format("Claim:[ID=%s, Owner=%s, from: [x=%d,z=%d], to: [x=%d,z=%d]", this.claimID != null ? this.claimID.toString() : "null", this.owner != null ? this.owner.toString() : "Admin", this.minX, this.minZ, this.maxX, this.maxZ); } public String nameAndPosition() { if (this.claimName.isEmpty()) return String.format("[x=%d,z=%d]-[x=%d,z=%d]", this.minX, this.minZ, this.maxX, this.maxZ); return String.format("%s:[x=%d,z=%d]-[x=%d,z=%d]", this.claimName, this.minX, this.minZ, this.maxX, this.maxZ); } public String formattedClaim() { if (this.claimName.isEmpty()) return String.format("[x=%d,z=%d] - [x=%d,z=%d] = %d blocks", this.minX, this.minZ, this.maxX, this.maxZ, this.getPlane()); return String.format("%s:[x=%d,z=%d] - [x=%d,z=%d] = %d blocks", this.claimName, this.minX, this.minZ, this.maxX, this.maxZ, this.getPlane()); } public List infoString(ServerPlayer player, InfoType infoType) { boolean perms = this.canInteract(player, PermissionRegistry.EDITPERMS, player.blockPosition()); List l = new ArrayList<>(); l.add(PermHelper.simpleColoredText("=============================================", ChatFormatting.GREEN)); String ownerName = this.isAdminClaim() ? "Admin" : player.getServer().getProfileCache().get(this.owner).map(GameProfile::getName).orElse(""); if (this.parent == null) { if (this.claimName.isEmpty()) l.add(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("claimBasicInfo"), ownerName, this.minX, this.minZ, this.maxX, this.maxZ, this.subClaims.size()), ChatFormatting.GOLD)); else l.add(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("claimBasicInfoNamed"), ownerName, this.minX, this.minZ, this.maxX, this.maxZ, this.subClaims.size(), this.claimName), ChatFormatting.GOLD)); } else { if (this.claimName.isEmpty()) l.add(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("claimBasicInfoSub"), ownerName, this.minX, this.minZ, this.maxX, this.maxZ), ChatFormatting.GOLD)); else l.add(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("claimBasicInfoSubNamed"), ownerName, this.minX, this.minZ, this.maxX, this.maxZ, this.claimName), ChatFormatting.GOLD)); } if (perms) { if (infoType == InfoType.ALL || infoType == InfoType.GLOBAL) l.add(fromPermissionMap("claimInfoPerms", this.globalPerm)); if (infoType == InfoType.ALL || infoType == InfoType.GROUP) { l.add(PermHelper.simpleColoredText(ConfigHandler.langManager.get("claimGroupInfoHeader"), ChatFormatting.GOLD)); Map> nameToGroup = new HashMap<>(); for (Map.Entry e : this.playersGroups.entrySet()) { player.getServer().getProfileCache().get(e.getKey()).ifPresent(pgroup -> nameToGroup.merge(e.getValue(), Lists.newArrayList(pgroup.getName()), (old, val) -> { old.add(pgroup.getName()); return old; }) ); } for (Map.Entry> e : this.permissions.entrySet()) { l.add(PermHelper.simpleColoredText(String.format(" %s:", e.getKey()), ChatFormatting.YELLOW)); l.add(fromPermissionMap("claimGroupPerms", e.getValue())); l.add(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("claimGroupPlayers"), nameToGroup.getOrDefault(e.getKey(), new ArrayList<>())), ChatFormatting.RED)); } } } l.add(PermHelper.simpleColoredText("=============================================", ChatFormatting.GREEN)); return l; } private static Component fromPermissionMap(String lang, Map map) { MutableComponent mapComp = Component.literal("[").withStyle(ChatFormatting.GRAY); int i = 0; for (Map.Entry entry : map.entrySet()) { MutableComponent pComp = Component.literal((i != 0 ? ", " : "") + entry.getKey().id + "=").withStyle(ChatFormatting.GRAY); pComp.append(Component.literal(entry.getValue().toString()).withStyle(entry.getValue() ? ChatFormatting.GREEN : ChatFormatting.RED)); mapComp.append(pComp); i++; } mapComp.append("]"); MutableComponent component = Component.translatable(ConfigHandler.langManager.get(lang), mapComp).withStyle(ChatFormatting.DARK_BLUE); return component; } public DisplayBox display() { return new ClaimDisplayBox(this, () -> new DisplayBox.Box(this.minX, this.minY, this.minZ, this.maxX, this.world.getMaxBuildHeight(), this.maxZ), this::isRemoved); } public enum InfoType { ALL, SIMPLE, GLOBAL, GROUP } interface ClaimUpdater { Map updater = Config.createHashMap(map -> map.put(2, claim -> claim.globalPerm.put(PermissionRegistry.LOCKITEMS, true))); static void updateClaim(Claim claim) { updater.entrySet().stream().filter(e -> e.getKey() > ConfigHandler.config.preConfigVersion).map(Map.Entry::getValue) .forEach(up -> up.update(claim)); } void update(Claim claim); } }