feat: Add guild history, guild chat (#), rank management system, fire spread protection, piston fixes and broadcasts
This commit is contained in:
@@ -74,6 +74,7 @@ public final class Main extends JavaPlugin {
|
|||||||
// 8. Enregistrer les écouteurs d'événements
|
// 8. Enregistrer les écouteurs d'événements
|
||||||
PluginManager pm = getServer().getPluginManager();
|
PluginManager pm = getServer().getPluginManager();
|
||||||
pm.registerEvents(new TerritoryProtectionListener(this), this);
|
pm.registerEvents(new TerritoryProtectionListener(this), this);
|
||||||
|
pm.registerEvents(new fr.luc.gamingcore.listener.GuildChatListener(this), this);
|
||||||
|
|
||||||
getLogger().info("GamingCore (Système de Guilde - Cœur Métier & Commandes) a ete active avec succes !");
|
getLogger().info("GamingCore (Système de Guilde - Cœur Métier & Commandes) a ete active avec succes !");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class GuildCommands {
|
|||||||
private static final Pattern GUILD_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,16}$");
|
private static final Pattern GUILD_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,16}$");
|
||||||
private static final int HELP_PAGE_SIZE = 8;
|
private static final int HELP_PAGE_SIZE = 8;
|
||||||
private static final int GUILD_LIST_PAGE_SIZE = 6;
|
private static final int GUILD_LIST_PAGE_SIZE = 6;
|
||||||
|
private static final int LOGS_PAGE_SIZE = 6;
|
||||||
|
|
||||||
private final Main plugin;
|
private final Main plugin;
|
||||||
private final GuildManager guildManager;
|
private final GuildManager guildManager;
|
||||||
@@ -75,6 +76,107 @@ public class GuildCommands {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Sous-commande : /guild chat <message>
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("chat")
|
||||||
|
.description("Envoyer un message dans le chat privé de votre guilde (ou préfixez par #)")
|
||||||
|
.aliases("c", "msg")
|
||||||
|
.playerOnly()
|
||||||
|
.argument(Arguments.string("message").greedy().description("Message à envoyer"))
|
||||||
|
.validate(context -> {
|
||||||
|
if (!guildManager.isInGuild(context.getPlayer().getUniqueId())) {
|
||||||
|
return ValidationResult.invalid(msg.get("guild.not_in_guild"));
|
||||||
|
}
|
||||||
|
return ValidationResult.valid();
|
||||||
|
})
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
String chatMsg = context.getString("message");
|
||||||
|
|
||||||
|
GuildMember member = guild.getMember(player.getUniqueId());
|
||||||
|
GuildRank rank = member != null ? guild.getRank(member.getRankId()) : null;
|
||||||
|
String rankName = rank != null ? rank.getName() : "Membre";
|
||||||
|
|
||||||
|
String formatted = msg.get("guild.chat.format",
|
||||||
|
"{guild}", guild.getFormattedName(),
|
||||||
|
"{tag}", guild.getFormattedTag(),
|
||||||
|
"{color}", guild.getColor(),
|
||||||
|
"{rank}", rankName,
|
||||||
|
"{player}", player.getName(),
|
||||||
|
"{message}", chatMsg
|
||||||
|
);
|
||||||
|
|
||||||
|
for (GuildMember m : guild.getMembers()) {
|
||||||
|
if (m.getOfflinePlayer() != null && m.getOfflinePlayer().isOnline()) {
|
||||||
|
Player onlinePlayer = m.getOfflinePlayer().getPlayer();
|
||||||
|
if (onlinePlayer != null) {
|
||||||
|
TextUtil.sendMessage(onlinePlayer, formatted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Sous-commande : /guild history [page]
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("history")
|
||||||
|
.description("Consulter l'historique des actions et transactions de votre guilde")
|
||||||
|
.aliases("logs", "journal", "historique")
|
||||||
|
.playerOnly()
|
||||||
|
.argument(Arguments.integer("page", 1, 100).optional().description("Numéro de page"))
|
||||||
|
.validate(context -> {
|
||||||
|
if (!guildManager.isInGuild(context.getPlayer().getUniqueId())) {
|
||||||
|
return ValidationResult.invalid(msg.get("guild.not_in_guild"));
|
||||||
|
}
|
||||||
|
return ValidationResult.valid();
|
||||||
|
})
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
int page = context.getOptional("page", Integer.class).orElse(1);
|
||||||
|
|
||||||
|
plugin.getGuildRepository().getLogsAsync(guild.getId(), 100, logs -> {
|
||||||
|
if (logs.isEmpty()) {
|
||||||
|
context.reply(msg.get("guild.history.empty"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalLogs = logs.size();
|
||||||
|
int maxPage = (int) Math.ceil((double) totalLogs / LOGS_PAGE_SIZE);
|
||||||
|
int finalPage = Math.min(Math.max(1, page), maxPage);
|
||||||
|
|
||||||
|
context.reply(msg.get("guild.history.header",
|
||||||
|
"{page}", String.valueOf(finalPage),
|
||||||
|
"{max_page}", String.valueOf(maxPage)
|
||||||
|
));
|
||||||
|
|
||||||
|
int startIndex = (finalPage - 1) * LOGS_PAGE_SIZE;
|
||||||
|
int endIndex = Math.min(startIndex + LOGS_PAGE_SIZE, totalLogs);
|
||||||
|
|
||||||
|
for (int i = startIndex; i < endIndex; i++) {
|
||||||
|
GuildLog log = logs.get(i);
|
||||||
|
context.reply(msg.get("guild.history.item",
|
||||||
|
"{date}", log.getFormattedDate(),
|
||||||
|
"{actor}", log.getActorName(),
|
||||||
|
"{details}", log.getDetails()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
int prevPage = Math.max(1, finalPage - 1);
|
||||||
|
int nextPage = Math.min(maxPage, finalPage + 1);
|
||||||
|
|
||||||
|
String pagination = msg.get("guild.history.pagination",
|
||||||
|
"{prev_page}", String.valueOf(prevPage),
|
||||||
|
"{next_page}", String.valueOf(nextPage)
|
||||||
|
);
|
||||||
|
context.reply(pagination);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// Sous-commande : /guild list [page]
|
// Sous-commande : /guild list [page]
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
@@ -91,7 +193,6 @@ public class GuildCommands {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trier par nombre de membres décroissant
|
|
||||||
allGuilds.sort((g1, g2) -> Integer.compare(g2.getMemberCount(), g1.getMemberCount()));
|
allGuilds.sort((g1, g2) -> Integer.compare(g2.getMemberCount(), g1.getMemberCount()));
|
||||||
|
|
||||||
int totalGuilds = allGuilds.size();
|
int totalGuilds = allGuilds.size();
|
||||||
@@ -323,7 +424,10 @@ public class GuildCommands {
|
|||||||
inviteManager.removeInvite(player, targetGuild.getId());
|
inviteManager.removeInvite(player, targetGuild.getId());
|
||||||
GuildResult result = guildManager.addMember(targetGuild, player);
|
GuildResult result = guildManager.addMember(targetGuild, player);
|
||||||
if (result.isSuccess()) {
|
if (result.isSuccess()) {
|
||||||
context.reply(msg.get("guild.invite.accepted", "{player}", player.getName()));
|
context.reply(msg.get("guild.invite.accepted_self",
|
||||||
|
"{guild}", targetGuild.getFormattedName(),
|
||||||
|
"{tag}", targetGuild.getFormattedTag()
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
context.replyError(result.getMessage());
|
context.replyError(result.getMessage());
|
||||||
}
|
}
|
||||||
@@ -357,7 +461,6 @@ public class GuildCommands {
|
|||||||
inviteManager.removeInvite(player, targetGuild.getId());
|
inviteManager.removeInvite(player, targetGuild.getId());
|
||||||
context.reply(msg.get("guild.invite.declined_target", "{guild}", targetGuild.getFormattedName()));
|
context.reply(msg.get("guild.invite.declined_target", "{guild}", targetGuild.getFormattedName()));
|
||||||
|
|
||||||
// Notifier l'émetteur si en ligne
|
|
||||||
GuildMember leader = targetGuild.getLeaderMember();
|
GuildMember leader = targetGuild.getLeaderMember();
|
||||||
if (leader != null && leader.getOfflinePlayer() != null && leader.getOfflinePlayer().isOnline()) {
|
if (leader != null && leader.getOfflinePlayer() != null && leader.getOfflinePlayer().isOnline()) {
|
||||||
Player leaderPlayer = leader.getOfflinePlayer().getPlayer();
|
Player leaderPlayer = leader.getOfflinePlayer().getPlayer();
|
||||||
@@ -500,7 +603,7 @@ public class GuildCommands {
|
|||||||
// Sous-commande : /guild unclaim
|
// Sous-commande : /guild unclaim
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
.subcommand(BetterMcCommands.subBuilder("unclaim")
|
.subcommand(BetterMcCommands.subBuilder("unclaim")
|
||||||
.description("Libérer le chunk actuel")
|
.description("Libérer le chunk actuel possédé par la guilde")
|
||||||
.playerOnly()
|
.playerOnly()
|
||||||
.validate(context -> {
|
.validate(context -> {
|
||||||
if (!guildManager.isInGuild(context.getPlayer().getUniqueId())) {
|
if (!guildManager.isInGuild(context.getPlayer().getUniqueId())) {
|
||||||
@@ -519,6 +622,7 @@ public class GuildCommands {
|
|||||||
}
|
}
|
||||||
return ValidationResult.valid();
|
return ValidationResult.valid();
|
||||||
})
|
})
|
||||||
|
.requireConfirmation(Duration.ofSeconds(15))
|
||||||
.executes(context -> {
|
.executes(context -> {
|
||||||
Player player = context.getPlayer();
|
Player player = context.getPlayer();
|
||||||
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
@@ -831,6 +935,130 @@ public class GuildCommands {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Sous-commande : /guild ranks (ou /guild rank)
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("ranks")
|
||||||
|
.description("Afficher les rangs et permissions de votre guilde")
|
||||||
|
.aliases("rank", "rangs", "rang")
|
||||||
|
.playerOnly()
|
||||||
|
.validate(context -> {
|
||||||
|
if (!guildManager.isInGuild(context.getPlayer().getUniqueId())) {
|
||||||
|
return ValidationResult.invalid(msg.get("guild.not_in_guild"));
|
||||||
|
}
|
||||||
|
return ValidationResult.valid();
|
||||||
|
})
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
|
||||||
|
context.reply(msg.get("guild.ranks.header"));
|
||||||
|
for (GuildRank r : guild.getRanks()) {
|
||||||
|
String perms = r.getPermissions().stream().map(Enum::name).collect(Collectors.joining(", "));
|
||||||
|
if (perms.isEmpty()) perms = "Aucune";
|
||||||
|
context.reply(msg.get("guild.ranks.item",
|
||||||
|
"{name}", r.getName(),
|
||||||
|
"{id}", r.getId(),
|
||||||
|
"{priority}", String.valueOf(r.getPriority()),
|
||||||
|
"{permissions}", perms
|
||||||
|
));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// /guild rank create <id> <nom> <priorite>
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("create")
|
||||||
|
.description("Créer un nouveau rang de guilde")
|
||||||
|
.playerOnly()
|
||||||
|
.argument(Arguments.string("id").description("ID unique du rang"))
|
||||||
|
.argument(Arguments.string("nom").description("Nom affiché"))
|
||||||
|
.argument(Arguments.integer("priorite", 1, 99).description("Priorité (1-99)"))
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
String id = context.getString("id");
|
||||||
|
String name = context.getString("nom");
|
||||||
|
int priority = context.getInt("priorite");
|
||||||
|
|
||||||
|
GuildResult res = guildManager.createRank(player, guild, id, name, priority);
|
||||||
|
if (res.isSuccess()) {
|
||||||
|
context.replySuccess(res.getMessage());
|
||||||
|
} else {
|
||||||
|
context.replyError(res.getMessage());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
// /guild rank delete <id>
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("delete")
|
||||||
|
.description("Supprimer un rang de guilde")
|
||||||
|
.aliases("supprimer", "remove")
|
||||||
|
.playerOnly()
|
||||||
|
.argument(Arguments.string("id").description("ID du rang"))
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
String id = context.getString("id");
|
||||||
|
|
||||||
|
GuildResult res = guildManager.deleteRank(player, guild, id);
|
||||||
|
if (res.isSuccess()) {
|
||||||
|
context.replySuccess(res.getMessage());
|
||||||
|
} else {
|
||||||
|
context.replyError(res.getMessage());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
// /guild rank setperm <id> <permission> <true/false>
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("setperm")
|
||||||
|
.description("Modifier une permission pour un rang")
|
||||||
|
.playerOnly()
|
||||||
|
.argument(Arguments.string("id").description("ID du rang"))
|
||||||
|
.argument(Arguments.enumOf("permission", GuildPermission.class).description("Permission"))
|
||||||
|
.argument(Arguments.bool("valeur").description("true ou false"))
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
String id = context.getString("id");
|
||||||
|
GuildPermission perm = context.get("permission", GuildPermission.class);
|
||||||
|
boolean state = context.getBoolean("valeur");
|
||||||
|
|
||||||
|
GuildResult res = guildManager.setRankPermission(player, guild, id, perm, state);
|
||||||
|
if (res.isSuccess()) {
|
||||||
|
context.replySuccess(res.getMessage());
|
||||||
|
} else {
|
||||||
|
context.replyError(res.getMessage());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Sous-commande : /guild setrank <joueur> <rang>
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
.subcommand(BetterMcCommands.subBuilder("setrank")
|
||||||
|
.description("Modifier le rang d'un membre de la guilde")
|
||||||
|
.aliases("promote", "demote")
|
||||||
|
.playerOnly()
|
||||||
|
.argument(Arguments.player("joueur").description("Membre cible"))
|
||||||
|
.argument(Arguments.string("rang").description("ID du rang cible"))
|
||||||
|
.validate(context -> {
|
||||||
|
if (!guildManager.isInGuild(context.getPlayer().getUniqueId())) {
|
||||||
|
return ValidationResult.invalid(msg.get("guild.not_in_guild"));
|
||||||
|
}
|
||||||
|
return ValidationResult.valid();
|
||||||
|
})
|
||||||
|
.executes(context -> {
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(player.getUniqueId());
|
||||||
|
Player target = context.getTargetPlayer("joueur");
|
||||||
|
String rankId = context.getString("rang");
|
||||||
|
|
||||||
|
GuildResult res = guildManager.setMemberRank(player, guild, target.getUniqueId(), rankId);
|
||||||
|
if (res.isSuccess()) {
|
||||||
|
context.replySuccess(res.getMessage());
|
||||||
|
} else {
|
||||||
|
context.replyError(res.getMessage());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// Sous-commande : /guild reload
|
// Sous-commande : /guild reload
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
@@ -853,6 +1081,10 @@ public class GuildCommands {
|
|||||||
List<HelpEntry> entries = new ArrayList<>();
|
List<HelpEntry> entries = new ArrayList<>();
|
||||||
entries.add(new HelpEntry("/guild create <nom> [tag]", "Fonder une nouvelle guilde et revendiquer le 1er chunk", "/guild create "));
|
entries.add(new HelpEntry("/guild create <nom> [tag]", "Fonder une nouvelle guilde et revendiquer le 1er chunk", "/guild create "));
|
||||||
entries.add(new HelpEntry("/guild list [page]", "Afficher la liste des guildes du serveur", "/guild list "));
|
entries.add(new HelpEntry("/guild list [page]", "Afficher la liste des guildes du serveur", "/guild list "));
|
||||||
|
entries.add(new HelpEntry("/guild chat <message>", "Envoyer un message dans le canal privé de guilde (ou #message)", "/guild chat "));
|
||||||
|
entries.add(new HelpEntry("/guild history [page]", "Consulter le journal des actions et transactions de la guilde", "/guild history "));
|
||||||
|
entries.add(new HelpEntry("/guild ranks", "Afficher et gérer les rangs et permissions de la guilde", "/guild ranks"));
|
||||||
|
entries.add(new HelpEntry("/guild setrank <joueur> <rang>", "Modifier le rang d'un membre de la guilde", "/guild setrank "));
|
||||||
entries.add(new HelpEntry("/guild info [guilde]", "Afficher les statistiques détaillées d'une guilde", "/guild info "));
|
entries.add(new HelpEntry("/guild info [guilde]", "Afficher les statistiques détaillées d'une guilde", "/guild info "));
|
||||||
entries.add(new HelpEntry("/guild members [guilde]", "Afficher la liste des membres classés par rang", "/guild members "));
|
entries.add(new HelpEntry("/guild members [guilde]", "Afficher la liste des membres classés par rang", "/guild members "));
|
||||||
entries.add(new HelpEntry("/guild color <#hex>", "Modifier la couleur hexadécimale de la guilde", "/guild color "));
|
entries.add(new HelpEntry("/guild color <#hex>", "Modifier la couleur hexadécimale de la guilde", "/guild color "));
|
||||||
|
|||||||
@@ -140,6 +140,18 @@ public class DatabaseManager {
|
|||||||
"claimed_at BIGINT NOT NULL, " +
|
"claimed_at BIGINT NOT NULL, " +
|
||||||
"FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
|
"FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
|
||||||
");");
|
");");
|
||||||
|
|
||||||
|
// Table de l'historique d'actions (logs)
|
||||||
|
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS guild_logs (" +
|
||||||
|
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||||
|
"guild_id VARCHAR(36) NOT NULL, " +
|
||||||
|
"actor_uuid VARCHAR(36), " +
|
||||||
|
"actor_name VARCHAR(32) NOT NULL, " +
|
||||||
|
"action_type VARCHAR(32) NOT NULL, " +
|
||||||
|
"details TEXT NOT NULL, " +
|
||||||
|
"timestamp BIGINT NOT NULL, " +
|
||||||
|
"FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
|
||||||
|
");");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -337,4 +337,60 @@ public class GuildRepository {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sauvegarde une entrée d'historique de guilde de façon asynchrone.
|
||||||
|
*
|
||||||
|
* @param log L'entrée de log à sauvegarder.
|
||||||
|
*/
|
||||||
|
public void saveLogAsync(fr.luc.gamingcore.model.GuildLog log) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
String sql = "INSERT INTO guild_logs (guild_id, actor_uuid, actor_name, action_type, details, timestamp) VALUES (?, ?, ?, ?, ?, ?)";
|
||||||
|
try (PreparedStatement ps = databaseManager.getConnection().prepareStatement(sql)) {
|
||||||
|
ps.setString(1, log.getGuildId().toString());
|
||||||
|
ps.setString(2, log.getActorUuid() != null ? log.getActorUuid().toString() : null);
|
||||||
|
ps.setString(3, log.getActorName());
|
||||||
|
ps.setString(4, log.getActionType());
|
||||||
|
ps.setString(5, log.getDetails());
|
||||||
|
ps.setLong(6, log.getTimestamp());
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Erreur lors de la sauvegarde du log de guilde", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère de façon asynchrone les dernières entrées de log d'une guilde.
|
||||||
|
*
|
||||||
|
* @param guildId L'UUID de la guilde.
|
||||||
|
* @param limit Nombre maximum d'entrées à récupérer.
|
||||||
|
* @param callback Callback recevant la liste des logs ordonnée du plus récent au plus ancien.
|
||||||
|
*/
|
||||||
|
public void getLogsAsync(UUID guildId, int limit, java.util.function.Consumer<java.util.List<fr.luc.gamingcore.model.GuildLog>> callback) {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
java.util.List<fr.luc.gamingcore.model.GuildLog> list = new java.util.ArrayList<>();
|
||||||
|
String sql = "SELECT id, guild_id, actor_uuid, actor_name, action_type, details, timestamp FROM guild_logs WHERE guild_id = ? ORDER BY timestamp DESC LIMIT ?";
|
||||||
|
try (PreparedStatement ps = databaseManager.getConnection().prepareStatement(sql)) {
|
||||||
|
ps.setString(1, guildId.toString());
|
||||||
|
ps.setInt(2, limit);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
long id = rs.getLong("id");
|
||||||
|
String actorUuidStr = rs.getString("actor_uuid");
|
||||||
|
UUID actorUuid = actorUuidStr != null ? UUID.fromString(actorUuidStr) : null;
|
||||||
|
String actorName = rs.getString("actor_name");
|
||||||
|
String actionType = rs.getString("action_type");
|
||||||
|
String details = rs.getString("details");
|
||||||
|
long timestamp = rs.getLong("timestamp");
|
||||||
|
|
||||||
|
list.add(new fr.luc.gamingcore.model.GuildLog(id, guildId, actorUuid, actorName, actionType, details, timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Erreur lors du chargement des logs de la guilde " + guildId, e);
|
||||||
|
}
|
||||||
|
Bukkit.getScheduler().runTask(plugin, () -> callback.accept(list));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package fr.luc.gamingcore.listener;
|
||||||
|
|
||||||
|
import fr.luc.gamingcore.Main;
|
||||||
|
import fr.luc.gamingcore.manager.GuildManager;
|
||||||
|
import fr.luc.gamingcore.model.Guild;
|
||||||
|
import fr.luc.gamingcore.model.GuildMember;
|
||||||
|
import fr.luc.gamingcore.model.GuildRank;
|
||||||
|
import fr.luc.gamingcore.util.MessageManager;
|
||||||
|
import fr.luc.gamingcore.util.TextUtil;
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Écouteur gérant le chat privé de guilde.
|
||||||
|
* Permet aux joueurs d'écrire dans le chat de guilde en préfixant leur message par '#' (ex: # Salut la guilde !).
|
||||||
|
*/
|
||||||
|
public class GuildChatListener implements Listener {
|
||||||
|
|
||||||
|
private final Main plugin;
|
||||||
|
private final GuildManager guildManager;
|
||||||
|
private final MessageManager messageManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur de l'écouteur de chat de guilde.
|
||||||
|
*
|
||||||
|
* @param plugin Instance principale du plugin.
|
||||||
|
*/
|
||||||
|
public GuildChatListener(Main plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.guildManager = plugin.getGuildManager();
|
||||||
|
this.messageManager = plugin.getMessageManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercepte les messages de chat commençant par '#' pour les rediriger exclusivement vers la guilde du joueur.
|
||||||
|
*
|
||||||
|
* @param event L'événement AsyncChatEvent de Paper.
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
|
public void onAsyncChat(AsyncChatEvent event) {
|
||||||
|
String rawText = PlainTextComponentSerializer.plainText().serialize(event.message()).trim();
|
||||||
|
if (!rawText.startsWith("#")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
Player sender = event.getPlayer();
|
||||||
|
|
||||||
|
Guild guild = guildManager.getGuildByPlayer(sender.getUniqueId());
|
||||||
|
if (guild == null) {
|
||||||
|
messageManager.send(sender, "guild.not_in_guild");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String guildMsg = rawText.substring(1).trim();
|
||||||
|
if (guildMsg.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendGuildChatMessage(guild, sender, guildMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diffuse un message formaté dans le canal privé de la guilde à tous les membres connectés.
|
||||||
|
*
|
||||||
|
* @param guild La guilde émettrice.
|
||||||
|
* @param sender Le joueur ayant envoyé le message.
|
||||||
|
* @param message Le texte du message.
|
||||||
|
*/
|
||||||
|
public void sendGuildChatMessage(Guild guild, Player sender, String message) {
|
||||||
|
GuildMember member = guild.getMember(sender.getUniqueId());
|
||||||
|
GuildRank rank = member != null ? guild.getRank(member.getRankId()) : null;
|
||||||
|
String rankName = rank != null ? rank.getName() : "Membre";
|
||||||
|
|
||||||
|
String formatted = messageManager.get("guild.chat.format",
|
||||||
|
"{guild}", guild.getFormattedName(),
|
||||||
|
"{tag}", guild.getFormattedTag(),
|
||||||
|
"{color}", guild.getColor(),
|
||||||
|
"{rank}", rankName,
|
||||||
|
"{player}", sender.getName(),
|
||||||
|
"{message}", message
|
||||||
|
);
|
||||||
|
|
||||||
|
for (GuildMember m : guild.getMembers()) {
|
||||||
|
if (m.getOfflinePlayer() != null && m.getOfflinePlayer().isOnline()) {
|
||||||
|
Player onlinePlayer = m.getOfflinePlayer().getPlayer();
|
||||||
|
if (onlinePlayer != null) {
|
||||||
|
TextUtil.sendMessage(onlinePlayer, formatted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Écouteur d'événements garantissant la protection territoriale complète des chunks de guilde :
|
* Écouteur d'événements garantissant la protection territoriale complète des chunks de guilde :
|
||||||
* anti-grief, anti-pvp, anti-pistons transfrontaliers, anti-fluides et protection des entités/conteneurs.
|
* anti-grief, anti-pvp, anti-pistons transfrontaliers, anti-fluides, anti-feu et protection des entités/conteneurs.
|
||||||
*/
|
*/
|
||||||
public class TerritoryProtectionListener implements Listener {
|
public class TerritoryProtectionListener implements Listener {
|
||||||
|
|
||||||
@@ -257,6 +257,7 @@ public class TerritoryProtectionListener implements Listener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Empêche les pistons de pousser des blocs à travers les frontières d'un claim étranger.
|
* Empêche les pistons de pousser des blocs à travers les frontières d'un claim étranger.
|
||||||
|
* Les pistons fonctionnant au sein d'une même guilde ou en territoire libre sont totalement autorisés.
|
||||||
*
|
*
|
||||||
* @param event L'événement BlockPistonExtendEvent.
|
* @param event L'événement BlockPistonExtendEvent.
|
||||||
*/
|
*/
|
||||||
@@ -266,16 +267,40 @@ public class TerritoryProtectionListener implements Listener {
|
|||||||
String worldName = piston.getWorld().getName();
|
String worldName = piston.getWorld().getName();
|
||||||
Guild guildPiston = guildManager.getGuildAt(worldName, piston.getX() >> 4, piston.getZ() >> 4);
|
Guild guildPiston = guildManager.getGuildAt(worldName, piston.getX() >> 4, piston.getZ() >> 4);
|
||||||
|
|
||||||
|
if (event.getBlocks().isEmpty()) {
|
||||||
|
// Piston qui pousse de l'air
|
||||||
|
Block targetAir = piston.getRelative(event.getDirection());
|
||||||
|
Guild guildTarget = guildManager.getGuildAt(worldName, targetAir.getX() >> 4, targetAir.getZ() >> 4);
|
||||||
|
if (guildPiston == null && guildTarget != null) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
} else if (guildPiston != null && guildTarget != null && !guildPiston.getId().equals(guildTarget.getId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Block block : event.getBlocks()) {
|
for (Block block : event.getBlocks()) {
|
||||||
Block targetBlock = block.getRelative(event.getDirection());
|
Block targetBlock = block.getRelative(event.getDirection());
|
||||||
Guild guildBlock = guildManager.getGuildAt(worldName, block.getX() >> 4, block.getZ() >> 4);
|
Guild guildBlock = guildManager.getGuildAt(worldName, block.getX() >> 4, block.getZ() >> 4);
|
||||||
Guild guildTarget = guildManager.getGuildAt(worldName, targetBlock.getX() >> 4, targetBlock.getZ() >> 4);
|
Guild guildTarget = guildManager.getGuildAt(worldName, targetBlock.getX() >> 4, targetBlock.getZ() >> 4);
|
||||||
|
|
||||||
// Si le piston ou les blocs déplacés traversent une frontière de guilde différente
|
if (guildPiston != null) {
|
||||||
if (!Objects.equals(guildPiston, guildBlock) || !Objects.equals(guildPiston, guildTarget)) {
|
// Piston appartenant à une guilde
|
||||||
|
if (guildBlock != null && !guildBlock.getId().equals(guildPiston.getId())) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (guildTarget != null && !guildTarget.getId().equals(guildPiston.getId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Piston en zone libre (wilderness) : ne doit toucher à aucun territoire revendiqué
|
||||||
|
if (guildBlock != null || guildTarget != null) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,10 +317,17 @@ public class TerritoryProtectionListener implements Listener {
|
|||||||
|
|
||||||
for (Block block : event.getBlocks()) {
|
for (Block block : event.getBlocks()) {
|
||||||
Guild guildBlock = guildManager.getGuildAt(worldName, block.getX() >> 4, block.getZ() >> 4);
|
Guild guildBlock = guildManager.getGuildAt(worldName, block.getX() >> 4, block.getZ() >> 4);
|
||||||
if (!Objects.equals(guildPiston, guildBlock)) {
|
if (guildPiston != null) {
|
||||||
|
if (guildBlock != null && !guildBlock.getId().equals(guildPiston.getId())) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (guildBlock != null) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +354,58 @@ public class TerritoryProtectionListener implements Listener {
|
|||||||
Guild guildFrom = guildManager.getGuildAt(worldName, fromChunkX, fromChunkZ);
|
Guild guildFrom = guildManager.getGuildAt(worldName, fromChunkX, fromChunkZ);
|
||||||
Guild guildTo = guildManager.getGuildAt(worldName, toChunkX, toChunkZ);
|
Guild guildTo = guildManager.getGuildAt(worldName, toChunkX, toChunkZ);
|
||||||
|
|
||||||
if (guildTo != null && !Objects.equals(guildFrom, guildTo)) {
|
if (guildTo != null) {
|
||||||
|
if (guildFrom == null || !guildFrom.getId().equals(guildTo.getId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empêche la destruction par combustion des blocs sur les territoires revendiqués.
|
||||||
|
*
|
||||||
|
* @param event L'événement BlockBurnEvent.
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||||
|
public void onBlockBurn(BlockBurnEvent event) {
|
||||||
|
Block block = event.getBlock();
|
||||||
|
if (guildManager.isChunkClaimed(block.getWorld().getName(), block.getX() >> 4, block.getZ() >> 4)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empêche la propagation du feu sur les territoires revendiqués.
|
||||||
|
*
|
||||||
|
* @param event L'événement BlockSpreadEvent.
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||||
|
public void onBlockSpread(BlockSpreadEvent event) {
|
||||||
|
Material source = event.getSource().getType();
|
||||||
|
Material newState = event.getNewState().getType();
|
||||||
|
|
||||||
|
if (source == Material.FIRE || source == Material.SOUL_FIRE || newState == Material.FIRE || newState == Material.SOUL_FIRE) {
|
||||||
|
Block block = event.getBlock();
|
||||||
|
if (guildManager.isChunkClaimed(block.getWorld().getName(), block.getX() >> 4, block.getZ() >> 4)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empêche l'allumage non autorisé par lave ou propagation de feu sur les claims.
|
||||||
|
*
|
||||||
|
* @param event L'événement BlockIgniteEvent.
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||||
|
public void onBlockIgnite(BlockIgniteEvent event) {
|
||||||
|
Block block = event.getBlock();
|
||||||
|
if (!guildManager.isChunkClaimed(block.getWorld().getName(), block.getX() >> 4, block.getZ() >> 4)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockIgniteEvent.IgniteCause cause = event.getCause();
|
||||||
|
if (cause == BlockIgniteEvent.IgniteCause.SPREAD || cause == BlockIgniteEvent.IgniteCause.LAVA || cause == BlockIgniteEvent.IgniteCause.FIREBALL) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import fr.luc.gamingcore.database.GuildRepository;
|
|||||||
import fr.luc.gamingcore.economy.ChunkPriceCalculator;
|
import fr.luc.gamingcore.economy.ChunkPriceCalculator;
|
||||||
import fr.luc.gamingcore.economy.EconomyManager;
|
import fr.luc.gamingcore.economy.EconomyManager;
|
||||||
import fr.luc.gamingcore.model.*;
|
import fr.luc.gamingcore.model.*;
|
||||||
|
import fr.luc.gamingcore.util.MessageManager;
|
||||||
|
import fr.luc.gamingcore.util.TextUtil;
|
||||||
|
import fr.luc.gamingcore.worldguard.WorldGuardManager;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@@ -12,58 +15,48 @@ import org.bukkit.entity.Player;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.regex.Pattern;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service central orchestrant l'intégralité de la logique métier du système de guilde.
|
* Service métier central et autonome pour la gestion des guildes, de leurs territoires,
|
||||||
|
* de leurs finances, de leurs rangs et de leur cycle de vie complet.
|
||||||
*/
|
*/
|
||||||
public class GuildManager {
|
public class GuildManager {
|
||||||
|
|
||||||
private static final Pattern GUILD_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,16}$");
|
|
||||||
|
|
||||||
private final Main plugin;
|
private final Main plugin;
|
||||||
private final GuildRepository repository;
|
private final GuildRepository repository;
|
||||||
private final EconomyManager economyManager;
|
private final EconomyManager economyManager;
|
||||||
private final fr.luc.gamingcore.worldguard.WorldGuardManager worldGuardManager;
|
private final WorldGuardManager worldGuardManager;
|
||||||
private final ChunkPriceCalculator priceCalculator;
|
private final ChunkPriceCalculator priceCalculator;
|
||||||
private final InviteManager inviteManager;
|
private final InviteManager inviteManager;
|
||||||
|
private final MessageManager messageManager;
|
||||||
|
|
||||||
// Caches d'accès rapide
|
// Indexations en mémoire pour des lookups O(1)
|
||||||
private final Map<UUID, Guild> guildsById = new ConcurrentHashMap<>();
|
private final Map<UUID, Guild> guildsById = new ConcurrentHashMap<>();
|
||||||
private final Map<String, UUID> guildsByName = new ConcurrentHashMap<>();
|
private final Map<String, UUID> guildsByName = new ConcurrentHashMap<>();
|
||||||
private final Map<UUID, UUID> playerGuildMap = new ConcurrentHashMap<>();
|
private final Map<UUID, UUID> playerGuildMap = new ConcurrentHashMap<>();
|
||||||
private final Map<String, UUID> chunkGuildMap = new ConcurrentHashMap<>();
|
private final Map<String, UUID> chunkGuildMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructeur complet du GuildManager avec WorldGuardManager.
|
* Constructeur complet du gestionnaire de guilde avec WorldGuard.
|
||||||
*
|
*
|
||||||
* @param plugin Instance du plugin principal.
|
* @param plugin Instance principale du plugin.
|
||||||
* @param repository Référentiel de persistance des données.
|
* @param repository Couche d'accès aux données.
|
||||||
* @param economyManager Gestionnaire de l'économie Vault.
|
* @param economyManager Gestionnaire d'économie Vault.
|
||||||
* @param worldGuardManager Gestionnaire des régions WorldGuard.
|
* @param worldGuardManager Gestionnaire WorldGuard.
|
||||||
*/
|
*/
|
||||||
public GuildManager(Main plugin, GuildRepository repository, EconomyManager economyManager, fr.luc.gamingcore.worldguard.WorldGuardManager worldGuardManager) {
|
public GuildManager(Main plugin, GuildRepository repository, EconomyManager economyManager, WorldGuardManager worldGuardManager) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.economyManager = economyManager;
|
this.economyManager = economyManager;
|
||||||
this.worldGuardManager = worldGuardManager;
|
this.worldGuardManager = worldGuardManager;
|
||||||
this.priceCalculator = new ChunkPriceCalculator();
|
this.priceCalculator = new ChunkPriceCalculator();
|
||||||
this.inviteManager = new InviteManager();
|
this.inviteManager = new InviteManager();
|
||||||
|
this.messageManager = plugin.getMessageManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructeur de compatibilité du GuildManager.
|
* Charge toutes les données depuis la base de données SQLite en mémoire.
|
||||||
*
|
|
||||||
* @param plugin Instance du plugin principal.
|
|
||||||
* @param repository Référentiel de persistance des données.
|
|
||||||
* @param economyManager Gestionnaire de l'économie Vault.
|
|
||||||
*/
|
|
||||||
public GuildManager(Main plugin, GuildRepository repository, EconomyManager economyManager) {
|
|
||||||
this(plugin, repository, economyManager, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Charge l'ensemble des données de la base en mémoire et reconstruit les index de recherche et régions WorldGuard.
|
|
||||||
*/
|
*/
|
||||||
public void loadData() {
|
public void loadData() {
|
||||||
guildsById.clear();
|
guildsById.clear();
|
||||||
@@ -71,157 +64,169 @@ public class GuildManager {
|
|||||||
playerGuildMap.clear();
|
playerGuildMap.clear();
|
||||||
chunkGuildMap.clear();
|
chunkGuildMap.clear();
|
||||||
|
|
||||||
Map<UUID, Guild> loaded = repository.loadAllGuilds();
|
Collection<Guild> loadedGuilds = repository.loadAllGuilds().values();
|
||||||
for (Guild guild : loaded.values()) {
|
int totalMembers = 0;
|
||||||
|
int totalClaims = 0;
|
||||||
|
|
||||||
|
for (Guild guild : loadedGuilds) {
|
||||||
indexGuild(guild);
|
indexGuild(guild);
|
||||||
|
totalMembers += guild.getMemberCount();
|
||||||
|
totalClaims += guild.getClaimCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worldGuardManager != null) {
|
plugin.getLogger().info("Charges " + loadedGuilds.size() + " guildes (" + totalMembers + " membres, " + totalClaims + " claims).");
|
||||||
worldGuardManager.syncAllGuilds(guildsById.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.getLogger().info("Charges " + guildsById.size() + " guildes (" + playerGuildMap.size() + " membres, " + chunkGuildMap.size() + " claims).");
|
// Synchronisation WorldGuard globale
|
||||||
|
if (worldGuardManager != null && worldGuardManager.isEnabled()) {
|
||||||
|
worldGuardManager.syncAllGuilds(new ArrayList<>(loadedGuilds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arrête proprement le gestionnaire et libère les ressources.
|
* Arrêt propre du service métier.
|
||||||
*/
|
*/
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
guildsById.clear();
|
guildsById.clear();
|
||||||
guildsByName.clear();
|
guildsByName.clear();
|
||||||
playerGuildMap.clear();
|
playerGuildMap.clear();
|
||||||
chunkGuildMap.clear();
|
chunkGuildMap.clear();
|
||||||
inviteManager.cleanExpired();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// MÉTHODES DE CRÉATION & DISSOLUTION
|
// NOTIFICATIONS & LOGS DE GUILDE
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée une nouvelle guilde pour un joueur avec prélèvement financier et claim obligatoire du premier chunk.
|
* Diffuse un message à tous les membres connectés d'une guilde.
|
||||||
*
|
*
|
||||||
* @param creator Le joueur fondateur.
|
* @param guild La guilde cible.
|
||||||
* @param name Nom de la guilde (3 à 16 caractères alphanumériques).
|
* @param messageKey La clé du message dans messages.yml.
|
||||||
* @param tag Tag court optionnel (ex: "LEG").
|
* @param placeholders Paires clé/valeur pour le remplacement.
|
||||||
* @param creationCost Coût financier requis pour la création.
|
|
||||||
* @return GuildResult indiquant le succès ou la raison de l'échec.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult createGuild(Player creator, String name, String tag, double creationCost) {
|
public void broadcastToGuild(Guild guild, String messageKey, String... placeholders) {
|
||||||
return createGuild(creator, name, tag, "#00C9FF", creationCost);
|
if (guild == null) return;
|
||||||
|
String formatted = messageManager.get(messageKey, placeholders);
|
||||||
|
for (GuildMember member : guild.getMembers()) {
|
||||||
|
if (member.getOfflinePlayer() != null && member.getOfflinePlayer().isOnline()) {
|
||||||
|
Player onlinePlayer = member.getOfflinePlayer().getPlayer();
|
||||||
|
if (onlinePlayer != null) {
|
||||||
|
TextUtil.sendMessage(onlinePlayer, formatted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée une nouvelle guilde pour un joueur avec prélèvement financier, couleur personnalisée et claim initial.
|
* Enregistre un événement dans l'historique de la guilde.
|
||||||
*
|
*
|
||||||
* @param creator Le joueur fondateur.
|
* @param guild La guilde concernée.
|
||||||
* @param name Nom de la guilde (3 à 16 caractères alphanumériques).
|
* @param actor Le joueur initiateur (peut être null).
|
||||||
* @param tag Tag court optionnel (ex: "LEG").
|
* @param actionType Le type d'action.
|
||||||
* @param color Couleur hexadécimale (ex: "#00C9FF").
|
* @param details Description textuelle.
|
||||||
* @param creationCost Coût financier requis pour la création.
|
|
||||||
* @return GuildResult indiquant le succès ou la raison de l'échec.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult createGuild(Player creator, String name, String tag, String color, double creationCost) {
|
public void logAction(Guild guild, Player actor, String actionType, String details) {
|
||||||
if (creator == null) {
|
if (guild == null) return;
|
||||||
return GuildResult.failure("Joueur invalide.");
|
UUID actorUuid = actor != null ? actor.getUniqueId() : null;
|
||||||
|
String actorName = actor != null ? actor.getName() : "Système";
|
||||||
|
GuildLog log = new GuildLog(0, guild.getId(), actorUuid, actorName, actionType, details, System.currentTimeMillis());
|
||||||
|
repository.saveLogAsync(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Vérifier si le joueur est déjà dans une guilde
|
// ==========================================
|
||||||
if (isInGuild(creator.getUniqueId())) {
|
// CYCLE DE VIE D'UNE GUILDE
|
||||||
|
// ==========================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée une nouvelle guilde.
|
||||||
|
*/
|
||||||
|
public GuildResult createGuild(Player founder, String name, String tag, double creationCost) {
|
||||||
|
if (founder == null || name == null || tag == null) {
|
||||||
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID founderUuid = founder.getUniqueId();
|
||||||
|
|
||||||
|
if (isInGuild(founderUuid)) {
|
||||||
return GuildResult.failure("Vous appartenez déjà à une guilde.");
|
return GuildResult.failure("Vous appartenez déjà à une guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Valider le format du nom de la guilde
|
|
||||||
if (name == null || !GUILD_NAME_PATTERN.matcher(name).matches()) {
|
|
||||||
return GuildResult.failure("Le nom de guilde doit comporter entre 3 et 16 caractères alphanumériques.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Vérifier l'unicité du nom
|
|
||||||
if (getGuildByName(name) != null) {
|
if (getGuildByName(name) != null) {
|
||||||
return GuildResult.failure("Une guilde portant le nom '" + name + "' existe déjà.");
|
return GuildResult.failure("Une guilde portant ce nom existe déjà.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Vérifier si le chunk actuel est disponible
|
Location loc = founder.getLocation();
|
||||||
Location loc = creator.getLocation();
|
|
||||||
Chunk chunk = loc.getChunk();
|
Chunk chunk = loc.getChunk();
|
||||||
String worldName = loc.getWorld().getName();
|
|
||||||
int chunkX = chunk.getX();
|
int chunkX = chunk.getX();
|
||||||
int chunkZ = chunk.getZ();
|
int chunkZ = chunk.getZ();
|
||||||
|
String worldName = loc.getWorld().getName();
|
||||||
|
|
||||||
if (isChunkClaimed(worldName, chunkX, chunkZ)) {
|
if (isChunkClaimed(worldName, chunkX, chunkZ)) {
|
||||||
return GuildResult.failure("Le chunk où vous vous trouvez est déjà revendiqué par une autre guilde.");
|
return GuildResult.failure("Le chunk où vous vous trouvez est déjà revendiqué par une autre guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Vérifier et prélever l'argent du joueur
|
|
||||||
if (creationCost > 0) {
|
if (creationCost > 0) {
|
||||||
if (!economyManager.has(creator, creationCost)) {
|
if (!economyManager.has(founder, creationCost)) {
|
||||||
return GuildResult.failure("Vous n'avez pas assez d'argent pour fonder une guilde (Requis: " + economyManager.format(creationCost) + ").");
|
return GuildResult.failure("Vous n'avez pas les fonds nécessaires (" + economyManager.format(creationCost) + ") pour créer une guilde.");
|
||||||
}
|
}
|
||||||
boolean success = economyManager.withdraw(creator, creationCost);
|
if (!economyManager.withdraw(founder, creationCost)) {
|
||||||
if (!success) {
|
return GuildResult.failure("Échec de la transaction économique.");
|
||||||
return GuildResult.failure("Échec de la transaction financière lors de la création de la guilde.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Instancier la nouvelle guilde
|
|
||||||
UUID guildId = UUID.randomUUID();
|
UUID guildId = UUID.randomUUID();
|
||||||
Guild guild = new Guild(guildId, name, tag, color, "Guilde fondée par " + creator.getName(), 0.0, System.currentTimeMillis());
|
long now = System.currentTimeMillis();
|
||||||
|
Guild guild = new Guild(guildId, name, tag.toUpperCase(), "Guilde fondée par " + founder.getName(), 0.0, now);
|
||||||
|
guild.setHome(loc);
|
||||||
|
|
||||||
// 7. Configurer les rangs par défaut
|
// Rangs initiaux
|
||||||
GuildRank leaderRank = new GuildRank("leader", guildId, "Chef", 100, false, EnumSet.allOf(GuildPermission.class));
|
GuildRank leaderRank = new GuildRank("leader", guildId, "Chef", 100, false, EnumSet.allOf(GuildPermission.class));
|
||||||
GuildRank officerRank = new GuildRank("officer", guildId, "Officier", 50, false, EnumSet.of(
|
GuildRank officerRank = new GuildRank("officer", guildId, "Officier", 50, false, EnumSet.of(
|
||||||
GuildPermission.CLAIM, GuildPermission.UNCLAIM, GuildPermission.INVITE, GuildPermission.KICK,
|
GuildPermission.CLAIM, GuildPermission.UNCLAIM, GuildPermission.INVITE,
|
||||||
GuildPermission.SET_HOME, GuildPermission.HOME, GuildPermission.BANK_DEPOSIT, GuildPermission.BANK_WITHDRAW,
|
GuildPermission.KICK, GuildPermission.SET_HOME, GuildPermission.HOME,
|
||||||
|
GuildPermission.BANK_DEPOSIT, GuildPermission.BANK_WITHDRAW,
|
||||||
GuildPermission.BUILD, GuildPermission.BREAK, GuildPermission.INTERACT, GuildPermission.CONTAINER
|
GuildPermission.BUILD, GuildPermission.BREAK, GuildPermission.INTERACT, GuildPermission.CONTAINER
|
||||||
));
|
));
|
||||||
GuildRank memberRank = new GuildRank("member", guildId, "Membre", 1, true, EnumSet.of(
|
GuildRank memberRank = new GuildRank("member", guildId, "Membre", 1, true, EnumSet.of(
|
||||||
GuildPermission.HOME, GuildPermission.BANK_DEPOSIT, GuildPermission.BUILD,
|
GuildPermission.HOME, GuildPermission.BANK_DEPOSIT,
|
||||||
GuildPermission.BREAK, GuildPermission.INTERACT, GuildPermission.CONTAINER
|
GuildPermission.BUILD, GuildPermission.BREAK, GuildPermission.INTERACT, GuildPermission.CONTAINER
|
||||||
));
|
));
|
||||||
|
|
||||||
guild.addRank(leaderRank);
|
guild.addRank(leaderRank);
|
||||||
guild.addRank(officerRank);
|
guild.addRank(officerRank);
|
||||||
guild.addRank(memberRank);
|
guild.addRank(memberRank);
|
||||||
|
|
||||||
// 8. Ajouter le fondateur comme chef
|
GuildMember founderMember = new GuildMember(founderUuid, guildId, "leader", now, now, 0.0);
|
||||||
GuildMember founder = new GuildMember(creator.getUniqueId(), guildId, leaderRank.getId(), System.currentTimeMillis(), System.currentTimeMillis(), 0.0);
|
guild.addMember(founderMember);
|
||||||
guild.addMember(founder);
|
|
||||||
|
|
||||||
// 9. Claimer le 1er chunk et définir le home
|
GuildClaim initialClaim = new GuildClaim(0, guildId, worldName, chunkX, chunkZ, now);
|
||||||
GuildClaim initialClaim = new GuildClaim(0, guildId, worldName, chunkX, chunkZ, System.currentTimeMillis());
|
|
||||||
guild.addClaim(initialClaim);
|
guild.addClaim(initialClaim);
|
||||||
guild.setHome(loc);
|
|
||||||
|
|
||||||
// 10. Indexer et persister en BDD
|
|
||||||
indexGuild(guild);
|
indexGuild(guild);
|
||||||
|
|
||||||
repository.saveGuildAsync(guild);
|
repository.saveGuildAsync(guild);
|
||||||
repository.saveRankAsync(leaderRank);
|
repository.saveRankAsync(leaderRank);
|
||||||
repository.saveRankAsync(officerRank);
|
repository.saveRankAsync(officerRank);
|
||||||
repository.saveRankAsync(memberRank);
|
repository.saveRankAsync(memberRank);
|
||||||
repository.saveMemberAsync(founder);
|
repository.saveMemberAsync(founderMember);
|
||||||
repository.saveClaimAsync(initialClaim);
|
repository.saveClaimAsync(initialClaim);
|
||||||
|
|
||||||
// 11. Créer la région WorldGuard
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.createOrUpdateRegion(guild, loc.getWorld(), chunkX, chunkZ);
|
worldGuardManager.createOrUpdateRegion(guild, loc.getWorld(), chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GuildResult.success("La guilde <white><bold>" + name + "</bold></white> a été créée avec succès !");
|
logAction(guild, founder, "CREATION", "Création de la guilde avec le chunk initial (" + chunkX + ", " + chunkZ + ")");
|
||||||
|
|
||||||
|
return GuildResult.success("La guilde " + guild.getFormattedName() + " a été créée avec succès !");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dissout définitivement une guilde existante. Seul le chef de guilde peut initier cette action.
|
* Dissout définitivement une guilde existante.
|
||||||
*
|
|
||||||
* @param actor Le joueur demandant la suppression.
|
|
||||||
* @param guild La guilde à dissoudre.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult disbandGuild(Player actor, Guild guild) {
|
public GuildResult disbandGuild(Player actor, Guild guild) {
|
||||||
if (actor == null || guild == null) {
|
if (actor == null || guild == null) {
|
||||||
return GuildResult.failure("Paramètres invalides.");
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifier si l'acteur est bien le chef de la guilde
|
|
||||||
GuildMember actorMember = guild.getMember(actor.getUniqueId());
|
GuildMember actorMember = guild.getMember(actor.getUniqueId());
|
||||||
if (actorMember == null) {
|
if (actorMember == null) {
|
||||||
return GuildResult.failure("Vous ne faites pas partie de cette guilde.");
|
return GuildResult.failure("Vous ne faites pas partie de cette guilde.");
|
||||||
@@ -233,15 +238,13 @@ public class GuildManager {
|
|||||||
return GuildResult.failure("Seul le Chef de la guilde peut dissoudre la guilde.");
|
return GuildResult.failure("Seul le Chef de la guilde peut dissoudre la guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supprimer toutes les régions WorldGuard associées
|
logAction(guild, actor, "DISBAND", "Dissolution de la guilde par " + actor.getName());
|
||||||
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.removeGuildRegions(guild);
|
worldGuardManager.removeGuildRegions(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Désindexer la guilde
|
|
||||||
unindexGuild(guild);
|
unindexGuild(guild);
|
||||||
|
|
||||||
// Supprimer de la base de données
|
|
||||||
repository.deleteGuildAsync(guild.getId());
|
repository.deleteGuildAsync(guild.getId());
|
||||||
|
|
||||||
return GuildResult.success("La guilde <white>" + guild.getName() + "</white> a été dissoute.");
|
return GuildResult.success("La guilde <white>" + guild.getName() + "</white> a été dissoute.");
|
||||||
@@ -252,11 +255,7 @@ public class GuildManager {
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intègre un joueur dans une guilde en lui attribuant le rang par défaut.
|
* Intègre un joueur dans une guilde.
|
||||||
*
|
|
||||||
* @param guild La guilde à rejoindre.
|
|
||||||
* @param player Le nouveau membre.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult addMember(Guild guild, Player player) {
|
public GuildResult addMember(Guild guild, Player player) {
|
||||||
if (guild == null || player == null) {
|
if (guild == null || player == null) {
|
||||||
@@ -277,21 +276,18 @@ public class GuildManager {
|
|||||||
playerGuildMap.put(player.getUniqueId(), guild.getId());
|
playerGuildMap.put(player.getUniqueId(), guild.getId());
|
||||||
repository.saveMemberAsync(member);
|
repository.saveMemberAsync(member);
|
||||||
|
|
||||||
// Synchroniser WorldGuard
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.syncGuildMembers(guild);
|
worldGuardManager.syncGuildMembers(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logAction(guild, player, "JOIN", player.getName() + " a rejoint la guilde (" + defaultRank.getName() + ")");
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.member_joined", "{player}", player.getName());
|
||||||
|
|
||||||
return GuildResult.success("Le joueur <white>" + player.getName() + "</white> a rejoint la guilde !");
|
return GuildResult.success("Le joueur <white>" + player.getName() + "</white> a rejoint la guilde !");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expulse un membre d'une guilde avec vérification de la hiérarchie des rangs.
|
* Expulse un membre d'une guilde.
|
||||||
*
|
|
||||||
* @param actor Le joueur initiateur de l'expulsion.
|
|
||||||
* @param guild La guilde concernée.
|
|
||||||
* @param targetUuid L'UUID du membre à expulser.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult kickMember(Player actor, Guild guild, UUID targetUuid) {
|
public GuildResult kickMember(Player actor, Guild guild, UUID targetUuid) {
|
||||||
if (actor == null || guild == null || targetUuid == null) {
|
if (actor == null || guild == null || targetUuid == null) {
|
||||||
@@ -317,24 +313,26 @@ public class GuildManager {
|
|||||||
return GuildResult.failure("Vous ne pouvez pas expulser un membre ayant un rang supérieur ou égal au vôtre.");
|
return GuildResult.failure("Vous ne pouvez pas expulser un membre ayant un rang supérieur ou égal au vôtre.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String targetName = targetMember.getOfflinePlayer() != null && targetMember.getOfflinePlayer().getName() != null
|
||||||
|
? targetMember.getOfflinePlayer().getName()
|
||||||
|
: targetUuid.toString().substring(0, 8);
|
||||||
|
|
||||||
guild.removeMember(targetUuid);
|
guild.removeMember(targetUuid);
|
||||||
playerGuildMap.remove(targetUuid);
|
playerGuildMap.remove(targetUuid);
|
||||||
repository.deleteMemberAsync(targetUuid);
|
repository.deleteMemberAsync(targetUuid);
|
||||||
|
|
||||||
// Synchroniser WorldGuard
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.syncGuildMembers(guild);
|
worldGuardManager.syncGuildMembers(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logAction(guild, actor, "KICK", targetName + " a été expulsé par " + actor.getName());
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.member_kicked", "{player}", targetName, "{actor}", actor.getName());
|
||||||
|
|
||||||
return GuildResult.success("Le membre a été expulsé de la guilde.");
|
return GuildResult.success("Le membre a été expulsé de la guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permet à un membre de quitter volontairement sa guilde.
|
* Permet à un membre de quitter volontairement sa guilde.
|
||||||
*
|
|
||||||
* @param player Le joueur souhaitant partir.
|
|
||||||
* @param guild La guilde quittée.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult leaveGuild(Player player, Guild guild) {
|
public GuildResult leaveGuild(Player player, Guild guild) {
|
||||||
if (player == null || guild == null) {
|
if (player == null || guild == null) {
|
||||||
@@ -355,22 +353,18 @@ public class GuildManager {
|
|||||||
playerGuildMap.remove(player.getUniqueId());
|
playerGuildMap.remove(player.getUniqueId());
|
||||||
repository.deleteMemberAsync(player.getUniqueId());
|
repository.deleteMemberAsync(player.getUniqueId());
|
||||||
|
|
||||||
// Synchroniser WorldGuard
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.syncGuildMembers(guild);
|
worldGuardManager.syncGuildMembers(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logAction(guild, player, "LEAVE", player.getName() + " a quitté la guilde.");
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.member_left", "{player}", player.getName());
|
||||||
|
|
||||||
return GuildResult.success("Vous avez quitté la guilde.");
|
return GuildResult.success("Vous avez quitté la guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifie le rang d'un membre avec contrôle de priorité hiérarchique.
|
* Modifie le rang d'un membre.
|
||||||
*
|
|
||||||
* @param actor Le joueur initiateur.
|
|
||||||
* @param guild La guilde concernée.
|
|
||||||
* @param targetUuid Le membre cible.
|
|
||||||
* @param newRankId L'identifiant du nouveau rang.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
*/
|
||||||
public GuildResult setMemberRank(Player actor, Guild guild, UUID targetUuid, String newRankId) {
|
public GuildResult setMemberRank(Player actor, Guild guild, UUID targetUuid, String newRankId) {
|
||||||
if (actor == null || guild == null || targetUuid == null || newRankId == null) {
|
if (actor == null || guild == null || targetUuid == null || newRankId == null) {
|
||||||
@@ -395,7 +389,6 @@ public class GuildManager {
|
|||||||
GuildRank targetCurrentRank = guild.getRank(targetMember.getRankId());
|
GuildRank targetCurrentRank = guild.getRank(targetMember.getRankId());
|
||||||
boolean isPromote = targetCurrentRank == null || newRank.getPriority() > targetCurrentRank.getPriority();
|
boolean isPromote = targetCurrentRank == null || newRank.getPriority() > targetCurrentRank.getPriority();
|
||||||
|
|
||||||
// Vérification des permissions
|
|
||||||
if (isPromote && !actorRank.hasPermission(GuildPermission.PROMOTE)) {
|
if (isPromote && !actorRank.hasPermission(GuildPermission.PROMOTE)) {
|
||||||
return GuildResult.failure("Vous n'avez pas la permission de promouvoir des membres.");
|
return GuildResult.failure("Vous n'avez pas la permission de promouvoir des membres.");
|
||||||
}
|
}
|
||||||
@@ -403,7 +396,6 @@ public class GuildManager {
|
|||||||
return GuildResult.failure("Vous n'avez pas la permission de rétrograder des membres.");
|
return GuildResult.failure("Vous n'avez pas la permission de rétrograder des membres.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contrôle hiérarchique : l'acteur ne peut pas affecter un rang supérieur ou égal au sien
|
|
||||||
GuildRank leaderRank = guild.getLeaderRank();
|
GuildRank leaderRank = guild.getLeaderRank();
|
||||||
boolean isLeader = actorRank.equals(leaderRank);
|
boolean isLeader = actorRank.equals(leaderRank);
|
||||||
if (!isLeader && newRank.getPriority() >= actorRank.getPriority()) {
|
if (!isLeader && newRank.getPriority() >= actorRank.getPriority()) {
|
||||||
@@ -413,26 +405,141 @@ public class GuildManager {
|
|||||||
targetMember.setRankId(newRank.getId());
|
targetMember.setRankId(newRank.getId());
|
||||||
repository.saveMemberAsync(targetMember);
|
repository.saveMemberAsync(targetMember);
|
||||||
|
|
||||||
// Synchroniser WorldGuard (au cas où le chef a changé)
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.syncGuildMembers(guild);
|
worldGuardManager.syncGuildMembers(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String targetName = targetMember.getOfflinePlayer() != null && targetMember.getOfflinePlayer().getName() != null
|
||||||
|
? targetMember.getOfflinePlayer().getName()
|
||||||
|
: targetUuid.toString().substring(0, 8);
|
||||||
|
|
||||||
|
logAction(guild, actor, "RANK_CHANGE", targetName + " assigné au rang " + newRank.getName());
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.rank_changed", "{player}", targetName, "{rank}", newRank.getName(), "{actor}", actor.getName());
|
||||||
|
|
||||||
return GuildResult.success("Le rang du membre a été mis à jour vers <white>" + newRank.getName() + "</white>.");
|
return GuildResult.success("Le rang du membre a été mis à jour vers <white>" + newRank.getName() + "</white>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un nouveau rang personnalisé pour la guilde.
|
||||||
|
*/
|
||||||
|
public GuildResult createRank(Player actor, Guild guild, String rankId, String name, int priority) {
|
||||||
|
if (actor == null || guild == null || rankId == null || name == null) {
|
||||||
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank actorRank = guild.getMemberRank(actor.getUniqueId());
|
||||||
|
if (actorRank == null || !actorRank.hasPermission(GuildPermission.MANAGE_RANKS)) {
|
||||||
|
return GuildResult.failure("Votre rang ne vous autorise pas à gérer les rangs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank leaderRank = guild.getLeaderRank();
|
||||||
|
boolean isLeader = actorRank.equals(leaderRank);
|
||||||
|
if (!isLeader && priority >= actorRank.getPriority()) {
|
||||||
|
return GuildResult.failure("Vous ne pouvez pas créer un rang ayant une priorité supérieure ou égale à la vôtre.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String cleanId = rankId.toLowerCase();
|
||||||
|
if (guild.getRank(cleanId) != null) {
|
||||||
|
return GuildResult.failure("Un rang avec cet identifiant existe déjà.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank newRank = new GuildRank(cleanId, guild.getId(), name, priority, false, EnumSet.of(GuildPermission.HOME, GuildPermission.BANK_DEPOSIT, GuildPermission.BUILD, GuildPermission.BREAK, GuildPermission.INTERACT, GuildPermission.CONTAINER));
|
||||||
|
guild.addRank(newRank);
|
||||||
|
repository.saveRankAsync(newRank);
|
||||||
|
|
||||||
|
logAction(guild, actor, "RANK_CREATE", "Création du rang " + name + " (Priorité: " + priority + ")");
|
||||||
|
|
||||||
|
return GuildResult.success("Le rang <yellow>" + name + "</yellow> (ID: " + cleanId + ", Priorité: " + priority + ") a été créé avec succès !");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime un rang existant de la guilde.
|
||||||
|
*/
|
||||||
|
public GuildResult deleteRank(Player actor, Guild guild, String rankId) {
|
||||||
|
if (actor == null || guild == null || rankId == null) {
|
||||||
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank actorRank = guild.getMemberRank(actor.getUniqueId());
|
||||||
|
if (actorRank == null || !actorRank.hasPermission(GuildPermission.MANAGE_RANKS)) {
|
||||||
|
return GuildResult.failure("Votre rang ne vous autorise pas à gérer les rangs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank rank = guild.getRank(rankId.toLowerCase());
|
||||||
|
if (rank == null) {
|
||||||
|
return GuildResult.failure("Le rang spécifié n'existe pas.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank leaderRank = guild.getLeaderRank();
|
||||||
|
GuildRank defaultRank = guild.getDefaultRank();
|
||||||
|
|
||||||
|
if (rank.equals(leaderRank)) {
|
||||||
|
return GuildResult.failure("Vous ne pouvez pas supprimer le rang de Chef.");
|
||||||
|
}
|
||||||
|
if (rank.equals(defaultRank)) {
|
||||||
|
return GuildResult.failure("Vous ne pouvez pas supprimer le rang par défaut.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank fallbackRank = defaultRank != null ? defaultRank : guild.getRanks().stream().filter(r -> !r.equals(rank)).findFirst().orElse(null);
|
||||||
|
if (fallbackRank == null) {
|
||||||
|
return GuildResult.failure("Impossible de supprimer ce rang sans rang de repli.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrer les membres occupant ce rang
|
||||||
|
for (GuildMember m : guild.getMembers()) {
|
||||||
|
if (m.getRankId().equalsIgnoreCase(rank.getId())) {
|
||||||
|
m.setRankId(fallbackRank.getId());
|
||||||
|
repository.saveMemberAsync(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guild.removeRank(rank.getId());
|
||||||
|
repository.deleteRankAsync(rank.getId(), guild.getId());
|
||||||
|
|
||||||
|
logAction(guild, actor, "RANK_DELETE", "Suppression du rang " + rank.getName());
|
||||||
|
|
||||||
|
return GuildResult.success("Le rang <white>" + rank.getName() + "</white> a été supprimé.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active ou désactive une permission spécifique pour un rang.
|
||||||
|
*/
|
||||||
|
public GuildResult setRankPermission(Player actor, Guild guild, String rankId, GuildPermission permission, boolean state) {
|
||||||
|
if (actor == null || guild == null || rankId == null || permission == null) {
|
||||||
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank actorRank = guild.getMemberRank(actor.getUniqueId());
|
||||||
|
if (actorRank == null || !actorRank.hasPermission(GuildPermission.MANAGE_RANKS)) {
|
||||||
|
return GuildResult.failure("Votre rang ne vous autorise pas à gérer les rangs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank rank = guild.getRank(rankId.toLowerCase());
|
||||||
|
if (rank == null) {
|
||||||
|
return GuildResult.failure("Le rang spécifié n'existe pas.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GuildRank leaderRank = guild.getLeaderRank();
|
||||||
|
if (rank.equals(leaderRank)) {
|
||||||
|
return GuildResult.failure("Vous ne pouvez pas modifier les permissions du Chef.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
rank.addPermission(permission);
|
||||||
|
} else {
|
||||||
|
rank.removePermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.saveRankAsync(rank);
|
||||||
|
logAction(guild, actor, "RANK_PERM", "Permission " + permission.name() + " -> " + state + " pour " + rank.getName());
|
||||||
|
|
||||||
|
return GuildResult.success("Permission <yellow>" + permission.name() + "</yellow> mise à <aqua>" + state + "</aqua> pour le rang <yellow>" + rank.getName() + "</yellow>.");
|
||||||
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// PERSONNALISATION (COULEUR & TAG)
|
// PERSONNALISATION (COULEUR & TAG)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifie la couleur hexadécimale de la guilde.
|
|
||||||
*
|
|
||||||
* @param actor Le joueur initiateur de la commande.
|
|
||||||
* @param guild La guilde concernée.
|
|
||||||
* @param hexColor Le code couleur hexadécimal (ex: "#FF5555").
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
|
||||||
public GuildResult setGuildColor(Player actor, Guild guild, String hexColor) {
|
public GuildResult setGuildColor(Player actor, Guild guild, String hexColor) {
|
||||||
if (actor == null || guild == null || hexColor == null) {
|
if (actor == null || guild == null || hexColor == null) {
|
||||||
return GuildResult.failure("Paramètres invalides.");
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
@@ -448,18 +555,11 @@ public class GuildManager {
|
|||||||
|
|
||||||
guild.setColor(hexColor);
|
guild.setColor(hexColor);
|
||||||
repository.saveGuildAsync(guild);
|
repository.saveGuildAsync(guild);
|
||||||
|
logAction(guild, actor, "COLOR", "Couleur modifiée vers " + hexColor);
|
||||||
|
|
||||||
return GuildResult.success("La couleur de la guilde a été changée pour <color:" + hexColor + ">" + hexColor + "</color> !");
|
return GuildResult.success("La couleur de la guilde a été changée pour <color:" + hexColor + ">" + hexColor + "</color> !");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Modifie le tag court de la guilde.
|
|
||||||
*
|
|
||||||
* @param actor Le joueur initiateur.
|
|
||||||
* @param guild La guilde concernée.
|
|
||||||
* @param newTag Le nouveau tag (2 à 6 caractères alphanumériques).
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
|
||||||
public GuildResult setGuildTag(Player actor, Guild guild, String newTag) {
|
public GuildResult setGuildTag(Player actor, Guild guild, String newTag) {
|
||||||
if (actor == null || guild == null || newTag == null) {
|
if (actor == null || guild == null || newTag == null) {
|
||||||
return GuildResult.failure("Paramètres invalides.");
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
@@ -475,6 +575,7 @@ public class GuildManager {
|
|||||||
|
|
||||||
guild.setTag(newTag.toUpperCase());
|
guild.setTag(newTag.toUpperCase());
|
||||||
repository.saveGuildAsync(guild);
|
repository.saveGuildAsync(guild);
|
||||||
|
logAction(guild, actor, "TAG", "Tag modifié vers [" + newTag.toUpperCase() + "]");
|
||||||
|
|
||||||
return GuildResult.success("Le tag de la guilde a été changé pour " + guild.getFormattedTag() + " !");
|
return GuildResult.success("Le tag de la guilde a été changé pour " + guild.getFormattedTag() + " !");
|
||||||
}
|
}
|
||||||
@@ -483,16 +584,6 @@ public class GuildManager {
|
|||||||
// GESTION DES CLAIMS (TERRITOIRES)
|
// GESTION DES CLAIMS (TERRITOIRES)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
||||||
/**
|
|
||||||
* Revendique un chunk territorial pour une guilde en débitant son coût depuis la banque de guilde.
|
|
||||||
*
|
|
||||||
* @param player Le joueur initiant le claim.
|
|
||||||
* @param guild La guilde pour laquelle claimer.
|
|
||||||
* @param world Le monde Minecraft.
|
|
||||||
* @param chunkX La coordonnée X du chunk.
|
|
||||||
* @param chunkZ La coordonnée Z du chunk.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
|
||||||
public GuildResult claimChunk(Player player, Guild guild, World world, int chunkX, int chunkZ) {
|
public GuildResult claimChunk(Player player, Guild guild, World world, int chunkX, int chunkZ) {
|
||||||
if (player == null || guild == null || world == null) {
|
if (player == null || guild == null || world == null) {
|
||||||
return GuildResult.failure("Paramètres invalides.");
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
@@ -500,52 +591,38 @@ public class GuildManager {
|
|||||||
|
|
||||||
String worldName = world.getName();
|
String worldName = world.getName();
|
||||||
|
|
||||||
// 1. Vérifier la permission
|
|
||||||
if (!guild.hasPermission(player.getUniqueId(), GuildPermission.CLAIM)) {
|
if (!guild.hasPermission(player.getUniqueId(), GuildPermission.CLAIM)) {
|
||||||
return GuildResult.failure("Votre rang ne vous autorise pas à revendiquer de nouveaux territoires.");
|
return GuildResult.failure("Votre rang ne vous autorise pas à revendiquer de nouveaux territoires.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Vérifier si le chunk est déjà claimé
|
|
||||||
if (isChunkClaimed(worldName, chunkX, chunkZ)) {
|
if (isChunkClaimed(worldName, chunkX, chunkZ)) {
|
||||||
return GuildResult.failure("Ce chunk est déjà revendiqué.");
|
return GuildResult.failure("Ce chunk est déjà revendiqué.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Calculer le prix du chunk avec la formule spatio-temporelle
|
|
||||||
double price = priceCalculator.calculateNextChunkPrice(guild);
|
double price = priceCalculator.calculateNextChunkPrice(guild);
|
||||||
|
|
||||||
// 4. Vérifier si la banque de guilde possède les fonds
|
|
||||||
if (!guild.hasBalance(price)) {
|
if (!guild.hasBalance(price)) {
|
||||||
return GuildResult.failure("La banque de guilde n'a pas assez d'argent (Requis: " + economyManager.format(price) + ", Solde: " + economyManager.format(guild.getBalance()) + ").");
|
return GuildResult.failure("La banque de guilde n'a pas assez d'argent (Requis: " + economyManager.format(price) + ", Solde: " + economyManager.format(guild.getBalance()) + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Débiter la banque et enregistrer le claim
|
|
||||||
guild.withdraw(price);
|
guild.withdraw(price);
|
||||||
GuildClaim claim = new GuildClaim(0, guild.getId(), worldName, chunkX, chunkZ, System.currentTimeMillis());
|
GuildClaim claim = new GuildClaim(0, guild.getId(), worldName, chunkX, chunkZ, System.currentTimeMillis());
|
||||||
guild.addClaim(claim);
|
guild.addClaim(claim);
|
||||||
chunkGuildMap.put(getChunkKey(worldName, chunkX, chunkZ), guild.getId());
|
chunkGuildMap.put(getChunkKey(worldName, chunkX, chunkZ), guild.getId());
|
||||||
|
|
||||||
// 6. Sauvegarder en BDD
|
|
||||||
repository.saveGuildAsync(guild);
|
repository.saveGuildAsync(guild);
|
||||||
repository.saveClaimAsync(claim);
|
repository.saveClaimAsync(claim);
|
||||||
|
|
||||||
// 7. Créer la région WorldGuard
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.createOrUpdateRegion(guild, world, chunkX, chunkZ);
|
worldGuardManager.createOrUpdateRegion(guild, world, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logAction(guild, player, "CLAIM", "Claim (" + chunkX + ", " + chunkZ + ") pour " + economyManager.format(price));
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.chunk_claimed", "{player}", player.getName(), "{chunk_x}", String.valueOf(chunkX), "{chunk_z}", String.valueOf(chunkZ), "{cost}", economyManager.format(price));
|
||||||
|
|
||||||
return GuildResult.success("Chunk revendiqué avec succès pour <yellow>" + economyManager.format(price) + "</yellow> ! (Total: " + guild.getClaimCount() + " chunks)");
|
return GuildResult.success("Chunk revendiqué avec succès pour <yellow>" + economyManager.format(price) + "</yellow> ! (Total: " + guild.getClaimCount() + " chunks)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Abandonne un chunk possédé par la guilde.
|
|
||||||
*
|
|
||||||
* @param player Le joueur initiateur.
|
|
||||||
* @param guild La guilde propriétaire.
|
|
||||||
* @param world Le monde Minecraft.
|
|
||||||
* @param chunkX La coordonnée X du chunk.
|
|
||||||
* @param chunkZ La coordonnée Z du chunk.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
|
||||||
public GuildResult unclaimChunk(Player player, Guild guild, World world, int chunkX, int chunkZ) {
|
public GuildResult unclaimChunk(Player player, Guild guild, World world, int chunkX, int chunkZ) {
|
||||||
if (player == null || guild == null || world == null) {
|
if (player == null || guild == null || world == null) {
|
||||||
return GuildResult.failure("Paramètres invalides.");
|
return GuildResult.failure("Paramètres invalides.");
|
||||||
@@ -553,31 +630,29 @@ public class GuildManager {
|
|||||||
|
|
||||||
String worldName = world.getName();
|
String worldName = world.getName();
|
||||||
|
|
||||||
// 1. Vérifier la permission
|
|
||||||
if (!guild.hasPermission(player.getUniqueId(), GuildPermission.UNCLAIM)) {
|
if (!guild.hasPermission(player.getUniqueId(), GuildPermission.UNCLAIM)) {
|
||||||
return GuildResult.failure("Votre rang ne vous autorise pas à abandonner des territoires.");
|
return GuildResult.failure("Votre rang ne vous autorise pas à abandonner des territoires.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Vérifier si le chunk appartient à la guilde
|
|
||||||
if (!guild.isClaimed(worldName, chunkX, chunkZ)) {
|
if (!guild.isClaimed(worldName, chunkX, chunkZ)) {
|
||||||
return GuildResult.failure("Ce chunk n'appartient pas à votre guilde.");
|
return GuildResult.failure("Ce chunk n'appartient pas à votre guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Empêcher d'avoir 0 chunk si c'est le dernier
|
|
||||||
if (guild.getClaimCount() <= 1) {
|
if (guild.getClaimCount() <= 1) {
|
||||||
return GuildResult.failure("Vous ne pouvez pas abandonner le dernier chunk de votre guilde.");
|
return GuildResult.failure("Vous ne pouvez pas abandonner le dernier chunk de votre guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Supprimer la région WorldGuard
|
|
||||||
if (worldGuardManager != null) {
|
if (worldGuardManager != null) {
|
||||||
worldGuardManager.removeRegion(guild, world, chunkX, chunkZ);
|
worldGuardManager.removeRegion(guild, world, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Supprimer le claim
|
|
||||||
guild.removeClaim(worldName, chunkX, chunkZ);
|
guild.removeClaim(worldName, chunkX, chunkZ);
|
||||||
chunkGuildMap.remove(getChunkKey(worldName, chunkX, chunkZ));
|
chunkGuildMap.remove(getChunkKey(worldName, chunkX, chunkZ));
|
||||||
repository.deleteClaimAsync(worldName, chunkX, chunkZ);
|
repository.deleteClaimAsync(worldName, chunkX, chunkZ);
|
||||||
|
|
||||||
|
logAction(guild, player, "UNCLAIM", "Abandon du chunk (" + chunkX + ", " + chunkZ + ")");
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.chunk_unclaimed", "{player}", player.getName(), "{chunk_x}", String.valueOf(chunkX), "{chunk_z}", String.valueOf(chunkZ));
|
||||||
|
|
||||||
return GuildResult.success("Le chunk a été libéré.");
|
return GuildResult.success("Le chunk a été libéré.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,14 +660,6 @@ public class GuildManager {
|
|||||||
// GESTION DE LA BANQUE
|
// GESTION DE LA BANQUE
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
||||||
/**
|
|
||||||
* Dépose de l'argent depuis le compte personnel d'un joueur vers la banque de guilde.
|
|
||||||
*
|
|
||||||
* @param player Le joueur déposant.
|
|
||||||
* @param guild La guilde bénéficiaire.
|
|
||||||
* @param amount Le montant à déposer.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
|
||||||
public GuildResult depositMoney(Player player, Guild guild, double amount) {
|
public GuildResult depositMoney(Player player, Guild guild, double amount) {
|
||||||
if (player == null || guild == null || amount <= 0) {
|
if (player == null || guild == null || amount <= 0) {
|
||||||
return GuildResult.failure("Montant invalide.");
|
return GuildResult.failure("Montant invalide.");
|
||||||
@@ -619,17 +686,12 @@ public class GuildManager {
|
|||||||
}
|
}
|
||||||
repository.saveGuildAsync(guild);
|
repository.saveGuildAsync(guild);
|
||||||
|
|
||||||
|
logAction(guild, player, "DEPOSIT", player.getName() + " a déposé " + economyManager.format(amount));
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.bank_deposit", "{player}", player.getName(), "{amount}", economyManager.format(amount), "{balance}", economyManager.format(guild.getBalance()));
|
||||||
|
|
||||||
return GuildResult.success("Vous avez déposé <green>" + economyManager.format(amount) + "</green> dans la banque de guilde ! (Nouveau solde: " + economyManager.format(guild.getBalance()) + ")");
|
return GuildResult.success("Vous avez déposé <green>" + economyManager.format(amount) + "</green> dans la banque de guilde ! (Nouveau solde: " + economyManager.format(guild.getBalance()) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retire de l'argent de la banque de guilde vers le compte d'un joueur.
|
|
||||||
*
|
|
||||||
* @param player Le joueur bénéficiaire.
|
|
||||||
* @param guild La guilde débitée.
|
|
||||||
* @param amount Le montant à retirer.
|
|
||||||
* @return GuildResult.
|
|
||||||
*/
|
|
||||||
public GuildResult withdrawMoney(Player player, Guild guild, double amount) {
|
public GuildResult withdrawMoney(Player player, Guild guild, double amount) {
|
||||||
if (player == null || guild == null || amount <= 0) {
|
if (player == null || guild == null || amount <= 0) {
|
||||||
return GuildResult.failure("Montant invalide.");
|
return GuildResult.failure("Montant invalide.");
|
||||||
@@ -648,14 +710,21 @@ public class GuildManager {
|
|||||||
return GuildResult.failure("Impossible de débiter la banque de guilde.");
|
return GuildResult.failure("Impossible de débiter la banque de guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
economyManager.deposit(player, amount);
|
boolean depositedToPlayer = economyManager.deposit(player, amount);
|
||||||
|
if (!depositedToPlayer) {
|
||||||
|
guild.deposit(amount);
|
||||||
|
return GuildResult.failure("Échec du crédit sur votre compte personnel.");
|
||||||
|
}
|
||||||
|
|
||||||
repository.saveGuildAsync(guild);
|
repository.saveGuildAsync(guild);
|
||||||
|
logAction(guild, player, "WITHDRAW", player.getName() + " a retiré " + economyManager.format(amount));
|
||||||
|
broadcastToGuild(guild, "guild.broadcast.bank_withdraw", "{player}", player.getName(), "{amount}", economyManager.format(amount), "{balance}", economyManager.format(guild.getBalance()));
|
||||||
|
|
||||||
return GuildResult.success("Vous avez retiré <green>" + economyManager.format(amount) + "</green> de la banque de guilde.");
|
return GuildResult.success("Vous avez retiré <green>" + economyManager.format(amount) + "</green> de la banque de guilde.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// GETTERS & LOOKUPS RAPIDES
|
// GETTERS & INDEXATION
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
||||||
public Guild getGuildById(UUID guildId) {
|
public Guild getGuildById(UUID guildId) {
|
||||||
@@ -704,14 +773,10 @@ public class GuildManager {
|
|||||||
return inviteManager;
|
return inviteManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public fr.luc.gamingcore.worldguard.WorldGuardManager getWorldGuardManager() {
|
public WorldGuardManager getWorldGuardManager() {
|
||||||
return worldGuardManager;
|
return worldGuardManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// MÉTHODES INTERNES D'INDEXATION
|
|
||||||
// ==========================================
|
|
||||||
|
|
||||||
private void indexGuild(Guild guild) {
|
private void indexGuild(Guild guild) {
|
||||||
guildsById.put(guild.getId(), guild);
|
guildsById.put(guild.getId(), guild);
|
||||||
guildsByName.put(guild.getName().toLowerCase(), guild.getId());
|
guildsByName.put(guild.getName().toLowerCase(), guild.getId());
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package fr.luc.gamingcore.model;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entité représentant une entrée d'historique (log) au sein d'une guilde.
|
||||||
|
*/
|
||||||
|
public class GuildLog {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MM HH:mm").withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
|
private final long id;
|
||||||
|
private final UUID guildId;
|
||||||
|
private final UUID actorUuid;
|
||||||
|
private final String actorName;
|
||||||
|
private final String actionType;
|
||||||
|
private final String details;
|
||||||
|
private final long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur complet d'une entrée de log de guilde.
|
||||||
|
*
|
||||||
|
* @param id Identifiant unique en BDD.
|
||||||
|
* @param guildId UUID de la guilde associée.
|
||||||
|
* @param actorUuid UUID du joueur ayant déclenché l'action (peut être null).
|
||||||
|
* @param actorName Nom du joueur ou "Système".
|
||||||
|
* @param actionType Type d'action (ex: JOIN, LEAVE, CLAIM, BANK_DEPOSIT, etc.).
|
||||||
|
* @param details Description textuelle de l'événement.
|
||||||
|
* @param timestamp Timestamp Unix en millisecondes.
|
||||||
|
*/
|
||||||
|
public GuildLog(long id, UUID guildId, UUID actorUuid, String actorName, String actionType, String details, long timestamp) {
|
||||||
|
this.id = id;
|
||||||
|
this.guildId = guildId;
|
||||||
|
this.actorUuid = actorUuid;
|
||||||
|
this.actorName = actorName != null ? actorName : "Système";
|
||||||
|
this.actionType = actionType != null ? actionType : "INFO";
|
||||||
|
this.details = details != null ? details : "";
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getGuildId() {
|
||||||
|
return guildId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getActorUuid() {
|
||||||
|
return actorUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getActorName() {
|
||||||
|
return actorName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getActionType() {
|
||||||
|
return actionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne la date et l'heure formatée de l'entrée de log.
|
||||||
|
*
|
||||||
|
* @return Ex: "20/08 20:45"
|
||||||
|
*/
|
||||||
|
public String getFormattedDate() {
|
||||||
|
return TIME_FORMATTER.format(Instant.ofEpochMilli(timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -123,6 +123,10 @@ public class WorldGuardManager {
|
|||||||
region.setFlag(Flags.TNT, StateFlag.State.DENY);
|
region.setFlag(Flags.TNT, StateFlag.State.DENY);
|
||||||
region.setFlag(Flags.CREEPER_EXPLOSION, StateFlag.State.DENY);
|
region.setFlag(Flags.CREEPER_EXPLOSION, StateFlag.State.DENY);
|
||||||
region.setFlag(Flags.PVP, StateFlag.State.DENY);
|
region.setFlag(Flags.PVP, StateFlag.State.DENY);
|
||||||
|
region.setFlag(Flags.PISTONS, StateFlag.State.ALLOW);
|
||||||
|
region.setFlag(Flags.FIRE_SPREAD, StateFlag.State.DENY);
|
||||||
|
region.setFlag(Flags.LAVA_FIRE, StateFlag.State.DENY);
|
||||||
|
region.setFlag(Flags.LIGHTER, StateFlag.State.DENY);
|
||||||
|
|
||||||
regionManager.addRegion(region);
|
regionManager.addRegion(region);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ guild:
|
|||||||
sent: "<green>Invitation envoyée à <white>{player}</white> (Expire dans <yellow>{seconds}s</yellow>).</green>"
|
sent: "<green>Invitation envoyée à <white>{player}</white> (Expire dans <yellow>{seconds}s</yellow>).</green>"
|
||||||
received_interactive: "<gradient:#00C9FF:#92FE9D>[Guilde]</gradient> Vous avez été invité à rejoindre la guilde {guild} {tag} par <yellow>{sender}</yellow> !\n<click:run_command:'/guild join {raw_guild}'><hover:show_text:'<green>Cliquez pour accepter l''invitation et rejoindre la guilde !</green>'><green><bold>[ ✅ ACCEPTER ]</bold></green></hover></click> <click:run_command:'/guild decline {raw_guild}'><hover:show_text:'<red>Cliquez pour refuser l''invitation.</red>'><red><bold>[ ❌ REFUSER ]</bold></red></hover></click>"
|
received_interactive: "<gradient:#00C9FF:#92FE9D>[Guilde]</gradient> Vous avez été invité à rejoindre la guilde {guild} {tag} par <yellow>{sender}</yellow> !\n<click:run_command:'/guild join {raw_guild}'><hover:show_text:'<green>Cliquez pour accepter l''invitation et rejoindre la guilde !</green>'><green><bold>[ ✅ ACCEPTER ]</bold></green></hover></click> <click:run_command:'/guild decline {raw_guild}'><hover:show_text:'<red>Cliquez pour refuser l''invitation.</red>'><red><bold>[ ❌ REFUSER ]</bold></red></hover></click>"
|
||||||
no_pending_invite: "<red>Vous n'avez aucune invitation valide en attente pour la guilde {guild}.</red>"
|
no_pending_invite: "<red>Vous n'avez aucune invitation valide en attente pour la guilde {guild}.</red>"
|
||||||
accepted: "<green>Le joueur <white>{player}</white> a rejoint la guilde !</green>"
|
accepted_self: "<green>Vous avez rejoint la guilde {guild} {tag} !</green>"
|
||||||
declined_sender: "<yellow><white>{player}</white> a refusé votre invitation.</yellow>"
|
declined_sender: "<yellow><white>{player}</white> a refusé votre invitation.</yellow>"
|
||||||
declined_target: "<gray>Vous avez refusé l'invitation de la guilde {guild}.</gray>"
|
declined_target: "<gray>Vous avez refusé l'invitation de la guilde {guild}.</gray>"
|
||||||
|
|
||||||
@@ -65,6 +65,7 @@ guild:
|
|||||||
unclaim_no_permission: "<red>Votre rang ne vous autorise pas à abandonner des territoires.</red>"
|
unclaim_no_permission: "<red>Votre rang ne vous autorise pas à abandonner des territoires.</red>"
|
||||||
unclaim_not_owned: "<red>Ce chunk n'appartient pas à votre guilde.</red>"
|
unclaim_not_owned: "<red>Ce chunk n'appartient pas à votre guilde.</red>"
|
||||||
unclaim_last_chunk: "<red>Vous ne pouvez pas abandonner le dernier territoire de votre guilde.</red>"
|
unclaim_last_chunk: "<red>Vous ne pouvez pas abandonner le dernier territoire de votre guilde.</red>"
|
||||||
|
unclaim_confirm_prompt: "<red><bold>⚠ ATTENTION :</bold> Vous allez libérer le chunk <aqua>{world} ({chunk_x}, {chunk_z})</aqua>.\n<gold>Exécutez à nouveau <yellow>/guild unclaim</yellow> pour confirmer l'abandon du territoire.</gold></red>"
|
||||||
unclaim_success: "<yellow>Le chunk a été libéré.</yellow>"
|
unclaim_success: "<yellow>Le chunk a été libéré.</yellow>"
|
||||||
|
|
||||||
bank:
|
bank:
|
||||||
@@ -89,6 +90,38 @@ guild:
|
|||||||
empty: "<gray>Aucune guilde n'a été créée pour le moment.</gray>"
|
empty: "<gray>Aucune guilde n'a été créée pour le moment.</gray>"
|
||||||
pagination: "<click:run_command:'/guild list {prev_page}'><hover:show_text:'<yellow>Page précédente</yellow>'><aqua>[◀ Précédent]</aqua></hover></click> <dark_gray>---</dark_gray> <click:run_command:'/guild list {next_page}'><hover:show_text:'<yellow>Page suivante</yellow>'><aqua>[Suivant ▶]</aqua></hover></click>"
|
pagination: "<click:run_command:'/guild list {prev_page}'><hover:show_text:'<yellow>Page précédente</yellow>'><aqua>[◀ Précédent]</aqua></hover></click> <dark_gray>---</dark_gray> <click:run_command:'/guild list {next_page}'><hover:show_text:'<yellow>Page suivante</yellow>'><aqua>[Suivant ▶]</aqua></hover></click>"
|
||||||
|
|
||||||
|
chat:
|
||||||
|
format: "<color:{color}>[Chat Guilde] <gold>{rank}</gold> <white>{player}</white> <dark_gray>»</dark_gray> <white>{message}</white></color>"
|
||||||
|
|
||||||
|
broadcast:
|
||||||
|
member_joined: "<green><white>{player}</white> a rejoint la guilde !</green>"
|
||||||
|
member_left: "<yellow><white>{player}</white> a quitté la guilde.</yellow>"
|
||||||
|
member_kicked: "<red><white>{player}</white> a été expulsé de la guilde par <yellow>{actor}</yellow>.</red>"
|
||||||
|
chunk_claimed: "<aqua><white>{player}</white> a revendiqué un nouveau chunk ({chunk_x}, {chunk_z}) pour <yellow>{cost}</yellow> !</aqua>"
|
||||||
|
chunk_unclaimed: "<gray><white>{player}</white> a libéré le chunk ({chunk_x}, {chunk_z}).</gray>"
|
||||||
|
bank_deposit: "<green><white>{player}</white> a déposé <yellow>{amount}</yellow> dans la banque (Solde: <green>{balance}</green>).</green>"
|
||||||
|
bank_withdraw: "<yellow><white>{player}</white> a retiré <yellow>{amount}</yellow> de la banque (Solde: <green>{balance}</green>).</yellow>"
|
||||||
|
rank_changed: "<gold><white>{player}</white> a été promu/assigné au rang <yellow>{rank}</yellow> par <white>{actor}</white>.</gold>"
|
||||||
|
|
||||||
|
history:
|
||||||
|
header: "<gradient:#00C9FF:#92FE9D><bold>=== HISTORIQUE DE GUILDE ({page}/{max_page}) ===</bold></gradient>"
|
||||||
|
item: "<dark_gray>[{date}]</dark_gray> <yellow>{actor}</yellow> <dark_gray>»</dark_gray> <gray>{details}</gray>"
|
||||||
|
empty: "<gray>Aucun événement enregistré dans l'historique.</gray>"
|
||||||
|
pagination: "<click:run_command:'/guild history {prev_page}'><hover:show_text:'<yellow>Page précédente</yellow>'><aqua>[◀ Précédent]</aqua></hover></click> <dark_gray>---</dark_gray> <click:run_command:'/guild history {next_page}'><hover:show_text:'<yellow>Page suivante</yellow>'><aqua>[Suivant ▶]</aqua></hover></click>"
|
||||||
|
|
||||||
|
ranks:
|
||||||
|
header: "<gradient:#00C9FF:#92FE9D><bold>=== RANGS DE LA GUILDE ===</bold></gradient>"
|
||||||
|
item: "<gold>• {name} <dark_gray>(ID: {id}, Priorité: {priority})</dark_gray></gold>\n <gray>Permissions : <aqua>{permissions}</aqua></gray>"
|
||||||
|
created: "<green>Le rang <yellow>{name}</yellow> (ID: {id}, Priorité: {priority}) a été créé avec succès !</green>"
|
||||||
|
deleted: "<yellow>Le rang <white>{name}</white> a été supprimé.</yellow>"
|
||||||
|
perm_updated: "<green>Permission <yellow>{perm}</yellow> mise à <aqua>{state}</aqua> pour le rang <yellow>{rank}</yellow>.</green>"
|
||||||
|
no_permission: "<red>Votre rang ne vous autorise pas à gérer les rangs de la guilde.</red>"
|
||||||
|
cannot_modify_leader: "<red>Vous ne pouvez pas modifier ou supprimer le rang de Chef.</red>"
|
||||||
|
cannot_delete_default: "<red>Vous ne pouvez pas supprimer le rang par défaut des recrues.</red>"
|
||||||
|
rank_already_exists: "<red>Un rang portant l'identifiant <yellow>{id}</yellow> existe déjà.</red>"
|
||||||
|
rank_not_found: "<red>Rang introuvable avec l'ID <yellow>{id}</yellow>.</red>"
|
||||||
|
insufficient_priority: "<red>Vous ne pouvez pas créer/modifier un rang ayant une priorité supérieure ou égale à la vôtre.</red>"
|
||||||
|
|
||||||
protection:
|
protection:
|
||||||
territory_enter_own: "<gray>Territoire de guilde : </gray>{guild} {tag}"
|
territory_enter_own: "<gray>Territoire de guilde : </gray>{guild} {tag}"
|
||||||
territory_enter_other: "<gray>Territoire étranger : </gray>{guild} {tag}"
|
territory_enter_other: "<gray>Territoire étranger : </gray>{guild} {tag}"
|
||||||
@@ -104,3 +137,4 @@ protection:
|
|||||||
piston_denied: "<red>⛔ Les pistons ne peuvent pas déplacer de blocs à travers les frontières d'un territoire de guilde.</red>"
|
piston_denied: "<red>⛔ Les pistons ne peuvent pas déplacer de blocs à travers les frontières d'un territoire de guilde.</red>"
|
||||||
fluid_denied: "<red>⛔ L'écoulement de fluides vers un territoire protégé est bloqué.</red>"
|
fluid_denied: "<red>⛔ L'écoulement de fluides vers un territoire protégé est bloqué.</red>"
|
||||||
hanging_denied: "<red>⛔ Vous ne pouvez pas modifier ou casser les entités de décoration dans ce territoire.</red>"
|
hanging_denied: "<red>⛔ Vous ne pouvez pas modifier ou casser les entités de décoration dans ce territoire.</red>"
|
||||||
|
fire_denied: "<red>🔥 La propagation du feu et la combustion des blocs sont désactivées sur les territoires protégés.</red>"
|
||||||
|
|||||||
Reference in New Issue
Block a user