diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java index 8b0334189..c7d00d979 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamCommand.java @@ -78,6 +78,8 @@ public class IslandTeamCommand extends CompositeCommand { private IslandTeamInviteRejectCommand rejectCommand; + private IslandTeamInviteCommand inviteCommand; + public IslandTeamCommand(CompositeCommand parent) { super(parent, "team"); inviteMap = new HashMap<>(); @@ -89,7 +91,7 @@ public class IslandTeamCommand extends CompositeCommand { setOnlyPlayer(true); setDescription("commands.island.team.description"); // Register commands - new IslandTeamInviteCommand(this); + inviteCommand = new IslandTeamInviteCommand(this); leaveCommand = new IslandTeamLeaveCommand(this); setOwnerCommand = new IslandTeamSetownerCommand(this); kickCommand = new IslandTeamKickCommand(this); @@ -164,13 +166,31 @@ public class IslandTeamCommand extends CompositeCommand { panelBuilder.registerTypeBuilder("MEMBER", this::createMemberButton); panelBuilder.registerTypeBuilder("INVITED", this::createInvitedButton); panelBuilder.registerTypeBuilder("RANK", this::createRankButton); - //panelBuilder.registerTypeBuilder("KICK", this::createKickButton); + panelBuilder.registerTypeBuilder("INVITE", this::createInviteButton); border = panelBuilder.getPanelTemplate().border(); background = panelBuilder.getPanelTemplate().background(); // Register unknown type builder. panelBuilder.build(); } + private PanelItem createInviteButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) { + if (island == null || !user.hasPermission(this.inviteCommand.getPermission()) + || island.getRank(user) < island.getRankCommand(this.getLabel() + " invite")) { + return this.getBlankBorder(); + } + PanelItemBuilder builder = new PanelItemBuilder(); + builder.icon(Material.PLAYER_HEAD); + builder.name(user.getTranslation("commands.island.team.gui.buttons.invite.name")); + builder.clickHandler((panel, user, clickType, clickSlot) -> { + if (clickType.equals(ClickType.LEFT)) { + user.closeInventory(); + this.inviteCommand.build(user); + } + return true; + }); + return builder.build(); + } + private PanelItem createRankButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) { // If there is no island, the do not show this icon if (island == null) { diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java index 4585dfc7c..95cca395f 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteCommand.java @@ -1,11 +1,15 @@ package world.bentobox.bentobox.api.commands.island.team; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.api.commands.CompositeCommand; @@ -13,6 +17,12 @@ import world.bentobox.bentobox.api.commands.island.team.Invite.Type; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.panels.PanelItem; +import world.bentobox.bentobox.api.panels.TemplatedPanel; +import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder; +import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder; +import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord; +import world.bentobox.bentobox.api.panels.reader.PanelTemplateRecord.TemplateItem; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.IslandsManager; @@ -24,6 +34,9 @@ public class IslandTeamInviteCommand extends CompositeCommand { private final IslandTeamCommand itc; private @Nullable User invitedPlayer; + private @Nullable TemplateItem border; + private @Nullable TemplateItem background; + private User user; public IslandTeamInviteCommand(IslandTeamCommand parent) { super(parent, "invite"); @@ -36,6 +49,8 @@ public class IslandTeamInviteCommand extends CompositeCommand { setOnlyPlayer(true); setDescription("commands.island.team.invite.description"); setConfigurableRankCommand(); + // Panels + getPlugin().saveResource("panels/team_invite_panel.yml", true); } @@ -65,6 +80,7 @@ public class IslandTeamInviteCommand extends CompositeCommand { Type inviteType = getInviteType(playerUUID); if (inviteType != null) { + // TODO: send to team command to present invite String name = getPlayers().getName(playerUUID); switch (inviteType) { case COOP -> user.sendMessage("commands.island.team.invite.name-has-invited-you.coop", TextVariables.NAME, name); @@ -73,7 +89,7 @@ public class IslandTeamInviteCommand extends CompositeCommand { } return true; } - + build(user); showHelp(this, user); return false; } @@ -204,4 +220,60 @@ public class IslandTeamInviteCommand extends CompositeCommand { return Optional.of(Util.tabLimit(options, lastArg)); } + public void build(User user) { + this.user = user; + // Start building panel. + TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder(); + panelBuilder.user(user); + panelBuilder.world(user.getWorld()); + + panelBuilder.template("team_panel", new File(getPlugin().getDataFolder(), "panels")); + + panelBuilder.parameters("[name]", user.getName(), "[display_name]", user.getDisplayName()); + + panelBuilder.registerTypeBuilder("PROSPECT", this::createProspectButton); + //panelBuilder.registerTypeBuilder("INVITED", this::createInvitedButton); + //panelBuilder.registerTypeBuilder("RANK", this::createRankButton); + //panelBuilder.registerTypeBuilder("INVITE", this::createInviteButton); + border = panelBuilder.getPanelTemplate().border(); + background = panelBuilder.getPanelTemplate().background(); + // Register unknown type builder. + panelBuilder.build(); + + } + + /** + * Create member button panel item. + * + * @param template the template + * @param slot the slot + * @return the panel item + */ + private PanelItem createProspectButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) { + // Player issuing the command must have an island + Island island = getIslands().getPrimaryIsland(getWorld(), user.getUniqueId()); + if (island == null) { + return this.getBlankBackground(); + } + // TODO: THERE"S A BUG HERE + return user.getWorld().getPlayers().stream() + .filter(player -> !getIslands().inTeam(getWorld(), player.getUniqueId())).skip(slot.slot() - 1) + .limit(1L) + .findFirst().map(this::getProspect).orElse(this.getBlankBackground()); + } + + private PanelItem getProspect(Player player) { + return new PanelItemBuilder().icon(player.getName()).build(); + } + + private PanelItem getBlankBorder() { + return new PanelItemBuilder().icon(Objects.requireNonNullElse(border.icon(), new ItemStack(Material.BARRIER))) + .name((Objects.requireNonNullElse(border.title(), ""))).build(); + } + + private PanelItem getBlankBackground() { + return new PanelItemBuilder() + .icon(Objects.requireNonNullElse(background.icon(), new ItemStack(Material.BARRIER))) + .name((Objects.requireNonNullElse(background.title(), ""))).build(); + } } diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 128529eb2..0014ef630 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -623,9 +623,12 @@ commands: name: "Rank Filter" description: "&a Click to cycle ranks" invitation: "Invitation" + invite: + name: "Invite player" tips: LEFT: name: "&b Left Click" + invite: "&a to invite a player" RIGHT: name: "&b Right Click" SHIFT_RIGHT: @@ -704,6 +707,21 @@ commands: to-accept-or-reject: '&a Do /[label] team accept to accept, or /[label] team reject to reject' you-will-lose-your-island: '&c WARNING! You will lose your island if you accept!' + gui: + titles: + team-invite-panel: "Invite Players" + tips: + LEFT: + name: "&b Left Click" + invite: | + &a to invite a player + &a to join your team + RIGHT: + name: "&b Right Click" + coop: "&a to coop player" + SHIFT_LEFT: + name: "&b Shift Left Click" + trust: "&a to trust a player" errors: cannot-invite-self: '&c You cannot invite yourself!' cooldown: '&c You cannot invite that person for another [number] seconds.' diff --git a/src/main/resources/panels/team_invite_panel.yml b/src/main/resources/panels/team_invite_panel.yml new file mode 100644 index 000000000..722a0bd8b --- /dev/null +++ b/src/main/resources/panels/team_invite_panel.yml @@ -0,0 +1,90 @@ +# Name of panel used for indentification in the code - must be the same name as the filename. +team_panel: + # Title of the panel shown to the user. This is a reference and the reference will be translatable in the locale file + title: commands.island.team.invite.gui.titles.team-invite-panel + # The type of panel to show. Options are INVENTORY, HOPPER, DROPPER. INVENTORY is that standard chest inventory and + # the others refer to the inventories shown for those items. + type: INVENTORY + # The background of the panel. These items will be shown if other items are not there. STAINED_GLASS_PANEs give a good effect. + background: + icon: BLACK_STAINED_GLASS_PANE + # Each item may have text applied to it, but usually for background items, nothing is shown. + title: "&b&r" # Empty text. This is using the Bukkit chat color coding with &'s. + border: + # The border of each panel may be shown as a different item. + # It can be used to provide a contrast to items in the panel. + icon: BLUE_STAINED_GLASS_PANE + title: "&b&r" # Empty text + # This tag indicates which rows in the panel must be shown. The panel will be sized vertically accordingly. This does not include the borders. + # This can be a list and rows must be between 1 and 6, if used. + force-shown: [] + # The content section contains details of each item/button in the panel. The numbers indicate the rows and then then columns of each item. + content: + # Row number + 2: + 2: prospect_button + 3: prospect_button + 4: prospect_button + 5: prospect_button + 6: prospect_button + 7: prospect_button + 8: prospect_button + 3: + 2: prospect_button + 3: prospect_button + 4: prospect_button + 5: prospect_button + 6: prospect_button + 7: prospect_button + 8: prospect_button + 4: + 2: prospect_button + 3: prospect_button + 4: prospect_button + 5: prospect_button + 6: prospect_button + 7: prospect_button + 8: prospect_button + 5: + 2: prospect_button + 3: prospect_button + 4: prospect_button + 5: prospect_button + 6: prospect_button + 7: prospect_button + 8: prospect_button + 6: + 2: prospect_button + 3: prospect_button + 4: prospect_button + 5: prospect_button + 6: prospect_button + 7: prospect_button + 8: prospect_button + # This is where reusable buttons are defined. + reusable: + # This is the name of the button that is referenced + prospect_button: + # If the icon for a button is not defined, it defaults to AIR and so effectively will not be shown. + # icons are usually not defined if the icon is going to be dynamically set in the panel, e.g. in this case the material will vary + #icon: STONE + title: commands.island.team.invite.gui.buttons.member.name + description: commands.island.team.invite.gui.buttons.member.description + data: + type: PROSPECT + # Actions cover what happens if the button is clicked or the mouse is moved over it. There can be multiple actions possible for different + # click-types. + actions: + # Each action has an arbitrary descriptive name to define it. + invite: + # The click-type is the same as the bukkit {@link org.bukkit.event.inventory.ClickType}. UNKNOWN is the default. + click-type: LEFT + # tooltip is a locale reference that will be translated for the user and shown when they hover over the button. + tooltip: commands.island.team.invite.gui.tips.LEFT.invite + coop: + click-type: RIGHT + tooltip: commands.island.team.invite.gui.tips.RIGHT.coop + trust: + click-type: SHIFT_LEFT + tooltip: commands.island.team.invite.gui.tips.SHIFT_LEFT.trust + \ No newline at end of file diff --git a/src/main/resources/panels/team_panel.yml b/src/main/resources/panels/team_panel.yml index e9ca5d19f..c34deb8d4 100644 --- a/src/main/resources/panels/team_panel.yml +++ b/src/main/resources/panels/team_panel.yml @@ -13,7 +13,7 @@ team_panel: border: # The border of each panel may be shown as a different item. # It can be used to provide a contrast to items in the panel. - icon: BLACK_STAINED_GLASS_PANE + icon: BLUE_STAINED_GLASS_PANE title: "&b&r" # Empty text # This tag indicates which rows in the panel must be shown. The panel will be sized vertically accordingly. This does not include the borders. # This can be a list and rows must be between 1 and 6, if used. @@ -61,6 +61,15 @@ team_panel: reject: click-type: SHIFT_RIGHT tooltip: commands.island.team.gui.tips.SHIFT_RIGHT.reject + 7: + # Invite button + data: + type: INVITE + name: commands.island.team.gui.buttons.invite + actions: + invite: + click-type: LEFT + tooltip: commands.island.team.gui.tips.LEFT.invite 2: 2: member_button 3: member_button