923 lines
39 KiB
Java
923 lines
39 KiB
Java
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<ClaimPermission, Boolean> globalPerm = new HashMap<>();
|
|
private final Map<String, Map<ClaimPermission, Boolean>> permissions = new HashMap<>();
|
|
|
|
private final Map<UUID, String> playersGroups = new HashMap<>();
|
|
|
|
private final Set<UUID> fakePlayers = new HashSet<>();
|
|
|
|
private final List<Claim> 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<MobEffect, Integer> 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<Claim> 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<ServerPlayer> 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<ClaimPermission, Boolean> 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<Claim> 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<Claim> 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<Claim> getAllSubclaims() {
|
|
return ImmutableList.copyOf(this.subClaims);
|
|
}
|
|
|
|
public Set<Claim> 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<Claim> 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<String> playersFromGroup(MinecraftServer server, String group) {
|
|
List<UUID> l = new ArrayList<>();
|
|
this.playersGroups.forEach((uuid, g) -> {
|
|
if (g.equals(group))
|
|
l.add(uuid);
|
|
});
|
|
List<String> names = new ArrayList<>();
|
|
l.forEach(uuid -> server.getProfileCache().get(uuid).ifPresent(prof -> names.add(prof.getName())));
|
|
names.sort(null);
|
|
return names;
|
|
}
|
|
|
|
public List<String> 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<ClaimPermission, Boolean> 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<UUID> 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<String> groups() {
|
|
List<String> 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<MobEffect, Integer> 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<ClaimPermission, Boolean> 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<Component> infoString(ServerPlayer player, InfoType infoType) {
|
|
boolean perms = this.canInteract(player, PermissionRegistry.EDITPERMS, player.blockPosition());
|
|
List<Component> l = new ArrayList<>();
|
|
l.add(PermHelper.simpleColoredText("=============================================", ChatFormatting.GREEN));
|
|
String ownerName = this.isAdminClaim() ? "Admin" : player.getServer().getProfileCache().get(this.owner).map(GameProfile::getName).orElse("<UNKNOWN>");
|
|
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<String, List<String>> nameToGroup = new HashMap<>();
|
|
for (Map.Entry<UUID, String> 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<String, Map<ClaimPermission, Boolean>> 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<ClaimPermission, Boolean> map) {
|
|
MutableComponent mapComp = Component.literal("[").withStyle(ChatFormatting.GRAY);
|
|
int i = 0;
|
|
for (Map.Entry<ClaimPermission, Boolean> 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<Integer, ClaimUpdater> 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);
|
|
}
|
|
}
|