mirror of
https://github.com/plexusorg/Module-Guilds.git
synced 2026-07-14 19:34:54 +00:00
Merge pull request #1 from plexusorg/codex/guild-worlds-gui
Add ASP guild worlds and management GUIs
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
plugins {
|
||||
java
|
||||
`maven-publish`
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
|
||||
maven {
|
||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
@@ -13,6 +16,10 @@ repositories {
|
||||
}
|
||||
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
url = uri("https://repo.infernalsuite.com/repository/maven-snapshots/")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -21,6 +28,8 @@ dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:26.1.2.build.+")
|
||||
implementation("org.apache.commons:commons-lang3:3.20.0")
|
||||
compileOnly("dev.plex:api:2.0-SNAPSHOT")
|
||||
compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT")
|
||||
implementation("com.infernalsuite.asp:file-loader:4.0.0-SNAPSHOT")
|
||||
implementation("org.jetbrains:annotations:26.1.0")
|
||||
}
|
||||
|
||||
@@ -45,6 +54,16 @@ tasks.getByName<Jar>("jar") {
|
||||
archiveVersion.set("")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveBaseName.set("Module-Guilds")
|
||||
archiveClassifier.set("")
|
||||
archiveVersion.set("")
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
|
||||
tasks {
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
|
||||
@@ -4,10 +4,14 @@ import dev.plex.command.GuildCommand;
|
||||
import dev.plex.config.ModuleConfig;
|
||||
import dev.plex.guild.GuildHolder;
|
||||
import dev.plex.handler.ChatHandlerImpl;
|
||||
import dev.plex.handler.GuildMenuListener;
|
||||
import dev.plex.handler.GuildWorldProtectionListener;
|
||||
import dev.plex.handler.RankPermissionMenuListener;
|
||||
import dev.plex.module.PlexModule;
|
||||
import dev.plex.api.storage.ModuleStorage;
|
||||
import dev.plex.storage.GuildRepository;
|
||||
import dev.plex.storage.JdbiGuildRepository;
|
||||
import dev.plex.world.GuildWorldService;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.sql.SQLException;
|
||||
@@ -18,6 +22,10 @@ public class Guilds extends PlexModule
|
||||
{
|
||||
private static Guilds module;
|
||||
private final GuildHolder guildHolder = new GuildHolder();
|
||||
private final GuildMenuListener guildMenuListener = new GuildMenuListener();
|
||||
private final GuildWorldProtectionListener guildWorldProtectionListener = new GuildWorldProtectionListener();
|
||||
private final RankPermissionMenuListener rankPermissionMenuListener = new RankPermissionMenuListener();
|
||||
private final GuildWorldService guildWorldService = new GuildWorldService();
|
||||
|
||||
private GuildRepository guildRepository;
|
||||
|
||||
@@ -36,10 +44,11 @@ public class Guilds extends PlexModule
|
||||
@Override
|
||||
public void enable()
|
||||
{
|
||||
guildWorldService.enable();
|
||||
ModuleStorage storage = api().storage().forModule(this);
|
||||
try
|
||||
{
|
||||
storage.migrations().run(List.of("001_initial_schema"));
|
||||
storage.migrations().run(List.of("001_initial_schema", "002_guild_world_permissions"));
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@@ -62,11 +71,15 @@ public class Guilds extends PlexModule
|
||||
guildHolder.replaceAll(guilds);
|
||||
});
|
||||
registerListener(new ChatHandlerImpl());
|
||||
registerListener(guildMenuListener);
|
||||
registerListener(guildWorldProtectionListener);
|
||||
registerListener(rankPermissionMenuListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable()
|
||||
{
|
||||
guildWorldService.disable();
|
||||
guildHolder.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,13 @@ public class GuildCommand extends SimplePlexCommand
|
||||
this.registerSubCommand(new ChatSubCommand());
|
||||
this.registerSubCommand(new SetHomeSubCommand());
|
||||
this.registerSubCommand(new HomeSubCommand());
|
||||
this.registerSubCommand(new WorldSubCommand());
|
||||
this.registerSubCommand(new PermissionsSubCommand());
|
||||
this.registerSubCommand(new OwnerSubCommand());
|
||||
this.registerSubCommand(new InviteSubCommand());
|
||||
this.registerSubCommand(new AcceptSubCommand());
|
||||
this.registerSubCommand(new DenySubCommand());
|
||||
this.registerSubCommand(new MenuSubCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +54,15 @@ public class GuildCommand extends SimplePlexCommand
|
||||
{
|
||||
if (args.length == 0)
|
||||
{
|
||||
return getSubs();
|
||||
if (player == null)
|
||||
{
|
||||
return getSubs();
|
||||
}
|
||||
Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(
|
||||
guild -> Guilds.get().getGuildMenuListener().openHome(player, guild),
|
||||
() -> player.sendMessage(messageComponent("guildNotFound"))
|
||||
);
|
||||
return null;
|
||||
}
|
||||
if (args[0].equalsIgnoreCase("help"))
|
||||
{
|
||||
|
||||
@@ -37,7 +37,9 @@ public class CreateSubCommand extends GuildSubCommand
|
||||
{
|
||||
return messageComponent("alreadyInGuild");
|
||||
}
|
||||
Guilds.get().getGuildRepository().createGuild(player, StringUtils.join(args, " ")).whenComplete((guild, throwable) ->
|
||||
Guilds.get().getGuildRepository().createGuild(player, StringUtils.join(args, " "))
|
||||
.thenCompose(guild -> Guilds.get().getGuildWorldService().ensureWorld(guild).thenApply(world -> guild))
|
||||
.whenComplete((guild, throwable) ->
|
||||
{
|
||||
if (throwable != null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package dev.plex.command.sub;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.command.source.RequiredCommandSource;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MenuSubCommand extends GuildSubCommand
|
||||
{
|
||||
public MenuSubCommand()
|
||||
{
|
||||
super(command("menu")
|
||||
.description("Opens the guild management menu")
|
||||
.usage("/guild <command>")
|
||||
.aliases("gui,panel")
|
||||
.permission("plex.guilds.menu")
|
||||
.source(RequiredCommandSource.IN_GAME)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args)
|
||||
{
|
||||
assert player != null;
|
||||
Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(
|
||||
guild -> Guilds.get().getGuildMenuListener().openHome(player, guild),
|
||||
() -> send(player, messageComponent("guildNotFound"))
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package dev.plex.command.sub;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.command.source.RequiredCommandSource;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PermissionsSubCommand extends GuildSubCommand
|
||||
{
|
||||
public PermissionsSubCommand()
|
||||
{
|
||||
super(command("permissions")
|
||||
.description("Opens the rank permissions GUI")
|
||||
.usage("/guild <command>")
|
||||
.aliases("perms")
|
||||
.permission("plex.guilds.permissions")
|
||||
.source(RequiredCommandSource.IN_GAME)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args)
|
||||
{
|
||||
assert player != null;
|
||||
Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild ->
|
||||
{
|
||||
if (!guild.isOwner(player.getUniqueId()))
|
||||
{
|
||||
send(player, messageComponent("guildNotOwner"));
|
||||
return;
|
||||
}
|
||||
Guilds.get().getRankPermissionMenuListener().openRankList(player, guild);
|
||||
}, () -> send(player, messageComponent("guildNotFound")));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.plex.command.sub;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.command.source.RequiredCommandSource;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class WorldSubCommand extends GuildSubCommand
|
||||
{
|
||||
public WorldSubCommand()
|
||||
{
|
||||
super(command("world")
|
||||
.description("Teleports to your guild world")
|
||||
.usage("/guild <command>")
|
||||
.aliases("base")
|
||||
.permission("plex.guilds.world")
|
||||
.source(RequiredCommandSource.IN_GAME)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args)
|
||||
{
|
||||
assert player != null;
|
||||
Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild ->
|
||||
{
|
||||
send(player, messageComponent("guildWorldLoading"));
|
||||
Guilds.get().getGuildWorldService().ensureWorld(guild).whenComplete((world, throwable) ->
|
||||
{
|
||||
if (throwable != null)
|
||||
{
|
||||
Guilds.get().api().scheduler().executeGlobal(() ->
|
||||
{
|
||||
throwable.printStackTrace();
|
||||
send(player, messageComponent("guildWorldLoadFailed"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
Guilds.get().api().scheduler().executeEntity(player, () -> teleport(player, world), 1L);
|
||||
});
|
||||
}, () -> send(player, messageComponent("guildNotFound")));
|
||||
return null;
|
||||
}
|
||||
|
||||
private void teleport(Player player, World world)
|
||||
{
|
||||
Location spawnLocation = world.getSpawnLocation().toCenterLocation();
|
||||
player.teleportAsync(spawnLocation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.plex.gui;
|
||||
|
||||
import dev.plex.guild.Guild;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record GuildMenuInventoryHolder(Guild guild, GuildMenuView view, UUID memberUuid) implements InventoryHolder
|
||||
{
|
||||
@Override
|
||||
public @NotNull Inventory getInventory()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package dev.plex.gui;
|
||||
|
||||
public enum GuildMenuView
|
||||
{
|
||||
HOME,
|
||||
MEMBERS,
|
||||
MEMBER
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.plex.gui;
|
||||
|
||||
import dev.plex.guild.Guild;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record RankPermissionInventoryHolder(Guild guild, String rankName) implements InventoryHolder
|
||||
{
|
||||
@Override
|
||||
public @NotNull Inventory getInventory()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,10 @@ package dev.plex.guild;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.guild.data.GuildPermission;
|
||||
import dev.plex.guild.data.GuildRole;
|
||||
import dev.plex.guild.data.Member;
|
||||
import dev.plex.api.player.PlexPlayerView;
|
||||
import dev.plex.util.CustomLocation;
|
||||
import dev.plex.util.GuildUtil;
|
||||
import lombok.Data;
|
||||
@@ -15,6 +17,7 @@ import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@@ -31,6 +34,9 @@ public class Guild
|
||||
private CustomLocation home;
|
||||
private boolean tagEnabled = true;
|
||||
private boolean isPublic;
|
||||
private boolean memberBlockBreaking;
|
||||
private boolean memberBlockPlacing;
|
||||
private boolean memberInteracting;
|
||||
|
||||
public static Guild create(Player player, String guildName)
|
||||
{
|
||||
@@ -62,4 +68,63 @@ public class Guild
|
||||
{
|
||||
return ownerUuid != null && ownerUuid.equals(uuid);
|
||||
}
|
||||
|
||||
public boolean isMember(UUID uuid)
|
||||
{
|
||||
return getMember(uuid) != null;
|
||||
}
|
||||
|
||||
public void removeMember(UUID uuid)
|
||||
{
|
||||
members.removeIf(member -> member.getUuid().equals(uuid));
|
||||
}
|
||||
|
||||
public List<? extends PlexPlayerView> getPlexPlayers()
|
||||
{
|
||||
return members.stream()
|
||||
.map(Member::getPlexPlayer)
|
||||
.flatMap(java.util.Optional::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<Player> getOnlinePlayers()
|
||||
{
|
||||
return getPlexPlayers().stream()
|
||||
.map(PlexPlayerView::bukkitPlayer)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public String getWorldName()
|
||||
{
|
||||
return "guild_" + guildUuid.toString().replace("-", "");
|
||||
}
|
||||
|
||||
public boolean hasPermission(UUID uuid, GuildPermission permission)
|
||||
{
|
||||
if (isOwner(uuid))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!isMember(uuid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return switch (permission)
|
||||
{
|
||||
case BLOCK_BREAKING -> memberBlockBreaking;
|
||||
case BLOCK_PLACING -> memberBlockPlacing;
|
||||
case INTERACTING -> memberInteracting;
|
||||
};
|
||||
}
|
||||
|
||||
public void setPermission(GuildPermission permission, boolean enabled)
|
||||
{
|
||||
switch (permission)
|
||||
{
|
||||
case BLOCK_BREAKING -> memberBlockBreaking = enabled;
|
||||
case BLOCK_PLACING -> memberBlockPlacing = enabled;
|
||||
case INTERACTING -> memberInteracting = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package dev.plex.guild.data;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
public enum GuildPermission
|
||||
{
|
||||
BLOCK_BREAKING("Block Breaking", Material.DIAMOND_PICKAXE),
|
||||
BLOCK_PLACING("Block Placing", Material.GRASS_BLOCK),
|
||||
INTERACTING("Interacting", Material.OAK_BUTTON);
|
||||
|
||||
private final String displayName;
|
||||
private final Material material;
|
||||
|
||||
GuildPermission(String displayName, Material material)
|
||||
{
|
||||
this.displayName = displayName;
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
public String displayName()
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public Material material()
|
||||
{
|
||||
return material;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package dev.plex.guild.data;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.api.player.PlexPlayerView;
|
||||
import lombok.Data;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@@ -28,4 +31,16 @@ public class Member
|
||||
{
|
||||
return Bukkit.getPlayer(this.uuid);
|
||||
}
|
||||
|
||||
public Optional<? extends PlexPlayerView> getPlexPlayer()
|
||||
{
|
||||
return Guilds.get().api().players().player(this.uuid);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return getPlexPlayer()
|
||||
.map(PlexPlayerView::name)
|
||||
.orElse(this.uuid.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
package dev.plex.handler;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.guild.Guild;
|
||||
import dev.plex.guild.data.GuildRole;
|
||||
import dev.plex.guild.data.Member;
|
||||
import dev.plex.gui.GuildMenuInventoryHolder;
|
||||
import dev.plex.gui.GuildMenuView;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GuildMenuListener implements Listener
|
||||
{
|
||||
private static final int MEMBERS_SLOT = 11;
|
||||
private static final int WORLD_SLOT = 13;
|
||||
private static final int PERMISSIONS_SLOT = 15;
|
||||
private static final int BACK_SLOT = 26;
|
||||
private static final int KICK_SLOT = 11;
|
||||
private static final int OWNER_SLOT = 13;
|
||||
private static final int RANK_PERMISSIONS_SLOT = 15;
|
||||
|
||||
public void openHome(Player player, Guild guild)
|
||||
{
|
||||
Inventory inventory = Bukkit.createInventory(new GuildMenuInventoryHolder(guild, GuildMenuView.HOME, null), 27, title("* " + guild.getName()));
|
||||
inventory.setItem(MEMBERS_SLOT, item(Material.PLAYER_HEAD, "Guild Members", NamedTextColor.AQUA, List.of(
|
||||
line("View online status", NamedTextColor.GRAY),
|
||||
line("Click to manage members", NamedTextColor.YELLOW)
|
||||
)));
|
||||
inventory.setItem(WORLD_SLOT, item(Material.GRASS_BLOCK, "Guild World", NamedTextColor.GREEN, List.of(
|
||||
line("Load and enter your guild world", NamedTextColor.GRAY),
|
||||
line("Only guild members can access it", NamedTextColor.DARK_AQUA)
|
||||
)));
|
||||
if (guild.isOwner(player.getUniqueId()))
|
||||
{
|
||||
inventory.setItem(PERMISSIONS_SLOT, item(Material.COMPARATOR, "Rank Permissions", NamedTextColor.GOLD, List.of(
|
||||
line("Configure member build permissions", NamedTextColor.GRAY),
|
||||
line("Break - Place - Interact", NamedTextColor.YELLOW)
|
||||
)));
|
||||
}
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
private void openMembers(Player player, Guild guild)
|
||||
{
|
||||
Inventory inventory = Bukkit.createInventory(new GuildMenuInventoryHolder(guild, GuildMenuView.MEMBERS, null), 54, title("* " + guild.getName() + " Members"));
|
||||
List<Member> members = guild.getMembers();
|
||||
for (int i = 0; i < members.size() && i < 45; i++)
|
||||
{
|
||||
inventory.setItem(i, memberItem(guild, members.get(i)));
|
||||
}
|
||||
inventory.setItem(BACK_SLOT, item(Material.ARROW, "Back", NamedTextColor.YELLOW, List.of(line("Return to the guild menu", NamedTextColor.GRAY))));
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
private void openMember(Player player, Guild guild, Member member)
|
||||
{
|
||||
Inventory inventory = Bukkit.createInventory(new GuildMenuInventoryHolder(guild, GuildMenuView.MEMBER, member.getUuid()), 27, title("* " + member.getName()));
|
||||
inventory.setItem(4, memberItem(guild, member));
|
||||
if (guild.isOwner(player.getUniqueId()) && !guild.isOwner(member.getUuid()))
|
||||
{
|
||||
inventory.setItem(KICK_SLOT, item(Material.BARRIER, "Kick Member", NamedTextColor.RED, List.of(
|
||||
line("Remove this player from the guild", NamedTextColor.GRAY),
|
||||
line("They will lose guild world access", NamedTextColor.DARK_RED)
|
||||
)));
|
||||
inventory.setItem(OWNER_SLOT, item(Material.GOLDEN_HELMET, "Transfer Ownership", NamedTextColor.GOLD, List.of(
|
||||
line("Make this player the guild owner", NamedTextColor.GRAY),
|
||||
line("You will become a regular member", NamedTextColor.YELLOW)
|
||||
)));
|
||||
}
|
||||
if (guild.isOwner(player.getUniqueId()))
|
||||
{
|
||||
inventory.setItem(RANK_PERMISSIONS_SLOT, item(Material.COMPARATOR, "Rank Permissions", NamedTextColor.AQUA, List.of(
|
||||
line("Open the rank permission editor", NamedTextColor.GRAY)
|
||||
)));
|
||||
}
|
||||
inventory.setItem(BACK_SLOT, item(Material.ARROW, "Back", NamedTextColor.YELLOW, List.of(line("Return to member list", NamedTextColor.GRAY))));
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onClick(InventoryClickEvent event)
|
||||
{
|
||||
if (!(event.getWhoClicked() instanceof Player player) || !(event.getInventory().getHolder() instanceof GuildMenuInventoryHolder holder))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
if (!holder.guild().isMember(player.getUniqueId()))
|
||||
{
|
||||
player.closeInventory();
|
||||
player.sendMessage(Guilds.get().messageComponent("guildNotFound"));
|
||||
return;
|
||||
}
|
||||
ItemStack clickedItem = event.getCurrentItem();
|
||||
if (clickedItem == null || clickedItem.getType() == Material.AIR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (holder.view())
|
||||
{
|
||||
case HOME -> clickHome(player, holder.guild(), event.getRawSlot());
|
||||
case MEMBERS -> clickMembers(player, holder.guild(), clickedItem, event.getRawSlot());
|
||||
case MEMBER -> clickMember(player, holder.guild(), holder.memberUuid(), event.getRawSlot());
|
||||
}
|
||||
}
|
||||
|
||||
private void clickHome(Player player, Guild guild, int slot)
|
||||
{
|
||||
if (slot == MEMBERS_SLOT)
|
||||
{
|
||||
openMembers(player, guild);
|
||||
return;
|
||||
}
|
||||
if (slot == WORLD_SLOT)
|
||||
{
|
||||
player.closeInventory();
|
||||
Guilds.get().getGuildWorldService().ensureWorld(guild).whenComplete((world, throwable) ->
|
||||
{
|
||||
if (throwable != null)
|
||||
{
|
||||
Guilds.get().api().scheduler().executeGlobal(() -> player.sendMessage(Guilds.get().messageComponent("guildWorldLoadFailed")));
|
||||
return;
|
||||
}
|
||||
Guilds.get().api().scheduler().executeEntity(player, () -> player.teleportAsync(world.getSpawnLocation().toCenterLocation()), 1L);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (slot == PERMISSIONS_SLOT && guild.isOwner(player.getUniqueId()))
|
||||
{
|
||||
Guilds.get().getRankPermissionMenuListener().openRankList(player, guild);
|
||||
}
|
||||
}
|
||||
|
||||
private void clickMembers(Player player, Guild guild, ItemStack clickedItem, int slot)
|
||||
{
|
||||
if (slot == BACK_SLOT)
|
||||
{
|
||||
openHome(player, guild);
|
||||
return;
|
||||
}
|
||||
memberUuid(clickedItem).map(guild::getMember).filter(Objects::nonNull).ifPresent(member -> openMember(player, guild, member));
|
||||
}
|
||||
|
||||
private void clickMember(Player player, Guild guild, UUID memberUuid, int slot)
|
||||
{
|
||||
Member member = guild.getMember(memberUuid);
|
||||
if (member == null)
|
||||
{
|
||||
openMembers(player, guild);
|
||||
return;
|
||||
}
|
||||
if (slot == BACK_SLOT)
|
||||
{
|
||||
openMembers(player, guild);
|
||||
return;
|
||||
}
|
||||
if (!guild.isOwner(player.getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (slot == KICK_SLOT && !guild.isOwner(memberUuid))
|
||||
{
|
||||
Guilds.get().getGuildRepository().removeMember(guild.getGuildUuid(), memberUuid).whenComplete((unused, throwable) ->
|
||||
{
|
||||
if (throwable != null)
|
||||
{
|
||||
player.sendMessage(Guilds.get().messageComponent("guildStorageFailed"));
|
||||
return;
|
||||
}
|
||||
guild.removeMember(memberUuid);
|
||||
Guilds.get().getGuildHolder().unindexMember(memberUuid);
|
||||
Guilds.get().getGuildWorldService().ejectNonMembers(guild);
|
||||
player.sendMessage(Guilds.get().messageComponent("guildMemberKicked", member.getName()));
|
||||
openMembers(player, guild);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (slot == OWNER_SLOT && !guild.isOwner(memberUuid))
|
||||
{
|
||||
Member previousOwner = guild.getMember(player.getUniqueId());
|
||||
Guilds.get().getGuildRepository().transferOwner(guild.getGuildUuid(), memberUuid, player.getUniqueId()).whenComplete((unused, throwable) ->
|
||||
{
|
||||
if (throwable != null)
|
||||
{
|
||||
player.sendMessage(Guilds.get().messageComponent("guildStorageFailed"));
|
||||
return;
|
||||
}
|
||||
guild.setOwnerUuid(memberUuid);
|
||||
member.setRole(GuildRole.OWNER);
|
||||
if (previousOwner != null)
|
||||
{
|
||||
previousOwner.setRole(GuildRole.MEMBER);
|
||||
}
|
||||
player.sendMessage(Guilds.get().messageComponent("guildOwnerSet", member.getName()));
|
||||
openMember(player, guild, previousOwner == null ? member : previousOwner);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (slot == RANK_PERMISSIONS_SLOT)
|
||||
{
|
||||
Guilds.get().getRankPermissionMenuListener().openRankList(player, guild);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack memberItem(Guild guild, Member member)
|
||||
{
|
||||
boolean online = Bukkit.getPlayer(member.getUuid()) != null;
|
||||
ItemStack itemStack = new ItemStack(online ? Material.LIME_WOOL : Material.GRAY_WOOL);
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
itemMeta.displayName(text(member.getName(), online ? NamedTextColor.GREEN : NamedTextColor.GRAY));
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(label("Status", online ? "Online" : "Offline", online ? NamedTextColor.GREEN : NamedTextColor.GRAY));
|
||||
lore.add(label("Role", guild.isOwner(member.getUuid()) ? "Owner" : "Member", guild.isOwner(member.getUuid()) ? NamedTextColor.GOLD : NamedTextColor.AQUA));
|
||||
lore.add(label("Rank", guild.isOwner(member.getUuid()) ? "Owner" : "Member", NamedTextColor.LIGHT_PURPLE));
|
||||
lore.add(Component.empty());
|
||||
lore.add(line("Click to manage", NamedTextColor.YELLOW));
|
||||
itemMeta.lore(lore);
|
||||
itemMeta.addItemFlags(ItemFlag.values());
|
||||
itemMeta.getPersistentDataContainer().set(Keys.MEMBER_UUID, org.bukkit.persistence.PersistentDataType.STRING, member.getUuid().toString());
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
private ItemStack item(Material material, String name, NamedTextColor color, List<Component> lore)
|
||||
{
|
||||
ItemStack itemStack = new ItemStack(material);
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
itemMeta.displayName(text(name, color));
|
||||
itemMeta.lore(lore);
|
||||
itemMeta.addItemFlags(ItemFlag.values());
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
private Component title(String value)
|
||||
{
|
||||
return text(value, NamedTextColor.DARK_AQUA);
|
||||
}
|
||||
|
||||
private Component text(String value, NamedTextColor color)
|
||||
{
|
||||
return Component.text(value, color).decoration(TextDecoration.ITALIC, false);
|
||||
}
|
||||
|
||||
private Component line(String value, NamedTextColor color)
|
||||
{
|
||||
return text("> " + value, color);
|
||||
}
|
||||
|
||||
private Component label(String label, String value, NamedTextColor valueColor)
|
||||
{
|
||||
return text(label + ": ", NamedTextColor.GRAY).append(text(value, valueColor));
|
||||
}
|
||||
|
||||
private java.util.Optional<UUID> memberUuid(ItemStack itemStack)
|
||||
{
|
||||
if (!itemStack.hasItemMeta())
|
||||
{
|
||||
return java.util.Optional.empty();
|
||||
}
|
||||
String value = itemStack.getItemMeta().getPersistentDataContainer().get(Keys.MEMBER_UUID, org.bukkit.persistence.PersistentDataType.STRING);
|
||||
if (value == null)
|
||||
{
|
||||
return java.util.Optional.empty();
|
||||
}
|
||||
return java.util.Optional.of(UUID.fromString(value));
|
||||
}
|
||||
|
||||
private static class Keys
|
||||
{
|
||||
private static final org.bukkit.NamespacedKey MEMBER_UUID = new org.bukkit.NamespacedKey("plex_guilds", "member_uuid");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package dev.plex.handler;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.guild.Guild;
|
||||
import dev.plex.guild.data.GuildPermission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class GuildWorldProtectionListener implements Listener
|
||||
{
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onTeleport(PlayerTeleportEvent event)
|
||||
{
|
||||
if (event.getTo() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Optional<Guild> guild = guildByWorld(event.getTo().getWorld());
|
||||
if (guild.isPresent() && !guild.get().isMember(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(Guilds.get().messageComponent("guildWorldNoAccess"));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onChangedWorld(PlayerChangedWorldEvent event)
|
||||
{
|
||||
Optional<Guild> guild = guildByWorld(event.getPlayer().getWorld());
|
||||
if (guild.isPresent() && !guild.get().isMember(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
World fallback = Bukkit.getWorlds().getFirst();
|
||||
event.getPlayer().teleportAsync(fallback.getSpawnLocation());
|
||||
event.getPlayer().sendMessage(Guilds.get().messageComponent("guildWorldNoAccess"));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onBlockBreak(BlockBreakEvent event)
|
||||
{
|
||||
if (!canUse(event.getPlayer(), event.getBlock().getWorld(), GuildPermission.BLOCK_BREAKING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(Guilds.get().messageComponent("guildWorldPermissionDenied"));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onBlockPlace(BlockPlaceEvent event)
|
||||
{
|
||||
if (!canUse(event.getPlayer(), event.getBlock().getWorld(), GuildPermission.BLOCK_PLACING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(Guilds.get().messageComponent("guildWorldPermissionDenied"));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onInteract(PlayerInteractEvent event)
|
||||
{
|
||||
if (event.getClickedBlock() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!canUse(event.getPlayer(), event.getClickedBlock().getWorld(), GuildPermission.INTERACTING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(Guilds.get().messageComponent("guildWorldPermissionDenied"));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canUse(Player player, World world, GuildPermission permission)
|
||||
{
|
||||
Optional<Guild> guild = guildByWorld(world);
|
||||
return guild.map(value -> value.hasPermission(player.getUniqueId(), permission)).orElse(true);
|
||||
}
|
||||
|
||||
private Optional<Guild> guildByWorld(World world)
|
||||
{
|
||||
if (world == null)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
return Guilds.get().getGuildHolder().getGuilds().stream()
|
||||
.filter(guild -> guild.getWorldName().equals(world.getName()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package dev.plex.handler;
|
||||
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.guild.Guild;
|
||||
import dev.plex.guild.data.GuildPermission;
|
||||
import dev.plex.gui.RankPermissionInventoryHolder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RankPermissionMenuListener implements Listener
|
||||
{
|
||||
private static final UUID MEMBER_PERMISSION_PROBE = new UUID(0L, 0L);
|
||||
|
||||
public void openRankList(Player player, Guild guild)
|
||||
{
|
||||
Inventory inventory = Bukkit.createInventory(new RankPermissionInventoryHolder(guild, null), 27, title("* Guild Rank Permissions"));
|
||||
inventory.setItem(13, rankItem());
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onClick(InventoryClickEvent event)
|
||||
{
|
||||
if (!(event.getWhoClicked() instanceof Player player) || !(event.getInventory().getHolder() instanceof RankPermissionInventoryHolder holder))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
if (!holder.guild().isOwner(player.getUniqueId()))
|
||||
{
|
||||
player.closeInventory();
|
||||
player.sendMessage(Guilds.get().messageComponent("guildNotOwner"));
|
||||
return;
|
||||
}
|
||||
ItemStack clickedItem = event.getCurrentItem();
|
||||
if (clickedItem == null || clickedItem.getType() == Material.AIR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (holder.rankName() == null)
|
||||
{
|
||||
openPermissionEditor(player, holder.guild());
|
||||
return;
|
||||
}
|
||||
GuildPermission permission = permissionBySlot(event.getRawSlot());
|
||||
if (permission == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
boolean enabled = !holder.guild().hasPermission(MEMBER_PERMISSION_PROBE, permission);
|
||||
holder.guild().setPermission(permission, enabled);
|
||||
Guilds.get().getGuildRepository().updateMemberPermission(holder.guild().getGuildUuid(), permission, enabled);
|
||||
openPermissionEditor(player, holder.guild());
|
||||
}
|
||||
|
||||
private void openPermissionEditor(Player player, Guild guild)
|
||||
{
|
||||
Inventory inventory = Bukkit.createInventory(new RankPermissionInventoryHolder(guild, "MEMBER"), 27, title("* Member Permissions"));
|
||||
GuildPermission[] permissions = GuildPermission.values();
|
||||
for (int i = 0; i < permissions.length; i++)
|
||||
{
|
||||
inventory.setItem(11 + i * 2, permissionItem(guild, permissions[i]));
|
||||
}
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
|
||||
private GuildPermission permissionBySlot(int slot)
|
||||
{
|
||||
return switch (slot)
|
||||
{
|
||||
case 11 -> GuildPermission.BLOCK_BREAKING;
|
||||
case 13 -> GuildPermission.BLOCK_PLACING;
|
||||
case 15 -> GuildPermission.INTERACTING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private ItemStack rankItem()
|
||||
{
|
||||
ItemStack itemStack = new ItemStack(Material.NAME_TAG);
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
itemMeta.displayName(text("Member", NamedTextColor.AQUA));
|
||||
itemMeta.lore(List.of(
|
||||
line("Manage member guild world access", NamedTextColor.GRAY),
|
||||
line("Click to edit permissions", NamedTextColor.YELLOW)
|
||||
));
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
private ItemStack permissionItem(Guild guild, GuildPermission permission)
|
||||
{
|
||||
ItemStack itemStack = new ItemStack(permission.material());
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
boolean enabled = guild.hasPermission(MEMBER_PERMISSION_PROBE, permission);
|
||||
itemMeta.displayName(text(permission.displayName(), enabled ? NamedTextColor.GREEN : NamedTextColor.RED));
|
||||
itemMeta.lore(List.of(
|
||||
text("Status: ", NamedTextColor.GRAY).append(text(enabled ? "Enabled" : "Disabled", enabled ? NamedTextColor.GREEN : NamedTextColor.RED)),
|
||||
Component.empty(),
|
||||
line("Click to toggle", NamedTextColor.YELLOW)
|
||||
));
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
private Component title(String value)
|
||||
{
|
||||
return text(value, NamedTextColor.DARK_AQUA);
|
||||
}
|
||||
|
||||
private Component text(String value, NamedTextColor color)
|
||||
{
|
||||
return Component.text(value, color).decoration(TextDecoration.ITALIC, false);
|
||||
}
|
||||
|
||||
private Component line(String value, NamedTextColor color)
|
||||
{
|
||||
return text("> " + value, color);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.plex.storage;
|
||||
|
||||
import dev.plex.guild.Guild;
|
||||
import dev.plex.guild.data.GuildPermission;
|
||||
import dev.plex.guild.data.GuildRole;
|
||||
import dev.plex.storage.entity.GuildInviteEntity;
|
||||
import dev.plex.util.CustomLocation;
|
||||
@@ -25,6 +26,8 @@ public interface GuildRepository
|
||||
|
||||
CompletableFuture<Void> transferOwner(UUID guildUuid, UUID newOwnerUuid, UUID oldOwnerUuid);
|
||||
|
||||
CompletableFuture<Void> updateMemberPermission(UUID guildUuid, GuildPermission permission, boolean enabled);
|
||||
|
||||
CompletableFuture<Void> updatePrefix(UUID guildUuid, String prefix);
|
||||
|
||||
CompletableFuture<Void> updateHome(UUID guildUuid, CustomLocation home);
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.plex.storage;
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.api.storage.ModuleStorage;
|
||||
import dev.plex.guild.Guild;
|
||||
import dev.plex.guild.data.GuildPermission;
|
||||
import dev.plex.guild.data.GuildRole;
|
||||
import dev.plex.guild.data.Member;
|
||||
import dev.plex.storage.entity.GuildEntity;
|
||||
@@ -92,9 +93,10 @@ public class JdbiGuildRepository implements GuildRepository
|
||||
jdbi.useTransaction(h ->
|
||||
{
|
||||
h.createUpdate("INSERT INTO " + guildsTable + " (guild_uuid, name, prefix, owner_uuid, created_at, " +
|
||||
"home_world, home_x, home_y, home_z, home_yaw, home_pitch, motd, tag_enabled, is_public) " +
|
||||
"home_world, home_x, home_y, home_z, home_yaw, home_pitch, motd, tag_enabled, is_public, " +
|
||||
"member_block_breaking, member_block_placing, member_interacting) " +
|
||||
"VALUES (:guildUuid, :name, :prefix, :ownerUuid, :createdAt, :homeWorld, :homeX, :homeY, :homeZ, " +
|
||||
":homeYaw, :homePitch, :motd, :tagEnabled, :isPublic)")
|
||||
":homeYaw, :homePitch, :motd, :tagEnabled, :isPublic, :memberBlockBreaking, :memberBlockPlacing, :memberInteracting)")
|
||||
.bind("guildUuid", e.getGuildUuid())
|
||||
.bind("name", e.getName())
|
||||
.bind("prefix", e.getPrefix())
|
||||
@@ -109,6 +111,9 @@ public class JdbiGuildRepository implements GuildRepository
|
||||
.bind("motd", e.getMotd())
|
||||
.bind("tagEnabled", e.isTagEnabled())
|
||||
.bind("isPublic", e.isPublicGuild())
|
||||
.bind("memberBlockBreaking", e.isMemberBlockBreaking())
|
||||
.bind("memberBlockPlacing", e.isMemberBlockPlacing())
|
||||
.bind("memberInteracting", e.isMemberInteracting())
|
||||
.execute();
|
||||
insertMember(h, guild.getGuildUuid(), owner.getUniqueId(), GuildRole.OWNER);
|
||||
});
|
||||
@@ -162,6 +167,21 @@ public class JdbiGuildRepository implements GuildRepository
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> updateMemberPermission(UUID guildUuid, GuildPermission permission, boolean enabled)
|
||||
{
|
||||
String column = switch (permission)
|
||||
{
|
||||
case BLOCK_BREAKING -> "member_block_breaking";
|
||||
case BLOCK_PLACING -> "member_block_placing";
|
||||
case INTERACTING -> "member_interacting";
|
||||
};
|
||||
return runAsync(() -> jdbi.useHandle(h -> h.createUpdate("UPDATE " + guildsTable + " SET " + column + " = :enabled WHERE guild_uuid = :g")
|
||||
.bind("enabled", enabled)
|
||||
.bind("g", guildUuid.toString())
|
||||
.execute()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> updatePrefix(UUID guildUuid, String prefix)
|
||||
{
|
||||
@@ -303,6 +323,9 @@ public class JdbiGuildRepository implements GuildRepository
|
||||
e.setMotd(rs.getString("motd"));
|
||||
e.setTagEnabled(rs.getBoolean("tag_enabled"));
|
||||
e.setPublicGuild(rs.getBoolean("is_public"));
|
||||
e.setMemberBlockBreaking(rs.getBoolean("member_block_breaking"));
|
||||
e.setMemberBlockPlacing(rs.getBoolean("member_block_placing"));
|
||||
e.setMemberInteracting(rs.getBoolean("member_interacting"));
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -353,6 +376,9 @@ public class JdbiGuildRepository implements GuildRepository
|
||||
guild.setMotd(entity.getMotd());
|
||||
guild.setTagEnabled(entity.isTagEnabled());
|
||||
guild.setPublic(entity.isPublicGuild());
|
||||
guild.setMemberBlockBreaking(entity.isMemberBlockBreaking());
|
||||
guild.setMemberBlockPlacing(entity.isMemberBlockPlacing());
|
||||
guild.setMemberInteracting(entity.isMemberInteracting());
|
||||
guild.setHome(toLocation(entity));
|
||||
return guild;
|
||||
}
|
||||
@@ -368,6 +394,9 @@ public class JdbiGuildRepository implements GuildRepository
|
||||
entity.setMotd(guild.getMotd());
|
||||
entity.setTagEnabled(guild.isTagEnabled());
|
||||
entity.setPublicGuild(guild.isPublic());
|
||||
entity.setMemberBlockBreaking(guild.isMemberBlockBreaking());
|
||||
entity.setMemberBlockPlacing(guild.isMemberBlockPlacing());
|
||||
entity.setMemberInteracting(guild.isMemberInteracting());
|
||||
setHome(entity, guild.getHome());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ public class GuildEntity
|
||||
private String motd;
|
||||
private boolean tagEnabled = true;
|
||||
private boolean publicGuild;
|
||||
private boolean memberBlockBreaking;
|
||||
private boolean memberBlockPlacing;
|
||||
private boolean memberInteracting;
|
||||
|
||||
public GuildEntity()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
package dev.plex.world;
|
||||
|
||||
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI;
|
||||
import com.infernalsuite.asp.api.exceptions.CorruptedWorldException;
|
||||
import com.infernalsuite.asp.api.exceptions.NewerFormatException;
|
||||
import com.infernalsuite.asp.api.exceptions.UnknownWorldException;
|
||||
import com.infernalsuite.asp.api.loaders.SlimeLoader;
|
||||
import com.infernalsuite.asp.api.world.SlimeWorld;
|
||||
import com.infernalsuite.asp.api.world.SlimeWorldInstance;
|
||||
import com.infernalsuite.asp.api.world.properties.SlimeProperties;
|
||||
import com.infernalsuite.asp.api.world.properties.SlimePropertyMap;
|
||||
import com.infernalsuite.asp.loaders.file.FileLoader;
|
||||
import dev.plex.Guilds;
|
||||
import dev.plex.guild.Guild;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class GuildWorldService
|
||||
{
|
||||
private final AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance();
|
||||
private final Map<UUID, SlimeWorldInstance> loadedWorlds = new ConcurrentHashMap<>();
|
||||
private SlimeLoader loader;
|
||||
|
||||
public void enable()
|
||||
{
|
||||
File worldDirectory = new File(Guilds.get().getDataFolder(), "slime-worlds");
|
||||
loader = new FileLoader(worldDirectory);
|
||||
}
|
||||
|
||||
public CompletableFuture<World> ensureWorld(Guild guild)
|
||||
{
|
||||
SlimeWorldInstance loadedWorld = loadedWorlds.get(guild.getGuildUuid());
|
||||
if (loadedWorld != null)
|
||||
{
|
||||
return CompletableFuture.completedFuture(loadedWorld.getBukkitWorld());
|
||||
}
|
||||
|
||||
SlimeWorldInstance aspLoadedWorld = asp.getLoadedWorld(guild.getWorldName());
|
||||
if (aspLoadedWorld != null)
|
||||
{
|
||||
loadedWorlds.put(guild.getGuildUuid(), aspLoadedWorld);
|
||||
return CompletableFuture.completedFuture(aspLoadedWorld.getBukkitWorld());
|
||||
}
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> readOrCreateWorld(guild), Guilds.get().api().scheduler().asyncExecutor())
|
||||
.thenCompose(slimeWorld -> loadWorld(guild, slimeWorld))
|
||||
.thenApply(world ->
|
||||
{
|
||||
initializeWorld(world);
|
||||
saveWorld(guild);
|
||||
return world;
|
||||
});
|
||||
}
|
||||
|
||||
public void saveWorld(Guild guild)
|
||||
{
|
||||
SlimeWorldInstance loadedWorld = loadedWorlds.get(guild.getGuildUuid());
|
||||
if (loadedWorld == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CompletableFuture.runAsync(() -> saveLoadedWorld(loadedWorld), Guilds.get().api().scheduler().asyncExecutor());
|
||||
}
|
||||
|
||||
public void ejectNonMembers(Guild guild)
|
||||
{
|
||||
SlimeWorldInstance loadedWorld = loadedWorlds.get(guild.getGuildUuid());
|
||||
if (loadedWorld == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Guilds.get().api().scheduler().executeGlobal(() ->
|
||||
{
|
||||
World fallback = Bukkit.getWorlds().getFirst();
|
||||
loadedWorld.getBukkitWorld().getPlayers().stream()
|
||||
.filter(player -> !guild.isMember(player.getUniqueId()))
|
||||
.forEach(player ->
|
||||
{
|
||||
player.teleportAsync(fallback.getSpawnLocation());
|
||||
player.sendMessage(Guilds.get().messageComponent("guildWorldNoAccess"));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void disable()
|
||||
{
|
||||
loadedWorlds.values().forEach(loadedWorld ->
|
||||
{
|
||||
saveLoadedWorld(loadedWorld);
|
||||
Bukkit.unloadWorld(loadedWorld.getBukkitWorld(), false);
|
||||
});
|
||||
loadedWorlds.clear();
|
||||
}
|
||||
|
||||
private SlimeWorld readOrCreateWorld(Guild guild)
|
||||
{
|
||||
SlimePropertyMap propertyMap = createPropertyMap();
|
||||
try
|
||||
{
|
||||
return asp.readWorld(loader, guild.getWorldName(), false, propertyMap);
|
||||
}
|
||||
catch (UnknownWorldException ignored)
|
||||
{
|
||||
return asp.createEmptyWorld(guild.getWorldName(), false, propertyMap, loader);
|
||||
}
|
||||
catch (IOException | CorruptedWorldException | NewerFormatException e)
|
||||
{
|
||||
throw new GuildWorldException("Failed to read guild world " + guild.getWorldName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<World> loadWorld(Guild guild, SlimeWorld slimeWorld)
|
||||
{
|
||||
CompletableFuture<World> future = new CompletableFuture<>();
|
||||
Guilds.get().api().scheduler().executeGlobal(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
SlimeWorldInstance loadedWorld = asp.loadWorld(slimeWorld, true);
|
||||
loadedWorlds.put(guild.getGuildUuid(), loadedWorld);
|
||||
future.complete(loadedWorld.getBukkitWorld());
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
future.completeExceptionally(throwable);
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
private void initializeWorld(World world)
|
||||
{
|
||||
int y = world.getMaxHeight() / 2;
|
||||
Location spawn = new Location(world, 0.5, y + 1, 0.5);
|
||||
world.getBlockAt(0, y, 0).setType(Material.GRASS_BLOCK, false);
|
||||
world.setSpawnLocation(spawn);
|
||||
}
|
||||
|
||||
private void saveLoadedWorld(SlimeWorldInstance loadedWorld)
|
||||
{
|
||||
try
|
||||
{
|
||||
asp.saveWorld(loadedWorld.getSerializableCopy());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new GuildWorldException("Failed to save guild world " + loadedWorld.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private SlimePropertyMap createPropertyMap()
|
||||
{
|
||||
SlimePropertyMap propertyMap = new SlimePropertyMap();
|
||||
propertyMap.setValue(SlimeProperties.DIFFICULTY, "peaceful");
|
||||
propertyMap.setValue(SlimeProperties.SPAWN_X, 0);
|
||||
propertyMap.setValue(SlimeProperties.SPAWN_Y, 65);
|
||||
propertyMap.setValue(SlimeProperties.SPAWN_Z, 0);
|
||||
propertyMap.setValue(SlimeProperties.ALLOW_ANIMALS, false);
|
||||
propertyMap.setValue(SlimeProperties.ALLOW_MONSTERS, false);
|
||||
propertyMap.setValue(SlimeProperties.DRAGON_BATTLE, false);
|
||||
propertyMap.setValue(SlimeProperties.PVP, false);
|
||||
propertyMap.setValue(SlimeProperties.ENVIRONMENT, "normal");
|
||||
propertyMap.setValue(SlimeProperties.WORLD_TYPE, "FLAT");
|
||||
propertyMap.setValue(SlimeProperties.DEFAULT_BIOME, "minecraft:plains");
|
||||
return propertyMap;
|
||||
}
|
||||
|
||||
public static class GuildWorldException extends RuntimeException
|
||||
{
|
||||
public GuildWorldException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN `member_block_breaking` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN `member_block_placing` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN `member_interacting` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN member_block_breaking BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN member_block_placing BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN member_interacting BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN member_block_breaking BOOLEAN NOT NULL DEFAULT 0;
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN member_block_placing BOOLEAN NOT NULL DEFAULT 0;
|
||||
ALTER TABLE {{table:guilds}} ADD COLUMN member_interacting BOOLEAN NOT NULL DEFAULT 0;
|
||||
@@ -37,3 +37,8 @@ guildInviteExpired: "<red>This guild invite has expired."
|
||||
guildTargetAlreadyInGuild: "<red>That player is already in a guild."
|
||||
guildCannotInviteSelf: "<red>You cannot invite yourself."
|
||||
guildStorageFailed: "<red>The guild storage operation failed."
|
||||
guildWorldLoading: "<green>Loading your guild world..."
|
||||
guildWorldLoadFailed: "<red>Your guild world could not be loaded."
|
||||
guildWorldNoAccess: "<red>You cannot access this guild world."
|
||||
guildWorldPermissionDenied: "<red>Your guild rank cannot do that here."
|
||||
guildMemberKicked: "<green>You removed <dark_green>{0}<green> from the guild."
|
||||
|
||||
Reference in New Issue
Block a user