diff --git a/Changelog.md b/Changelog.md index 072c743..840f322 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,13 @@ Flan 1.8.4 - Prevent dragon egg interaction near claims without permissions - Fix invalid player data when editing offline player data - Make owned allays not able to pickup locked items or if claim disables pickup items in general +- Add special list for handling fake players in claim. + Instead of adding fakeplayers to permission groups you can add fake players to this list instead. + Command is: /flan fakePlayer uuid + Note: Some mods dont have a fixed uuid for fake players meaning the uuid changes each server restart. + This means you need to reconfig it every restart for those mods. + Report it to them to have them make it persistent. +- Also add notification when fakeplayers cannot perform their action in a claim Flan 1.8.3 ================ diff --git a/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java b/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java index 52faa82..64369ce 100644 --- a/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java +++ b/common/src/main/java/io/github/flemmli97/flan/claim/Claim.java @@ -65,6 +65,8 @@ public class Claim implements IPermissionContainer { private final Map playersGroups = new HashMap<>(); + private final Set fakePlayers = new HashSet<>(); + private final List subClaims = new ArrayList<>(); private UUID parent; @@ -271,6 +273,8 @@ public class Claim implements IPermissionContainer { 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; } @@ -284,6 +288,8 @@ public class Claim implements IPermissionContainer { 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; @@ -296,6 +302,8 @@ public class Claim implements IPermissionContainer { 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())) { @@ -312,6 +320,8 @@ public class Claim implements IPermissionContainer { 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)) @@ -329,6 +339,8 @@ public class Claim implements IPermissionContainer { 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; } } @@ -336,6 +348,8 @@ public class Claim implements IPermissionContainer { 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; } @@ -450,6 +464,12 @@ public class Claim implements IPermissionContainer { 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) -> { @@ -462,6 +482,10 @@ public class Claim implements IPermissionContainer { 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; @@ -602,11 +626,11 @@ public class Claim implements IPermissionContainer { } public void displayEnterTitle(ServerPlayer player) { - displayTitleMessage(player, this.enterTitle, this.enterSubtitle); + this.displayTitleMessage(player, this.enterTitle, this.enterSubtitle); } public void displayLeaveTitle(ServerPlayer player) { - displayTitleMessage(player, this.leaveTitle, this.leaveSubtitle); + this.displayTitleMessage(player, this.leaveTitle, this.leaveSubtitle); } /** @@ -705,6 +729,13 @@ public class Claim implements IPermissionContainer { .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); } @@ -767,6 +798,11 @@ public class Claim implements IPermissionContainer { 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; } @@ -793,6 +829,12 @@ public class Claim implements IPermissionContainer { 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()); diff --git a/common/src/main/java/io/github/flemmli97/flan/commands/CommandClaim.java b/common/src/main/java/io/github/flemmli97/flan/commands/CommandClaim.java index 39ca70b..16ed0d4 100644 --- a/common/src/main/java/io/github/flemmli97/flan/commands/CommandClaim.java +++ b/common/src/main/java/io/github/flemmli97/flan/commands/CommandClaim.java @@ -30,6 +30,7 @@ import net.minecraft.commands.Commands; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.arguments.ComponentArgument; import net.minecraft.commands.arguments.GameProfileArgument; +import net.minecraft.commands.arguments.UuidArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -105,15 +106,29 @@ public class CommandClaim { .then(Commands.literal("remove").then(Commands.argument("group", StringArgumentType.word()).suggests(CommandHelpers::groupSuggestion) .then(Commands.argument("players", GameProfileArgument.gameProfile()).suggests((context, build) -> { ServerPlayer player = context.getSource().getPlayerOrException(); + String group = StringArgumentType.getString(context, "group"); List list = new ArrayList<>(); CommandSourceStack src = context.getSource(); ClaimStorage storage = ClaimStorage.get(src.getLevel()); Claim claim = storage.getClaimAt(src.getPlayerOrException().blockPosition()); if (claim != null && claim.canInteract(src.getPlayerOrException(), PermissionRegistry.EDITPERMS, src.getPlayerOrException().blockPosition())) { - list = claim.playersFromGroup(player.getServer(), ""); + list = claim.playersFromGroup(player.getServer(), group); } return SharedSuggestionProvider.suggest(list, build); }).executes(CommandClaim::removePlayer)))))) + .then(Commands.literal("fakePlayer").executes(CommandClaim::toggleFakePlayer) + .then(Commands.literal("add").requires(src -> PermissionNodeHandler.INSTANCE.perm(src, PermissionNodeHandler.cmdFakePlayer, true)).then(Commands.argument("uuid", UuidArgument.uuid()).executes(CommandClaim::addFakePlayer))) + .then(Commands.literal("remove").requires(src -> PermissionNodeHandler.INSTANCE.perm(src, PermissionNodeHandler.cmdFakePlayer, true)) + .then(Commands.argument("uuid", UuidArgument.uuid()).suggests((context, build) -> { + List list = new ArrayList<>(); + CommandSourceStack src = context.getSource(); + ClaimStorage storage = ClaimStorage.get(src.getLevel()); + Claim claim = storage.getClaimAt(src.getPlayerOrException().blockPosition()); + if (claim != null && claim.canInteract(src.getPlayerOrException(), PermissionRegistry.EDITPERMS, src.getPlayerOrException().blockPosition())) { + list = claim.getAllowedFakePlayerUUID(); + } + return SharedSuggestionProvider.suggest(list, build); + }).executes(CommandClaim::removeFakePlayer)))) .then(Commands.literal("teleport").requires(src -> PermissionNodeHandler.INSTANCE.perm(src, PermissionNodeHandler.cmdTeleport)) .then(Commands.literal("self").then(Commands.argument("claim", StringArgumentType.string()).suggests((ctx, b) -> CommandHelpers.claimSuggestions(ctx, b, ctx.getSource().getPlayerOrException().getUUID())) .executes(CommandClaim::teleport))) @@ -645,8 +660,53 @@ public class CommandClaim { if (!modified.isEmpty()) player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("playerModify"), group, modified), ChatFormatting.GOLD), false); else - player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("playerModifyNo"), group, modified), ChatFormatting.RED), false); - return Command.SINGLE_SUCCESS; + player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("playerModifyNo"), group), ChatFormatting.RED), false); + return modified.size(); + } + + private static int toggleFakePlayer(CommandContext context) throws CommandSyntaxException { + ServerPlayer player = context.getSource().getPlayerOrException(); + PlayerClaimData data = PlayerClaimData.get(player); + data.setFakePlayerNotif(!data.hasFakePlayerNotificationOn()); + player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("fakePlayerNotification"), data.hasFakePlayerNotificationOn()), ChatFormatting.GOLD), false); + return 1; + } + + private static int addFakePlayer(CommandContext context) throws CommandSyntaxException { + return modifyFakePlayer(context, false); + } + + private static int removeFakePlayer(CommandContext context) throws CommandSyntaxException { + return modifyFakePlayer(context, true); + } + + private static int modifyFakePlayer(CommandContext context, boolean remove) throws CommandSyntaxException { + ServerPlayer player = context.getSource().getPlayerOrException(); + ClaimStorage storage = ClaimStorage.get(player.getLevel()); + Claim claim = storage.getClaimAt(player.blockPosition()); + if (claim == null) { + PermHelper.noClaimMessage(player); + return 0; + } + if (PlayerClaimData.get(player).getEditMode() == EnumEditMode.SUBCLAIM) { + Claim sub = claim.getSubClaim(player.blockPosition()); + if (sub != null) + claim = sub; + } + if (!claim.canInteract(player, PermissionRegistry.EDITPERMS, player.blockPosition())) { + player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("noPermission"), ChatFormatting.DARK_RED), false); + return 0; + } + UUID uuid = UuidArgument.getUuid(context, "uuid"); + if (claim.modifyFakePlayerUUID(uuid, remove)) { + if (!remove) + player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("uuidFakeAdd"), uuid), ChatFormatting.GOLD), false); + else + player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("uuidFakeRemove"), uuid), ChatFormatting.GOLD), false); + return 1; + } + player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("uuidFakeModifyNo"), ChatFormatting.RED), false); + return 0; } private static int editGlobalPerm(CommandContext context) throws CommandSyntaxException { diff --git a/common/src/main/java/io/github/flemmli97/flan/config/LangManager.java b/common/src/main/java/io/github/flemmli97/flan/config/LangManager.java index 4a8e2cb..ec2c6ed 100644 --- a/common/src/main/java/io/github/flemmli97/flan/config/LangManager.java +++ b/common/src/main/java/io/github/flemmli97/flan/config/LangManager.java @@ -68,6 +68,9 @@ public class LangManager { this.defaultTranslation.put("groupAdd", "Added group %1$s"); this.defaultTranslation.put("groupRemove", "Removed group %1$s"); this.defaultTranslation.put("groupExist", "Group already exist"); + this.defaultTranslation.put("uuidFakeAdd", "Added fakeplayer with uuid %1$s to the claim"); + this.defaultTranslation.put("uuidFakeRemove", "Removed fakeplayer with uuid %1$s from the claim"); + this.defaultTranslation.put("uuidFakeModifyNo", "Fakeplayer with given uuid is already added"); this.defaultTranslation.put("playerModify", "Modified permission group for following players to %1$s: %2$s"); this.defaultTranslation.put("playerModifyNo", "Couldn't set permission group for the players. Probably cause they already belong to a group"); this.defaultTranslation.put("playerGroupAddFail", "Couldn't add that player to the group either cause the player " + @@ -98,6 +101,12 @@ public class LangManager { this.defaultTranslation.put("readConflict", "%1$s conflicts with existing claims. Not added to world! Conflicts:"); this.defaultTranslation.put("giveClaimBlocks", "Gave following players %2$d claimblocks: %1$s"); + this.defaultTranslation.put("fakePlayerNotification1", "A fakeplayer tried to interact with your claim at %1$s in %2$s."); + this.defaultTranslation.put("fakePlayerNotification2", "Click %s while standing in your claim to add the fakeplayer to the claim."); + this.defaultTranslation.put("clickableComponent", "here"); + this.defaultTranslation.put("fakePlayerNotification3", "Click %s to disable this notification."); + this.defaultTranslation.put("fakePlayerNotification", "FakePlayer notification set to %s"); + this.defaultTranslation.put("claimBasicInfo", "Owner: %1$s, from: [x=%2$d,z=%3$d] to [x=%4$d,z=%5$d]); Subclaim-amount: %6$d"); this.defaultTranslation.put("claimBasicInfoNamed", "Claim: %7$s, Owner: %1$s, from: [x=%2$d,z=%3$d] to [x=%4$d,z=%5$d]); Subclaim-amount: %6$d"); this.defaultTranslation.put("claimSubHeader", "==SubclaimInfo=="); @@ -129,6 +138,7 @@ public class LangManager { this.defaultTranslation.put("screenMenuGroup", "Edit Permissiongroups"); this.defaultTranslation.put("screenMenuPotion", "Edit Potioneffects"); this.defaultTranslation.put("screenMenuClaimText", "Edit Enter/Leave Text"); + this.defaultTranslation.put("screenMenuFakePlayers", "Fake Players"); this.defaultTranslation.put("screenMenuDelete", "Delete Claim"); this.defaultTranslation.put("screenConfirm", "Confirm"); this.defaultTranslation.put("screenYes", "Yes"); @@ -141,6 +151,7 @@ public class LangManager { this.defaultTranslation.put("screenGroupPerms", "%1$s-Permissions"); this.defaultTranslation.put("screenPersonalGroups", "Personal-Groups"); this.defaultTranslation.put("screenPersonalPermissions", "Personal Permissions for %1$s"); + this.defaultTranslation.put("screenFakePlayerNameUUID", "%s"); this.defaultTranslation.put("screenPotions", "Claim Potions"); this.defaultTranslation.put("screenPotionText", "%s"); this.defaultTranslation.put("screenTitleEditor", "Claim messages"); diff --git a/common/src/main/java/io/github/flemmli97/flan/gui/ClaimMenuScreenHandler.java b/common/src/main/java/io/github/flemmli97/flan/gui/ClaimMenuScreenHandler.java index 9e972cf..3bdb0ca 100644 --- a/common/src/main/java/io/github/flemmli97/flan/gui/ClaimMenuScreenHandler.java +++ b/common/src/main/java/io/github/flemmli97/flan/gui/ClaimMenuScreenHandler.java @@ -81,6 +81,13 @@ public class ClaimMenuScreenHandler extends ServerOnlyScreenHandler { ServerScreenHelper.addLore(sign, ServerScreenHelper.coloredGuiText(ConfigHandler.langManager.get("screenNoPerm"), ChatFormatting.DARK_RED)); inv.updateStack(i, sign); } + case 6 -> { + ItemStack head = new ItemStack(Items.ZOMBIE_HEAD); + head.setHoverName(ServerScreenHelper.coloredGuiText(ConfigHandler.langManager.get("screenMenuFakePlayers"), ChatFormatting.GOLD)); + if (player instanceof ServerPlayer && !this.hasPerm(claim, (ServerPlayer) player, PermissionRegistry.EDITPERMS)) + ServerScreenHelper.addLore(head, ServerScreenHelper.coloredGuiText(ConfigHandler.langManager.get("screenNoPerm"), ChatFormatting.DARK_RED)); + inv.updateStack(i, head); + } case 8 -> { ItemStack delete = new ItemStack(Items.BARRIER); delete.setHoverName(ServerScreenHelper.coloredGuiText(ConfigHandler.langManager.get("screenMenuDelete"), ChatFormatting.RED)); @@ -95,7 +102,7 @@ public class ClaimMenuScreenHandler extends ServerOnlyScreenHandler { @Override protected boolean isRightSlot(int slot) { - return slot == 0 || slot == 2 || slot == 3 || slot == 4 || slot == 5 || slot == 8; + return slot == 0 || slot == 2 || slot == 3 || slot == 4 || slot == 5 || slot == 6 || slot == 8; } @Override @@ -137,6 +144,14 @@ public class ClaimMenuScreenHandler extends ServerOnlyScreenHandler { } else ServerScreenHelper.playSongToPlayer(player, SoundEvents.VILLAGER_NO, 1, 1f); break; + case 6: + if (this.hasPerm(this.claim, player, PermissionRegistry.EDITPERMS)) { + player.closeContainer(); + player.getServer().execute(() -> FakePlayerScreenHandler.open(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } else + ServerScreenHelper.playSongToPlayer(player, SoundEvents.VILLAGER_NO, 1, 1f); + break; case 8: if (this.hasPerm(this.claim, player, PermissionRegistry.EDITCLAIM)) { player.closeContainer(); diff --git a/common/src/main/java/io/github/flemmli97/flan/gui/FakePlayerScreenHandler.java b/common/src/main/java/io/github/flemmli97/flan/gui/FakePlayerScreenHandler.java new file mode 100644 index 0000000..3c41999 --- /dev/null +++ b/common/src/main/java/io/github/flemmli97/flan/gui/FakePlayerScreenHandler.java @@ -0,0 +1,133 @@ +package io.github.flemmli97.flan.gui; + +import io.github.flemmli97.flan.claim.Claim; +import io.github.flemmli97.flan.claim.PermHelper; +import io.github.flemmli97.flan.config.ConfigHandler; +import io.github.flemmli97.flan.gui.inv.SeparateInv; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import java.util.List; +import java.util.UUID; + +public class FakePlayerScreenHandler extends ServerOnlyScreenHandler { + + private final Claim claim; + private boolean removeMode; + + private FakePlayerScreenHandler(int syncId, Inventory playerInventory, Claim claim) { + super(syncId, playerInventory, 6, claim); + this.claim = claim; + } + + public static void open(Player player, Claim claim) { + MenuProvider fac = new MenuProvider() { + @Override + public AbstractContainerMenu createMenu(int syncId, Inventory inv, Player player) { + return new FakePlayerScreenHandler(syncId, inv, claim); + } + + @Override + public Component getDisplayName() { + return PermHelper.simpleColoredText(ConfigHandler.langManager.get("screenMenuFakePlayers")); + } + }; + player.openMenu(fac); + } + + @Override + protected void fillInventoryWith(Player player, SeparateInv inv, Claim claim) { + List players = claim.getAllowedFakePlayerUUID(); + for (int i = 0; i < 54; i++) { + if (i == 0) { + ItemStack close = new ItemStack(Items.TNT); + close.setHoverName(ServerScreenHelper.coloredGuiText(ConfigHandler.langManager.get("screenBack"), ChatFormatting.DARK_RED)); + inv.updateStack(i, close); + } else if (i == 3) { + ItemStack stack = new ItemStack(Items.ANVIL); + stack.setHoverName(ServerScreenHelper.coloredGuiText(ConfigHandler.langManager.get("screenAdd"), ChatFormatting.DARK_GREEN)); + inv.updateStack(i, stack); + } else if (i == 4) { + ItemStack stack = new ItemStack(Items.REDSTONE_BLOCK); + stack.setHoverName(ServerScreenHelper.coloredGuiText(String.format(ConfigHandler.langManager.get("screenRemoveMode"), this.removeMode ? ConfigHandler.langManager.get("screenTrue") : ConfigHandler.langManager.get("screenFalse")), ChatFormatting.DARK_RED)); + inv.updateStack(i, stack); + } else if (i < 9 || i > 44 || i % 9 == 0 || i % 9 == 8) + inv.updateStack(i, ServerScreenHelper.emptyFiller()); + else { + int row = i / 9 - 1; + int id = (i % 9) + row * 7 - 1; + if (id < players.size()) { + ItemStack fakePlayer = new ItemStack(Items.ZOMBIE_HEAD); + fakePlayer.setHoverName(ServerScreenHelper.coloredGuiText(String.format(ConfigHandler.langManager.get("screenFakePlayerNameUUID"), players.get(id)), ChatFormatting.YELLOW)); + inv.updateStack(i, fakePlayer); + } + } + } + } + + @Override + protected boolean isRightSlot(int slot) { + return slot == 0 || slot == 3 || slot == 4 || (slot < 45 && slot > 8 && slot % 9 != 0 && slot % 9 != 8); + } + + @Override + protected boolean handleSlotClicked(ServerPlayer player, int index, Slot slot, int clickType) { + if (index == 0) { + player.closeContainer(); + player.getServer().execute(() -> ClaimMenuScreenHandler.openClaimMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + if (index == 3) { + player.closeContainer(); + player.getServer().execute(() -> StringResultScreenHandler.createNewStringResult(player, (s) -> { + boolean fl = player.getServer().getProfileCache().get(s).map(prof -> this.claim.modifyFakePlayerUUID(prof.getId(), false)).orElse(true); + player.closeContainer(); + player.getServer().execute(() -> FakePlayerScreenHandler.open(player, this.claim)); + if (fl) + ServerScreenHelper.playSongToPlayer(player, SoundEvents.ANVIL_USE, 1, 1f); + else { + player.displayClientMessage(PermHelper.simpleColoredText(ConfigHandler.langManager.get("playerGroupAddFail"), ChatFormatting.RED), false); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.VILLAGER_NO, 1, 1f); + } + }, () -> { + player.closeContainer(); + player.getServer().execute(() -> FakePlayerScreenHandler.open(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.VILLAGER_NO, 1, 1f); + })); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + if (index == 4) { + this.removeMode = !this.removeMode; + ItemStack stack = new ItemStack(Items.REDSTONE_BLOCK); + stack.setHoverName(ServerScreenHelper.coloredGuiText(String.format(ConfigHandler.langManager.get("screenRemoveMode"), this.removeMode ? ConfigHandler.langManager.get("screenTrue") : ConfigHandler.langManager.get("screenFalse")), ChatFormatting.DARK_RED)); + slot.set(stack); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + ItemStack stack = slot.getItem(); + if (!stack.isEmpty()) { + UUID uuid = null; + try { + uuid = UUID.fromString(stack.getHoverName().getString()); + } catch (IllegalArgumentException ignored) { + } + if (this.removeMode && uuid != null) { + this.claim.modifyFakePlayerUUID(uuid, true); + slot.set(ItemStack.EMPTY); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.BAT_DEATH, 1, 1f); + } + } + return false; + } +} diff --git a/common/src/main/java/io/github/flemmli97/flan/platform/integration/permissions/PermissionNodeHandler.java b/common/src/main/java/io/github/flemmli97/flan/platform/integration/permissions/PermissionNodeHandler.java index 086c564..37267eb 100644 --- a/common/src/main/java/io/github/flemmli97/flan/platform/integration/permissions/PermissionNodeHandler.java +++ b/common/src/main/java/io/github/flemmli97/flan/platform/integration/permissions/PermissionNodeHandler.java @@ -33,6 +33,7 @@ public interface PermissionNodeHandler { String cmdAdminGive = "flan.command.admin.give"; String cmdGroup = "flan.command.group"; + String cmdFakePlayer = "flan.command.fakeplayer"; String cmdPermission = "flan.command.permission"; String cmdSell = "flan.command.buy"; diff --git a/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java b/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java index 9581b93..1863eb2 100644 --- a/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java +++ b/common/src/main/java/io/github/flemmli97/flan/player/PlayerClaimData.java @@ -23,6 +23,10 @@ import io.github.flemmli97.flan.scoreboard.ClaimCriterias; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.Style; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -81,6 +85,10 @@ public class PlayerClaimData implements IPlayerData { private boolean shouldProtectDrop, calculateShouldDrop = true; + private final Map> fakePlayerNotif = new HashMap<>(); + + private boolean fakePlayerNotification = true; + public PlayerClaimData(ServerPlayer player) { this.player = player; this.claimBlocks = ConfigHandler.config.startingBlocks; @@ -300,7 +308,7 @@ public class PlayerClaimData implements IPlayerData { this.claimBlockMessage = true; this.player.displayClientMessage(PermHelper.simpleColoredText(String.format(ConfigHandler.langManager.get("claimBlocksFormat"), this.getClaimBlocks(), this.getAdditionalClaims(), this.usedClaimBlocks(), this.remainingClaimBlocks()), ChatFormatting.GOLD), false); - this.addDisplayClaim(currentClaim, EnumDisplayType.MAIN, player.blockPosition().getY()); + this.addDisplayClaim(currentClaim, EnumDisplayType.MAIN, this.player.blockPosition().getY()); } this.actionCooldown--; if (--this.trappedTick >= 0) { @@ -408,6 +416,40 @@ public class PlayerClaimData implements IPlayerData { return this.shouldProtectDrop; } + public void setFakePlayerNotif(boolean on) { + this.fakePlayerNotification = on; + } + + public boolean hasFakePlayerNotificationOn() { + return this.fakePlayerNotification; + } + + public void notifyFakePlayerInteraction(ServerPlayer fakePlayer, BlockPos pos, Claim claim) { + if (!this.fakePlayerNotification) + return; + Map map = this.fakePlayerNotif.computeIfAbsent(claim.getClaimID(), o -> new HashMap<>()); + Long last = map.get(fakePlayer.getUUID()); + if (last == null || this.player.getLevel().getGameTime() - 1200 > last) { + Component claimMsg = Component.literal(String.format(ConfigHandler.langManager.get("fakePlayerNotification1"), claim.getWorld().dimension().location().toString(), pos)).withStyle(ChatFormatting.DARK_RED); + this.player.sendSystemMessage(claimMsg); + String cmdStr = String.format("/flan fakePlayer add %s", fakePlayer.getUUID().toString()); + Component cmd = Component.literal(ConfigHandler.langManager.get("clickableComponent")) + .withStyle(Style.EMPTY.withColor(ChatFormatting.GOLD) + .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmdStr)) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(cmdStr)))); + Component msg = Component.translatable(ConfigHandler.langManager.get("fakePlayerNotification2"), cmd); + this.player.sendSystemMessage(msg); + cmdStr = "/flan fakePlayer"; + cmd = Component.literal(ConfigHandler.langManager.get("clickableComponent")) + .withStyle(Style.EMPTY.withColor(ChatFormatting.GOLD) + .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmdStr)) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(cmdStr)))); + msg = Component.translatable(ConfigHandler.langManager.get("fakePlayerNotification3"), cmd); + this.player.sendSystemMessage(msg); + map.put(fakePlayer.getUUID(), this.player.getLevel().getGameTime()); + } + } + public void save(MinecraftServer server) { Flan.log("Saving player data for player {} with uuid {}", this.player.getName(), this.player.getUUID()); Path dir = ConfigHandler.getPlayerSavePath(server); @@ -429,6 +471,7 @@ public class PlayerClaimData implements IPlayerData { defPerm.add(key, perm); }); obj.add("DefaultGroups", defPerm); + obj.addProperty("FakePlayerNotification", this.fakePlayerNotification); JsonWriter jsonWriter = ConfigHandler.GSON.newJsonWriter(Files.newBufferedWriter(file, StandardCharsets.UTF_8)); ConfigHandler.GSON.toJson(obj, jsonWriter); @@ -466,6 +509,7 @@ public class PlayerClaimData implements IPlayerData { }); } }); + this.fakePlayerNotification = ConfigHandler.fromJson(obj, "FakePlayerNotification", true); updateScoreFor(this.player, ClaimCriterias.AMOUNT, this.claimBlocks + this.additionalClaimBlocks); this.updateClaimScores(); } catch (IOException e) {