Skip to content

Commit

Permalink
GH-677 Add home admin feature. (#683)
Browse files Browse the repository at this point in the history
* Add home admin feature.

* Fix checkstyle violations.

* Update “homeName” variable to “name”

* Setup base of suggestions.

* work in progress.

* work in progress.

* Update eternalcore-core/src/main/java/com/eternalcode/core/translation/implementation/PLTranslation.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update eternalcore-core/src/main/java/com/eternalcode/core/feature/home/homeadmin/PlayerHomeMultiArgument.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Follow @Rollczi and @coderabbitai feedback.

* Follow @Rollczi feedback.

---------

Co-authored-by: Norbert Dejlich <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 20, 2024
1 parent 90cee8e commit ebd42af
Show file tree
Hide file tree
Showing 8 changed files with 349 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ public boolean hasHome(UUID playerUniqueId, String name) {
return homes.containsKey(name);
}

@Override
public boolean hasHome(UUID playerUniqueId, Home home) {
Map<String, Home> homes = this.userHomes.get(playerUniqueId);

if (homes == null) {
return false;
}

return homes.containsValue(home);
}

@Override
public Optional<Home> getHome(UUID uniqueId, String name) {
Map<String, Home> homes = this.userHomes.get(uniqueId);
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = "<user> <home> [location]")
void setHome(@Context Player sender, @Arg PlayerHomeEntry playerHomeEntry, @Arg Optional<Location> 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 = "<user> <home>")
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 = "<user> <home>")
void home(@Context Player player, @Arg PlayerHomeEntry playerHomeEntry) {
Home home = playerHomeEntry.home();
Player user = playerHomeEntry.player();

Optional<Home> 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 = "<user>")
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(", "));
}
}

Original file line number Diff line number Diff line change
@@ -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) {
}
Original file line number Diff line number Diff line change
@@ -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<CommandSender, PlayerHomeEntry> {

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<PlayerHomeEntry> parse(
Invocation<CommandSender> invocation,
Argument<PlayerHomeEntry> 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<Home> 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> home = this.homeManager.getHome(uniqueId, homeName);

if (home.isEmpty()) {
Collection<Home> 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<PlayerHomeEntry> playerHomeEntryArgument) {
return Range.of(2);
}

@Override
public SuggestionResult suggest(
Invocation<CommandSender> invocation,
Argument<PlayerHomeEntry> 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<Home> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public interface Translation {
ArgumentSection argument();

interface ArgumentSection {
Notice missingPlayerName();
Notice permissionMessage();
Notice usageMessage();
Notice usageMessageHead();
Expand Down Expand Up @@ -205,6 +206,12 @@ interface HomeSection {
Notice overrideHomeLocation();
Notice noHomesOwned();
String noHomesOwnedPlaceholder();

Notice overrideHomeLocationAsAdmin();
Notice playerNoOwnedHomes();
Notice createAsAdmin();
Notice deleteAsAdmin();
Notice homeListAsAdmin();
}

// tpa section
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public static class ENArgumentSection implements ArgumentSection {
public Notice usageMessageEntry = Notice.chat("<green>► <white>{USAGE}");

@Description(" ")
public Notice missingPlayerName = Notice.chat("<red>✘ <dark_red>You must provide a player name!");
public Notice offlinePlayer = Notice.chat("<red>✘ <dark_red>This player is currently offline!");
public Notice onlyPlayer = Notice.chat("<red>✘ <dark_red>Command is only for players!");
public Notice numberBiggerThanOrEqualZero = Notice.chat("<red>✘ <dark_red>The number must be greater than or equal to 0!");
Expand Down Expand Up @@ -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("<green>► <white>Home <green>{HOME} <white>has been overridden for <green>{PLAYER}<white>.");
public Notice playerNoOwnedHomes = Notice.chat("<dark_red>✘ <red>Player <dark_red>{PLAYER} <red>doesn't have any homes.");
public Notice createAsAdmin = Notice.chat("<green>► <white>Home <green>{HOME} <white>has been created for <green>{PLAYER}<white>.");
public Notice deleteAsAdmin = Notice.chat("<red>► <white>Home <red>{HOME} <white>has been deleted for <red>{PLAYER}<white>.");
public Notice homeListAsAdmin = Notice.chat("<green>► <white>Available homes for <green>{PLAYER}<white>: <green>{HOMES}");
}

@Description({
Expand Down
Loading

0 comments on commit ebd42af

Please sign in to comment.