diff --git a/eternalcore-api/src/main/java/com/eternalcode/core/feature/home/HomeService.java b/eternalcore-api/src/main/java/com/eternalcode/core/feature/home/HomeService.java index 6b062c360..911b5b6fa 100644 --- a/eternalcore-api/src/main/java/com/eternalcode/core/feature/home/HomeService.java +++ b/eternalcore-api/src/main/java/com/eternalcode/core/feature/home/HomeService.java @@ -18,6 +18,8 @@ public interface HomeService { boolean hasHome(UUID playerUniqueId, String name); + boolean hasHome(UUID playerUniqueId, Home home); + void deleteHome(UUID playerUniqueId, String name); @Nullable diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomeManager.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomeManager.java index 7a57cce01..0dd357e4a 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomeManager.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomeManager.java @@ -123,6 +123,17 @@ public boolean hasHome(UUID playerUniqueId, String name) { return homes.containsKey(name); } + @Override + public boolean hasHome(UUID playerUniqueId, Home home) { + Map homes = this.userHomes.get(playerUniqueId); + + if (homes == null) { + return false; + } + + return homes.containsValue(home); + } + @Override public Optional getHome(UUID uniqueId, String name) { Map homes = this.userHomes.get(uniqueId); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/HomeAdminCommand.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/HomeAdminCommand.java new file mode 100644 index 000000000..23a632f21 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/HomeAdminCommand.java @@ -0,0 +1,134 @@ +package com.eternalcode.core.feature.home.homeadmin; + +import com.eternalcode.annotations.scan.command.DescriptionDocs; +import com.eternalcode.core.feature.home.Home; +import com.eternalcode.core.feature.home.HomeManager; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.notice.NoticeService; +import com.eternalcode.core.user.User; +import com.eternalcode.core.viewer.Viewer; +import dev.rollczi.litecommands.annotations.argument.Arg; +import dev.rollczi.litecommands.annotations.command.Command; +import dev.rollczi.litecommands.annotations.context.Context; +import dev.rollczi.litecommands.annotations.execute.Execute; +import dev.rollczi.litecommands.annotations.permission.Permission; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +@Command(name = "homeadmin") +@Permission("eternalcode.home.admin") +class HomeAdminCommand { + + private final HomeManager homeManager; + private final NoticeService noticeService; + + @Inject + public HomeAdminCommand(HomeManager homeManager, NoticeService noticeService) { + this.homeManager = homeManager; + this.noticeService = noticeService; + } + + @Execute(name = "sethome") + @DescriptionDocs(description = "Set home for user", arguments = " [location]") + void setHome(@Context Player sender, @Arg PlayerHomeEntry playerHomeEntry, @Arg Optional location) { + Location optionalLocation = location.orElse(sender.getLocation()); + + Home home = playerHomeEntry.home(); + Player player = playerHomeEntry.player(); + UUID uniqueId = player.getUniqueId(); + + boolean hasHome = this.homeManager.hasHome(uniqueId, home); + String name = home.getName(); + + if (hasHome) { + this.homeManager.createHome(uniqueId, name, optionalLocation); + this.noticeService.create() + .notice(translate -> translate.home().overrideHomeLocationAsAdmin()) + .placeholder("{HOME}", name) + .player(player.getUniqueId()) + .send(); + + return; + } + + this.homeManager.createHome(uniqueId, name, optionalLocation); + this.noticeService.create() + .notice(translate -> translate.home().createAsAdmin()) + .placeholder("{HOME}", name) + .player(player.getUniqueId()) + .send(); + } + + @Execute(name = "delhome") + @DescriptionDocs(description = "Delete home for user", arguments = " ") + void deleteHome(@Context Player sender, @Arg PlayerHomeEntry playerHomeEntry) { + Home home = playerHomeEntry.home(); + Player player = playerHomeEntry.player(); + + UUID uniqueId = player.getUniqueId(); + boolean hasHome = this.homeManager.hasHome(uniqueId, home); + + if (!hasHome) { + String homes = this.formattedListUserHomes(uniqueId); + + this.noticeService.create() + .notice(translate -> translate.home().homeList()) + .placeholder("{HOMES}", homes) + .player(sender.getUniqueId()) + .send(); + + return; + } + + this.homeManager.deleteHome(uniqueId, home.getName()); + this.noticeService.create() + .notice(translate -> translate.home().deleteAsAdmin()) + .placeholder("{HOME}", home.getName()) + .placeholder("{PLAYER}", player.getName()) + .player(sender.getUniqueId()) + .send(); + } + + @Execute(name = "home") + @DescriptionDocs(description = "Teleport to user home", arguments = " ") + void home(@Context Player player, @Arg PlayerHomeEntry playerHomeEntry) { + Home home = playerHomeEntry.home(); + Player user = playerHomeEntry.player(); + + Optional homeOption = this.homeManager.getHome(user.getUniqueId(), home.getName()); + + if (homeOption.isEmpty()) { + this.noticeService.create() + .notice(translate -> translate.home().playerNoOwnedHomes()) + .placeholder("{HOME}", home.getName()) + .player(player.getUniqueId()) + .send(); + + return; + } + + player.teleport(homeOption.get().getLocation()); + } + + @Execute(name = "list") + @DescriptionDocs(description = "List user homes", arguments = "") + void list(@Context Viewer viewer, @Arg User user) { + String homes = this.formattedListUserHomes(user.getUniqueId()); + + this.noticeService.create() + .notice(translate -> translate.home().homeListAsAdmin()) + .placeholder("{HOMES}", homes) + .viewer(viewer) + .send(); + } + + private String formattedListUserHomes(UUID uniqueId) { + return this.homeManager.getHomes(uniqueId).stream() + .map(home -> home.getName()) + .collect(Collectors.joining(", ")); + } +} + diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeEntry.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeEntry.java new file mode 100644 index 000000000..9388df48f --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeEntry.java @@ -0,0 +1,7 @@ +package com.eternalcode.core.feature.home.homeadmin; + +import com.eternalcode.core.feature.home.Home; +import org.bukkit.entity.Player; + +record PlayerHomeEntry(Player player, Home home) { +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeMultiArgument.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeMultiArgument.java new file mode 100644 index 000000000..1cce738f3 --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeMultiArgument.java @@ -0,0 +1,163 @@ +package com.eternalcode.core.feature.home.homeadmin; + +import com.eternalcode.core.feature.home.Home; +import com.eternalcode.core.feature.home.HomeManager; +import com.eternalcode.core.injector.annotations.Inject; +import com.eternalcode.core.injector.annotations.lite.LiteArgument; +import com.eternalcode.core.notice.NoticeService; +import com.eternalcode.core.viewer.Viewer; +import com.eternalcode.core.viewer.ViewerService; +import com.eternalcode.multification.notice.NoticeBroadcast; +import dev.rollczi.litecommands.argument.Argument; +import dev.rollczi.litecommands.argument.parser.ParseResult; +import dev.rollczi.litecommands.argument.resolver.MultipleArgumentResolver; +import dev.rollczi.litecommands.input.raw.RawInput; +import dev.rollczi.litecommands.invocation.Invocation; +import dev.rollczi.litecommands.range.Range; +import dev.rollczi.litecommands.suggestion.Suggestion; +import dev.rollczi.litecommands.suggestion.SuggestionContext; +import dev.rollczi.litecommands.suggestion.SuggestionResult; +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +@LiteArgument(type = PlayerHomeEntry.class) +class PlayerHomeMultiArgument implements MultipleArgumentResolver { + + private static final String HOME_LIST_PLACEHOLDER_PREFIX = "{HOMES}"; + private static final String PLAYER_NAME_PLACEHOLDER_PREFIX = "{PLAYER}"; + private static final String HOME_DELIMITER = ", "; + + private final HomeManager homeManager; + private final NoticeService noticeService; + private final ViewerService viewerService; + private final Server server; + + @Inject + PlayerHomeMultiArgument( + HomeManager homeManager, + NoticeService noticeService, + ViewerService viewerService, + Server server + ) { + this.homeManager = homeManager; + this.noticeService = noticeService; + this.viewerService = viewerService; + this.server = server; + } + + @Override + public ParseResult parse( + Invocation invocation, + Argument argument, + RawInput rawInput + ) { + Viewer viewer = this.viewerService.any(invocation.sender()); + + NoticeBroadcast offlinePlayer = this.noticeService.create() + .notice(translation -> translation.argument().offlinePlayer()) + .viewer(viewer); + + if (!rawInput.hasNext()) { + NoticeBroadcast missingPlayerName = this.noticeService.create() + .notice(translation -> translation.argument().missingPlayerName()) + .viewer(viewer); + return ParseResult.failure(missingPlayerName); + } + + String playerName = rawInput.next(); + Player player = this.server.getPlayer(playerName); + + if (player == null) { + return ParseResult.failure(offlinePlayer); + } + + UUID uniqueId = player.getUniqueId(); + if (!rawInput.hasNext()) { + Collection homes = this.homeManager.getHomes(uniqueId); + if (homes.isEmpty()) { + NoticeBroadcast home = this.noticeService.create() + .notice(translate -> translate.home().playerNoOwnedHomes()) + .placeholder(PLAYER_NAME_PLACEHOLDER_PREFIX, player.getName()) + .player(uniqueId); + return ParseResult.failure(home); + } + NoticeBroadcast homeListNotice = homeNotice(homes, player, uniqueId); + return ParseResult.failure(homeListNotice); + } + + String homeName = rawInput.next(); + Optional home = this.homeManager.getHome(uniqueId, homeName); + + if (home.isEmpty()) { + Collection homes = this.homeManager.getHomes(uniqueId); + + NoticeBroadcast homeListNotice = homeNotice(homes, player, uniqueId); + + return ParseResult.failure(homeListNotice); + } + + return ParseResult.success(new PlayerHomeEntry(player, home.get())); + } + + @Override + public Range getRange(Argument playerHomeEntryArgument) { + return Range.of(2); + } + + @Override + public SuggestionResult suggest( + Invocation invocation, + Argument argument, + SuggestionContext context + ) { + Suggestion current = context.getCurrent(); + int index = current.lengthMultilevel(); + + if (index == 1) { + return SuggestionResult.of(this.server.getOnlinePlayers().stream() + .map(Player::getName) + .collect(Collectors.toList())); + } + + if (index == 2) { + String playerName = current.multilevelList().get(0); + Player player = this.server.getPlayer(playerName); + + if (player == null) { + return SuggestionResult.empty(); + } + + return SuggestionResult.of(this.homeManager.getHomes(player.getUniqueId()).stream() + .map(Home::getName) + .collect(Collectors.toList())) + .appendLeft(playerName); + } + + return SuggestionResult.empty(); + } + + private NoticeBroadcast homeNotice(Collection homes, Player player, UUID uniqueId) { + if (homes.isEmpty()) { + this.noticeService.create() + .notice(translate -> translate.home().playerNoOwnedHomes()) + .placeholder(PLAYER_NAME_PLACEHOLDER_PREFIX, player.getName()) + .player(uniqueId) + .send(); + } + + String homeList = homes.stream() + .map(h -> h.getName()) + .collect(Collectors.joining(HOME_DELIMITER)); + + return this.noticeService.create() + .notice(translate -> homes.isEmpty() ? translate.home().playerNoOwnedHomes() : translate.home().homeList()) + .placeholder(HOME_LIST_PLACEHOLDER_PREFIX, homeList) + .placeholder(PLAYER_NAME_PLACEHOLDER_PREFIX, player.getName()) + .player(uniqueId); + } +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/translation/Translation.java b/eternalcore-core/src/main/java/com/eternalcode/core/translation/Translation.java index d7a65b62f..1367f8533 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/translation/Translation.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/translation/Translation.java @@ -19,6 +19,7 @@ public interface Translation { ArgumentSection argument(); interface ArgumentSection { + Notice missingPlayerName(); Notice permissionMessage(); Notice usageMessage(); Notice usageMessageHead(); @@ -205,6 +206,12 @@ interface HomeSection { Notice overrideHomeLocation(); Notice noHomesOwned(); String noHomesOwnedPlaceholder(); + + Notice overrideHomeLocationAsAdmin(); + Notice playerNoOwnedHomes(); + Notice createAsAdmin(); + Notice deleteAsAdmin(); + Notice homeListAsAdmin(); } // tpa section diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/ENTranslation.java b/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/ENTranslation.java index cad457d68..f77de1e3a 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/ENTranslation.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/ENTranslation.java @@ -108,6 +108,7 @@ public static class ENArgumentSection implements ArgumentSection { public Notice usageMessageEntry = Notice.chat("{USAGE}"); @Description(" ") + public Notice missingPlayerName = Notice.chat("You must provide a player name!"); public Notice offlinePlayer = Notice.chat("This player is currently offline!"); public Notice onlyPlayer = Notice.chat("Command is only for players!"); public Notice numberBiggerThanOrEqualZero = Notice.chat("The number must be greater than or equal to 0!"); @@ -439,6 +440,17 @@ public static class ENHomeSection implements HomeSection { @Description({" ", "# Placeholders messages"}) public String noHomesOwnedPlaceholder = "You don't have any homes."; + + @Description({ + " ", + "# Home Admin Section, you can edit player homes as admin", + "# {HOME} - Home name, {PLAYER} - Player name, {HOMES} - List of homes (separated by commas)" + }) + public Notice overrideHomeLocationAsAdmin = Notice.chat("Home {HOME} has been overridden for {PLAYER}."); + public Notice playerNoOwnedHomes = Notice.chat("Player {PLAYER} doesn't have any homes."); + public Notice createAsAdmin = Notice.chat("Home {HOME} has been created for {PLAYER}."); + public Notice deleteAsAdmin = Notice.chat("Home {HOME} has been deleted for {PLAYER}."); + public Notice homeListAsAdmin = Notice.chat("Available homes for {PLAYER}: {HOMES}"); } @Description({ diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/PLTranslation.java b/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/PLTranslation.java index ec798beba..28c5efcc6 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/PLTranslation.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/PLTranslation.java @@ -103,7 +103,9 @@ public static class PLArgumentSection implements ArgumentSection { public Notice usageMessage = Notice.chat("Poprawne użycie: {USAGE}"); public Notice usageMessageHead = Notice.chat("Poprawne użycie:"); public Notice usageMessageEntry = Notice.chat("{USAGE}"); + @Description(" ") + public Notice missingPlayerName = Notice.chat("Błąd: Musisz podać nazwę gracza!"); public Notice offlinePlayer = Notice.chat("Błąd: Ten gracz jest obecnie offline!"); public Notice onlyPlayer = Notice.chat("Błąd: Ta komenda jest dostępna tylko dla graczy!"); public Notice numberBiggerThanOrEqualZero = Notice.chat("Błąd: Liczba musi być równa lub większa od 0!"); @@ -445,6 +447,17 @@ public static class PLHomeSection implements HomeSection { @Description({" ", "# Wiadomości placeholderów"}) public String noHomesOwnedPlaceholder = "Nie posiadasz żadnego domu."; + + @Description({ + " ", + "# Sekcja wiadomości administracyjnych dla domów graczy", + "# {HOME} - Nazwa domu, {PLAYER} - Gracz, {HOMES} - Lista domów" + }) + public Notice overrideHomeLocationAsAdmin = Notice.chat("Nadpisałeś lokalizację domu {HOME} dla gracza {PLAYER}!"); + public Notice playerNoOwnedHomes = Notice.chat("Błąd: Gracz {PLAYER} nie posiada żadnego domu!"); + public Notice createAsAdmin = Notice.chat("Stworzono dom {HOME} dla gracza {PLAYER}!"); + public Notice deleteAsAdmin = Notice.chat("Usunięto dom {HOME} dla gracza {PLAYER}!"); + public Notice homeListAsAdmin = Notice.chat("Lista domów gracza {PLAYER}: {HOMES}!"); } @Description({