feat(worldguard): integrate WorldGuard 7 cuboid claims with automatic member synchronization

This commit is contained in:
2026-08-20 18:35:23 +02:00
parent 7637412b1d
commit ff810608b3
4 changed files with 342 additions and 14 deletions
+19 -6
View File
@@ -31,6 +31,7 @@ public final class Main extends JavaPlugin {
private DatabaseManager databaseManager; private DatabaseManager databaseManager;
private GuildRepository guildRepository; private GuildRepository guildRepository;
private EconomyManager economyManager; private EconomyManager economyManager;
private fr.luc.gamingcore.worldguard.WorldGuardManager worldGuardManager;
private GuildManager guildManager; private GuildManager guildManager;
private BetterMcCommands betterMcCommands; private BetterMcCommands betterMcCommands;
@@ -50,24 +51,27 @@ public final class Main extends JavaPlugin {
setupWorldGuard(); setupWorldGuard();
setupEconomy(); setupEconomy();
// 3. Initialiser la couche de données SQLite // 3. Initialiser le gestionnaire WorldGuard
this.worldGuardManager = new fr.luc.gamingcore.worldguard.WorldGuardManager(this);
// 4. Initialiser la couche de données SQLite
this.databaseManager = new DatabaseManager(this); this.databaseManager = new DatabaseManager(this);
this.databaseManager.initialize(); this.databaseManager.initialize();
this.guildRepository = new GuildRepository(this, databaseManager); this.guildRepository = new GuildRepository(this, databaseManager);
// 4. Initialiser la couche économique // 5. Initialiser la couche économique
this.economyManager = new EconomyManager(this); this.economyManager = new EconomyManager(this);
// 5. Initialiser le service métier GuildManager et charger les données // 6. Initialiser le service métier GuildManager et charger les données
this.guildManager = new GuildManager(this, guildRepository, economyManager); this.guildManager = new GuildManager(this, guildRepository, economyManager, worldGuardManager);
loadConfigSettings(); loadConfigSettings();
this.guildManager.loadData(); this.guildManager.loadData();
// 6. Initialiser le framework betterMcCommands et enregistrer les commandes // 7. Initialiser le framework betterMcCommands et enregistrer les commandes
this.betterMcCommands = BetterMcCommands.create(this); this.betterMcCommands = BetterMcCommands.create(this);
new GuildCommands(this, guildManager).register(); new GuildCommands(this, guildManager).register();
// 7. 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);
@@ -216,6 +220,15 @@ public final class Main extends JavaPlugin {
return databaseManager; return databaseManager;
} }
/**
* Obtient le gestionnaire WorldGuard.
*
* @return L'instance WorldGuardManager.
*/
public fr.luc.gamingcore.worldguard.WorldGuardManager getWorldGuardManager() {
return worldGuardManager;
}
/** /**
* Obtient le référentiel de persistance des guildes. * Obtient le référentiel de persistance des guildes.
* *
@@ -24,6 +24,7 @@ public class GuildManager {
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 ChunkPriceCalculator priceCalculator; private final ChunkPriceCalculator priceCalculator;
private final InviteManager inviteManager; private final InviteManager inviteManager;
@@ -34,22 +35,35 @@ public class GuildManager {
private final Map<String, UUID> chunkGuildMap = new ConcurrentHashMap<>(); private final Map<String, UUID> chunkGuildMap = new ConcurrentHashMap<>();
/** /**
* Constructeur du GuildManager. * Constructeur complet du GuildManager avec WorldGuardManager.
*
* @param plugin Instance du plugin principal.
* @param repository Référentiel de persistance des données.
* @param economyManager Gestionnaire de l'économie Vault.
* @param worldGuardManager Gestionnaire des régions WorldGuard.
*/
public GuildManager(Main plugin, GuildRepository repository, EconomyManager economyManager, fr.luc.gamingcore.worldguard.WorldGuardManager worldGuardManager) {
this.plugin = plugin;
this.repository = repository;
this.economyManager = economyManager;
this.worldGuardManager = worldGuardManager;
this.priceCalculator = new ChunkPriceCalculator();
this.inviteManager = new InviteManager();
}
/**
* Constructeur de compatibilité du GuildManager.
* *
* @param plugin Instance du plugin principal. * @param plugin Instance du plugin principal.
* @param repository Référentiel de persistance des données. * @param repository Référentiel de persistance des données.
* @param economyManager Gestionnaire de l'économie Vault. * @param economyManager Gestionnaire de l'économie Vault.
*/ */
public GuildManager(Main plugin, GuildRepository repository, EconomyManager economyManager) { public GuildManager(Main plugin, GuildRepository repository, EconomyManager economyManager) {
this.plugin = plugin; this(plugin, repository, economyManager, null);
this.repository = repository;
this.economyManager = economyManager;
this.priceCalculator = new ChunkPriceCalculator();
this.inviteManager = new InviteManager();
} }
/** /**
* Charge l'ensemble des données de la base en mémoire et reconstruit les index de recherche. * 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();
@@ -62,6 +76,10 @@ public class GuildManager {
indexGuild(guild); indexGuild(guild);
} }
if (worldGuardManager != null) {
worldGuardManager.syncAllGuilds(guildsById.values());
}
plugin.getLogger().info("Charges " + guildsById.size() + " guildes (" + playerGuildMap.size() + " membres, " + chunkGuildMap.size() + " claims)."); plugin.getLogger().info("Charges " + guildsById.size() + " guildes (" + playerGuildMap.size() + " membres, " + chunkGuildMap.size() + " claims).");
} }
@@ -183,6 +201,11 @@ public class GuildManager {
repository.saveMemberAsync(founder); repository.saveMemberAsync(founder);
repository.saveClaimAsync(initialClaim); repository.saveClaimAsync(initialClaim);
// 11. Créer la région WorldGuard
if (worldGuardManager != null) {
worldGuardManager.createOrUpdateRegion(guild, loc.getWorld(), chunkX, chunkZ);
}
return GuildResult.success("La guilde <white><bold>" + name + "</bold></white> a été créée avec succès !"); return GuildResult.success("La guilde <white><bold>" + name + "</bold></white> a été créée avec succès !");
} }
@@ -210,6 +233,11 @@ 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
if (worldGuardManager != null) {
worldGuardManager.removeGuildRegions(guild);
}
// Désindexer la guilde // Désindexer la guilde
unindexGuild(guild); unindexGuild(guild);
@@ -249,6 +277,11 @@ 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) {
worldGuardManager.syncGuildMembers(guild);
}
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 !");
} }
@@ -288,6 +321,11 @@ public class GuildManager {
playerGuildMap.remove(targetUuid); playerGuildMap.remove(targetUuid);
repository.deleteMemberAsync(targetUuid); repository.deleteMemberAsync(targetUuid);
// Synchroniser WorldGuard
if (worldGuardManager != null) {
worldGuardManager.syncGuildMembers(guild);
}
return GuildResult.success("Le membre a été expulsé de la guilde."); return GuildResult.success("Le membre a été expulsé de la guilde.");
} }
@@ -317,6 +355,11 @@ public class GuildManager {
playerGuildMap.remove(player.getUniqueId()); playerGuildMap.remove(player.getUniqueId());
repository.deleteMemberAsync(player.getUniqueId()); repository.deleteMemberAsync(player.getUniqueId());
// Synchroniser WorldGuard
if (worldGuardManager != null) {
worldGuardManager.syncGuildMembers(guild);
}
return GuildResult.success("Vous avez quitté la guilde."); return GuildResult.success("Vous avez quitté la guilde.");
} }
@@ -370,6 +413,11 @@ 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) {
worldGuardManager.syncGuildMembers(guild);
}
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>.");
} }
@@ -480,6 +528,11 @@ public class GuildManager {
repository.saveGuildAsync(guild); repository.saveGuildAsync(guild);
repository.saveClaimAsync(claim); repository.saveClaimAsync(claim);
// 7. Créer la région WorldGuard
if (worldGuardManager != null) {
worldGuardManager.createOrUpdateRegion(guild, world, chunkX, chunkZ);
}
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)");
} }
@@ -515,7 +568,12 @@ public class GuildManager {
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 le claim // 4. Supprimer la région WorldGuard
if (worldGuardManager != null) {
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);
@@ -646,6 +704,10 @@ public class GuildManager {
return inviteManager; return inviteManager;
} }
public fr.luc.gamingcore.worldguard.WorldGuardManager getWorldGuardManager() {
return worldGuardManager;
}
// ========================================== // ==========================================
// MÉTHODES INTERNES D'INDEXATION // MÉTHODES INTERNES D'INDEXATION
// ========================================== // ==========================================
@@ -0,0 +1,241 @@
package fr.luc.gamingcore.worldguard;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import fr.luc.gamingcore.Main;
import fr.luc.gamingcore.model.Guild;
import fr.luc.gamingcore.model.GuildClaim;
import fr.luc.gamingcore.model.GuildMember;
import org.bukkit.Bukkit;
import org.bukkit.World;
import java.util.Collection;
import java.util.Objects;
import java.util.logging.Level;
/**
* Service d'intégration avec WorldGuard 7 pour la création, la protection et la synchronisation des régions de claim.
*/
public class WorldGuardManager {
private final Main plugin;
private final RegionContainer regionContainer;
private final boolean enabled;
/**
* Constructeur du WorldGuardManager.
*
* @param plugin L'instance principale de GamingCore.
*/
public WorldGuardManager(Main plugin) {
this.plugin = Objects.requireNonNull(plugin, "plugin cannot be null");
RegionContainer container = null;
boolean isEnabled = false;
try {
if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null) {
container = WorldGuard.getInstance().getPlatform().getRegionContainer();
isEnabled = (container != null);
}
} catch (Throwable t) {
plugin.getLogger().log(Level.WARNING, "Erreur lors de l'initialisation de WorldGuardManager : " + t.getMessage());
}
this.regionContainer = container;
this.enabled = isEnabled;
}
/**
* Indique si l'intégration WorldGuard est active.
*
* @return true si WorldGuard est chargé et fonctionnel.
*/
public boolean isEnabled() {
return enabled && regionContainer != null;
}
/**
* Génère l'identifiant unique WorldGuard d'une région de claim pour un chunk donné.
*
* @param guild La guilde propriétaire.
* @param chunkX Coordonnée X du chunk.
* @param chunkZ Coordonnée Z du chunk.
* @return L'identifiant normalisé de la région (ex: "guild_a1b2c3d4_12_-4").
*/
public String getRegionId(Guild guild, int chunkX, int chunkZ) {
String cleanId = guild.getId().toString().replace("-", "").substring(0, 12);
return "guild_" + cleanId + "_" + chunkX + "_" + chunkZ;
}
/**
* Obtient le gestionnaire de régions WorldGuard pour un monde Bukkit donné.
*
* @param world Le monde Bukkit.
* @return L'instance RegionManager ou null si indisponible.
*/
public RegionManager getRegionManager(World world) {
if (!isEnabled() || world == null) return null;
return regionContainer.get(BukkitAdapter.adapt(world));
}
/**
* Crée ou met à jour la région WorldGuard associée à un claim territorial de guilde.
* Les membres de la guilde sont enregistrés en tant que membres de la région (permettant la pose/casse de blocs et l'ouverture de coffres).
*
* @param guild La guilde propriétaire.
* @param world Le monde Bukkit dans lequel se situe le claim.
* @param chunkX Coordonnée X du chunk.
* @param chunkZ Coordonnée Z du chunk.
* @return La région protégée créée ou mise à jour, ou null en cas d'échec.
*/
public ProtectedRegion createOrUpdateRegion(Guild guild, World world, int chunkX, int chunkZ) {
if (!isEnabled() || guild == null || world == null) return null;
RegionManager regionManager = getRegionManager(world);
if (regionManager == null) return null;
String regionId = getRegionId(guild, chunkX, chunkZ);
ProtectedRegion region = regionManager.getRegion(regionId);
int minX = chunkX * 16;
int minZ = chunkZ * 16;
int maxX = minX + 15;
int maxZ = minZ + 15;
int minY = world.getMinHeight();
int maxY = world.getMaxHeight() - 1;
BlockVector3 min = BlockVector3.at(minX, minY, minZ);
BlockVector3 max = BlockVector3.at(maxX, maxY, maxZ);
if (region == null) {
region = new ProtectedCuboidRegion(regionId, min, max);
region.setPriority(plugin.getConfig().getInt("worldguard.region_priority", 10));
// Flags WorldGuard
region.setFlag(Flags.PASSTHROUGH, StateFlag.State.DENY);
region.setFlag(Flags.TNT, StateFlag.State.DENY);
region.setFlag(Flags.CREEPER_EXPLOSION, StateFlag.State.DENY);
region.setFlag(Flags.PVP, StateFlag.State.ALLOW);
regionManager.addRegion(region);
}
// Synchroniser les membres et propriétaires
syncRegionMembers(guild, region);
return region;
}
/**
* Supprime la région WorldGuard correspondant à un chunk précis.
*
* @param guild La guilde propriétaire.
* @param world Le monde du chunk.
* @param chunkX Coordonnée X.
* @param chunkZ Coordonnée Z.
* @return true si la région a été supprimée.
*/
public boolean removeRegion(Guild guild, World world, int chunkX, int chunkZ) {
if (!isEnabled() || guild == null || world == null) return false;
RegionManager regionManager = getRegionManager(world);
if (regionManager == null) return false;
String regionId = getRegionId(guild, chunkX, chunkZ);
return regionManager.removeRegion(regionId) != null;
}
/**
* Supprime toutes les régions WorldGuard appartenant à une guilde dans tous les mondes (utilisé lors du disband).
*
* @param guild La guilde dissoute.
*/
public void removeGuildRegions(Guild guild) {
if (!isEnabled() || guild == null) return;
for (GuildClaim claim : guild.getClaims()) {
World world = Bukkit.getWorld(claim.getWorldName());
if (world != null) {
removeRegion(guild, world, claim.getChunkX(), claim.getChunkZ());
}
}
}
/**
* Synchronise la liste des membres et propriétaires sur toutes les régions WorldGuard d'une guilde.
* Doit être appelée à chaque ajout, retrait ou modification de membre.
*
* @param guild La guilde à synchroniser.
*/
public void syncGuildMembers(Guild guild) {
if (!isEnabled() || guild == null) return;
for (GuildClaim claim : guild.getClaims()) {
World world = Bukkit.getWorld(claim.getWorldName());
if (world == null) continue;
RegionManager regionManager = getRegionManager(world);
if (regionManager == null) continue;
String regionId = getRegionId(guild, claim.getChunkX(), claim.getChunkZ());
ProtectedRegion region = regionManager.getRegion(regionId);
if (region == null) {
// Si la région n'existe pas encore, la créer
createOrUpdateRegion(guild, world, claim.getChunkX(), claim.getChunkZ());
} else {
syncRegionMembers(guild, region);
}
}
}
/**
* Synchronise tous les claims et membres de l'intégralité des guildes dans WorldGuard au démarrage du serveur.
*
* @param guilds Collection des guildes chargées en mémoire.
*/
public void syncAllGuilds(Collection<Guild> guilds) {
if (!isEnabled() || guilds == null) return;
int totalRegions = 0;
for (Guild guild : guilds) {
for (GuildClaim claim : guild.getClaims()) {
World world = Bukkit.getWorld(claim.getWorldName());
if (world != null) {
createOrUpdateRegion(guild, world, claim.getChunkX(), claim.getChunkZ());
totalRegions++;
}
}
}
plugin.getLogger().info("WorldGuard: Synchronisation de " + totalRegions + " regions territoriales de guilde terminee avec succes !");
}
/**
* Met à jour les domaines de membres et d'owners d'une région WorldGuard à partir de la guilde.
*
* @param guild La guilde source.
* @param region La région WorldGuard cible.
*/
private void syncRegionMembers(Guild guild, ProtectedRegion region) {
// 1. Mise à jour des propriétaires (Chef de guilde)
region.getOwners().clear();
GuildMember leader = guild.getLeaderMember();
if (leader != null) {
region.getOwners().addPlayer(leader.getPlayerUuid());
}
// 2. Mise à jour des membres (Tous les membres de la guilde)
region.getMembers().clear();
for (GuildMember member : guild.getMembers()) {
region.getMembers().addPlayer(member.getPlayerUuid());
}
}
}
@@ -57,4 +57,16 @@ public class GuildModelTest {
assertFalse(guild.hasPermission(memberUuid, GuildPermission.CLAIM)); assertFalse(guild.hasPermission(memberUuid, GuildPermission.CLAIM));
assertFalse(guild.hasPermission(memberUuid, GuildPermission.BANK_WITHDRAW)); assertFalse(guild.hasPermission(memberUuid, GuildPermission.BANK_WITHDRAW));
} }
@Test
public void testGuildColorAndTagFormatting() {
assertEquals("#00C9FF", guild.getColor());
assertEquals("<color:#00C9FF>[VAL]</color>", guild.getFormattedTag());
assertEquals("<color:#00C9FF><bold>Valhalla</bold></color>", guild.getFormattedName());
guild.setColor("#FF5555");
guild.setTag("VALH");
assertEquals("#FF5555", guild.getColor());
assertEquals("<color:#FF5555>[VALH]</color>", guild.getFormattedTag());
}
} }