diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index f95f1ee80..000000000 --- a/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -wrapperVersion=3.3.2 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip diff --git a/co/aikar/commands/annotations.xml b/co/aikar/commands/annotations.xml deleted file mode 100644 index 7a662ec6e..000000000 --- a/co/aikar/commands/annotations.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/org/bukkit/configuration/annotations.xml b/org/bukkit/configuration/annotations.xml deleted file mode 100644 index 2e2c43ac6..000000000 --- a/org/bukkit/configuration/annotations.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index d5a110ed5..8aaf30ce3 100644 --- a/pom.xml +++ b/pom.xml @@ -208,7 +208,7 @@ me.clip placeholderapi - 2.11.3 + 2.11.7 provided diff --git a/src/main/java/net/sacredlabyrinth/phaed/simpleclans/listeners/SCPlayerListener.java b/src/main/java/net/sacredlabyrinth/phaed/simpleclans/listeners/SCPlayerListener.java index 09f871a15..0c1a53687 100644 --- a/src/main/java/net/sacredlabyrinth/phaed/simpleclans/listeners/SCPlayerListener.java +++ b/src/main/java/net/sacredlabyrinth/phaed/simpleclans/listeners/SCPlayerListener.java @@ -174,26 +174,14 @@ private void registerChatListener() { } private void updatePlayerName(@NotNull final Player player) { + // Update in-memory ClanPlayer if exists final ClanPlayer cp = plugin.getClanManager().getAnyClanPlayer(player.getUniqueId()); - - ClanPlayer duplicate = null; - for (ClanPlayer other : plugin.getClanManager().getAllClanPlayers()) { - if (other.getName().equals(player.getName()) && !other.getUniqueId().equals(player.getUniqueId())) { - duplicate = other; - break; - } - } - - if (duplicate != null) { - plugin.getLogger().warning(String.format("Found duplicate for %s, UUIDs: %s, %s", player.getName(), - player.getUniqueId(), duplicate.getUniqueId())); - duplicate.setName(duplicate.getUniqueId().toString()); - plugin.getStorageManager().updatePlayerName(duplicate); - } if (cp != null) { cp.setName(player.getName()); - plugin.getStorageManager().updatePlayerName(cp); } + + // Synchronize player data in database asynchronously + plugin.getStorageManager().syncPlayerDataAsync(player); } -} +} \ No newline at end of file diff --git a/src/main/java/net/sacredlabyrinth/phaed/simpleclans/managers/StorageManager.java b/src/main/java/net/sacredlabyrinth/phaed/simpleclans/managers/StorageManager.java index b218311cd..e9b0d5d4e 100644 --- a/src/main/java/net/sacredlabyrinth/phaed/simpleclans/managers/StorageManager.java +++ b/src/main/java/net/sacredlabyrinth/phaed/simpleclans/managers/StorageManager.java @@ -10,6 +10,7 @@ import net.sacredlabyrinth.phaed.simpleclans.utils.ChatUtils; import net.sacredlabyrinth.phaed.simpleclans.utils.YAMLSerializer; import net.sacredlabyrinth.phaed.simpleclans.uuid.UUIDFetcher; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -60,8 +61,8 @@ public StorageManager() { * @param player the Player * @return the ChatBlock */ - public ChatBlock getChatBlock(Player player) { - return chatBlocks.get(player.getName()); + public ChatBlock getChatBlock(@NotNull Player player) { + return chatBlocks.get(player.getName()); } /** @@ -69,7 +70,7 @@ public ChatBlock getChatBlock(Player player) { * */ public void addChatBlock(CommandSender player, ChatBlock cb) { - chatBlocks.put(player.getName(), cb); + chatBlocks.put(player.getName(), cb); } /** @@ -101,13 +102,13 @@ public void initiateDB() { + " `packed_bb` mediumtext NOT NULL," + " `cape_url` varchar(255) NOT NULL," + " `flags` text NOT NULL," - + " `balance` double(64,2)," - + " `fee_enabled` tinyint(1) default '0'," - + " `fee_value` double(64,2)," - + " `ranks` text NOT NULL," + + " `balance` double(64,2)," + + " `fee_enabled` tinyint(1) default '0'," + + " `fee_value` double(64,2)," + + " `ranks` text NOT NULL," + " `banner` text," - + " PRIMARY KEY (`id`)," - + " UNIQUE KEY `uq_simpleclans_1` (`tag`));"; + + " PRIMARY KEY (`id`)," + + " UNIQUE KEY `uq_simpleclans_1` (`tag`));"; core.execute(query); } @@ -115,25 +116,25 @@ public void initiateDB() { plugin.getLogger().info("Creating table: " + getPrefixedTable("players")); String query = "CREATE TABLE IF NOT EXISTS `" + getPrefixedTable("players") + "` (" - + " `id` bigint(20) NOT NULL auto_increment," - + " `name` varchar(16) NOT NULL," - + " `leader` tinyint(1) default '0'," - + " `tag` varchar(25) NOT NULL," - + " `friendly_fire` tinyint(1) default '0'," - + " `neutral_kills` int(11) default NULL," - + " `rival_kills` int(11) default NULL," - + " `civilian_kills` int(11) default NULL," + + " `id` bigint(20) NOT NULL auto_increment," + + " `name` varchar(16) NOT NULL," + + " `leader` tinyint(1) default '0'," + + " `tag` varchar(25) NOT NULL," + + " `friendly_fire` tinyint(1) default '0'," + + " `neutral_kills` int(11) default NULL," + + " `rival_kills` int(11) default NULL," + + " `civilian_kills` int(11) default NULL," + " `ally_kills` int(11) default NULL," - + " `deaths` int(11) default NULL," - + " `last_seen` bigint NOT NULL," - + " `join_date` bigint NOT NULL," - + " `trusted` tinyint(1) default '0'," - + " `flags` text NOT NULL," - + " `packed_past_clans` text," - + " `resign_times` text," + + " `deaths` int(11) default NULL," + + " `last_seen` bigint NOT NULL," + + " `join_date` bigint NOT NULL," + + " `trusted` tinyint(1) default '0'," + + " `flags` text NOT NULL," + + " `packed_past_clans` text," + + " `resign_times` text," + " `locale` varchar(10)," - + " PRIMARY KEY (`id`)," - + " UNIQUE KEY `uq_sc_players_1` (`name`));"; + + " PRIMARY KEY (`id`)," + + " UNIQUE KEY `uq_sc_players_1` (`name`));"; core.execute(query); } @@ -141,14 +142,14 @@ public void initiateDB() { plugin.getLogger().info("Creating table: " + getPrefixedTable("kills")); String query = "CREATE TABLE IF NOT EXISTS `" + getPrefixedTable("kills") + "` (" - + " `kill_id` bigint(20) NOT NULL auto_increment," - + " `attacker` varchar(16) NOT NULL," - + " `attacker_tag` varchar(16) NOT NULL," - + " `victim` varchar(16) NOT NULL," - + " `victim_tag` varchar(16) NOT NULL," - + " `kill_type` varchar(1) NOT NULL," + + " `kill_id` bigint(20) NOT NULL auto_increment," + + " `attacker` varchar(16) NOT NULL," + + " `attacker_tag` varchar(16) NOT NULL," + + " `victim` varchar(16) NOT NULL," + + " `victim_tag` varchar(16) NOT NULL," + + " `kill_type` varchar(1) NOT NULL," + " `created_at` datetime NULL," - + " PRIMARY KEY (`kill_id`));"; + + " PRIMARY KEY (`kill_id`));"; core.execute(query); } } else { @@ -159,7 +160,7 @@ public void initiateDB() { if (core.checkConnection()) { - plugin.getLogger().info(lang("sqlite.connection.successful")); + plugin.getLogger().info(lang("sqlite.connection.successful")); if (!core.existsTable(getPrefixedTable("clans"))) { plugin.getLogger().info("Creating table: " + getPrefixedTable("clans")); @@ -179,13 +180,13 @@ public void initiateDB() { + " `packed_bb` mediumtext NOT NULL," + " `cape_url` varchar(255) NOT NULL," + " `flags` text NOT NULL," - + " `balance` double(64,2) default 0.0," - + " `fee_enabled` tinyint(1) default '0'," - + " `fee_value` double(64,2)," - + " `ranks` text NOT NULL," + + " `balance` double(64,2) default 0.0," + + " `fee_enabled` tinyint(1) default '0'," + + " `fee_value` double(64,2)," + + " `ranks` text NOT NULL," + " `banner` text," - + " PRIMARY KEY (`id`)," - + " UNIQUE (`tag`));"; + + " PRIMARY KEY (`id`)," + + " UNIQUE (`tag`));"; core.execute(query); } @@ -193,25 +194,25 @@ public void initiateDB() { plugin.getLogger().info("Creating table: " + getPrefixedTable("players")); String query = "CREATE TABLE IF NOT EXISTS `" + getPrefixedTable("players") + "` (" - + " `id` bigint(20)," - + " `name` varchar(16) NOT NULL," - + " `leader` tinyint(1) default '0'," - + " `tag` varchar(25) NOT NULL," - + " `friendly_fire` tinyint(1) default '0'," - + " `neutral_kills` int(11) default NULL," - + " `rival_kills` int(11) default NULL," - + " `civilian_kills` int(11) default NULL," + + " `id` bigint(20)," + + " `name` varchar(16) NOT NULL," + + " `leader` tinyint(1) default '0'," + + " `tag` varchar(25) NOT NULL," + + " `friendly_fire` tinyint(1) default '0'," + + " `neutral_kills` int(11) default NULL," + + " `rival_kills` int(11) default NULL," + + " `civilian_kills` int(11) default NULL," + " `ally_kills` int(11) default NULL," - + " `deaths` int(11) default NULL," - + " `last_seen` bigint NOT NULL," - + " `join_date` bigint NOT NULL," - + " `trusted` tinyint(1) default '0'," - + " `flags` text NOT NULL," - + " `packed_past_clans` text," - + " `resign_times` text," + + " `deaths` int(11) default NULL," + + " `last_seen` bigint NOT NULL," + + " `join_date` bigint NOT NULL," + + " `trusted` tinyint(1) default '0'," + + " `flags` text NOT NULL," + + " `packed_past_clans` text," + + " `resign_times` text," + " `locale` varchar(10)," - + " PRIMARY KEY (`id`)," - + " UNIQUE (`name`));"; + + " PRIMARY KEY (`id`)," + + " UNIQUE (`name`));"; core.execute(query); } @@ -219,14 +220,14 @@ public void initiateDB() { plugin.getLogger().info("Creating table: " + getPrefixedTable("kills")); String query = "CREATE TABLE IF NOT EXISTS `" + getPrefixedTable("kills") + "` (" - + " `kill_id` bigint(20)," - + " `attacker` varchar(16) NOT NULL," - + " `attacker_tag` varchar(16) NOT NULL," - + " `victim` varchar(16) NOT NULL," - + " `victim_tag` varchar(16) NOT NULL," - + " `kill_type` varchar(1) NOT NULL," + + " `kill_id` bigint(20)," + + " `attacker` varchar(16) NOT NULL," + + " `attacker_tag` varchar(16) NOT NULL," + + " `victim` varchar(16) NOT NULL," + + " `victim_tag` varchar(16) NOT NULL," + + " `kill_type` varchar(1) NOT NULL," + " `created_at` datetime NULL," - + " PRIMARY KEY (`kill_id`));"; + + " PRIMARY KEY (`kill_id`));"; core.execute(query); } } else { @@ -260,7 +261,7 @@ public void importFromDatabase() { } if (!clans.isEmpty()) { - plugin.getLogger().info(MessageFormat.format(lang("clans"), clans.size())); + plugin.getLogger().info(MessageFormat.format(lang("clans"), clans.size())); } List cps = retrieveClanPlayers(); @@ -276,7 +277,7 @@ public void importFromDatabase() { } if (!cps.isEmpty()) { - plugin.getLogger().info(MessageFormat.format(lang("clan.players"), cps.size())); + plugin.getLogger().info(MessageFormat.format(lang("clan.players"), cps.size())); } } @@ -324,7 +325,7 @@ private void purgeClans(List clans) { } for (Clan clan : purge) { - plugin.getLogger().info(lang("purging.clan", clan.getName())); + plugin.getLogger().info(lang("purging.clan", clan.getName())); for (ClanPlayer member : clan.getMembers()) { clan.removePlayerFromClan(member.getUniqueId()); } @@ -351,7 +352,7 @@ private void purgeClanPlayers(List cps) { } for (ClanPlayer cp : purge) { - plugin.getLogger().info(lang("purging.player.data", cp.getName())); + plugin.getLogger().info(lang("purging.player.data", cp.getName())); deleteClanPlayer(cp); cps.remove(cp); } @@ -687,28 +688,8 @@ public List retrieveClanPlayers() { public void insertClan(Clan clan) { plugin.getProxyManager().sendUpdate(clan); - String query = "INSERT INTO `" + getPrefixedTable("clans") + "` (`banner`, `ranks`, `description`, `fee_enabled`, `fee_value`, `verified`, `tag`," + - " `color_tag`, `name`, `friendly_fire`, `founded`, `last_used`, `packed_allies`, `packed_rivals`, " + - "`packed_bb`, `cape_url`, `flags`, `balance`) "; - String values = "VALUES ( '" - + Helper.escapeQuotes(YAMLSerializer.serialize(clan.getBanner())) + "','" - + Helper.escapeQuotes(Helper.ranksToJson(clan.getRanks(), clan.getDefaultRank())) + "','" - + Helper.escapeQuotes(clan.getDescription())+ "'," - + (clan.isMemberFeeEnabled() ? 1 : 0) +"," - + Helper.escapeQuotes(String.valueOf(clan.getMemberFee())) + "," - + (clan.isVerified() ? 1 : 0) + ",'" - + Helper.escapeQuotes(clan.getTag()) + "','" - + Helper.escapeQuotes(clan.getColorTag()) + "','" - + Helper.escapeQuotes(clan.getName()) + "'," - + (clan.isFriendlyFire() ? 1 : 0) + ",'" - + clan.getFounded() + "','" - + clan.getLastUsed() + "','" - + Helper.escapeQuotes(clan.getPackedAllies()) + "','" - + Helper.escapeQuotes(clan.getPackedRivals()) + "','" - + Helper.escapeQuotes(clan.getPackedBb()) + "','" - + Helper.escapeQuotes(clan.getCapeUrl()) + "','" - + Helper.escapeQuotes(clan.getFlags()) + "','" - + Helper.escapeQuotes(String.valueOf(clan.getBalance())) + "');"; + String query = "INSERT INTO `" + getPrefixedTable("clans") + "` (`banner`, `ranks`, `description`, `fee_enabled`, `fee_value`, `verified`, `tag`," + " `color_tag`, `name`, `friendly_fire`, `founded`, `last_used`, `packed_allies`, `packed_rivals`, " + "`packed_bb`, `cape_url`, `flags`, `balance`) "; + String values = "VALUES ( '" + Helper.escapeQuotes(YAMLSerializer.serialize(clan.getBanner())) + "','" + Helper.escapeQuotes(Helper.ranksToJson(clan.getRanks(), clan.getDefaultRank())) + "','" + Helper.escapeQuotes(clan.getDescription()) + "'," + (clan.isMemberFeeEnabled() ? 1 : 0) + "," + Helper.escapeQuotes(String.valueOf(clan.getMemberFee())) + "," + (clan.isVerified() ? 1 : 0) + ",'" + Helper.escapeQuotes(clan.getTag()) + "','" + Helper.escapeQuotes(clan.getColorTag()) + "','" + Helper.escapeQuotes(clan.getName()) + "'," + (clan.isFriendlyFire() ? 1 : 0) + ",'" + clan.getFounded() + "','" + clan.getLastUsed() + "','" + Helper.escapeQuotes(clan.getPackedAllies()) + "','" + Helper.escapeQuotes(clan.getPackedRivals()) + "','" + Helper.escapeQuotes(clan.getPackedBb()) + "','" + Helper.escapeQuotes(clan.getCapeUrl()) + "','" + Helper.escapeQuotes(clan.getFlags()) + "','" + Helper.escapeQuotes(String.valueOf(clan.getBalance())) + "');"; core.executeUpdate(query + values); } @@ -732,19 +713,256 @@ public void run() { * @param cp to update */ public void updatePlayerNameAsync(final @NotNull ClanPlayer cp) { - new BukkitRunnable() { - @Override - public void run() { + new BukkitRunnable() { + @Override + public void run() { updatePlayerName(cp); - } - }.runTaskAsynchronously(plugin); + } + }.runTaskAsynchronously(plugin); + } + + /** + * Retrieves a clan player from the database by name + * + * @param name the player name to search for + * @return the ClanPlayer if found, null otherwise + */ + public @Nullable ClanPlayer retrieveClanPlayerByName(String name) { + if (name == null || name.trim().isEmpty()) { + return null; + } + String query = "SELECT * FROM `" + getPrefixedTable("players") + "` WHERE `name` = ?;"; + try (Connection connection = core.getConnection(); + PreparedStatement ps = connection.prepareStatement(query)) { + ps.setString(1, name); + try (ResultSet res = ps.executeQuery()) { + if (res.next()) { + return buildClanPlayerFromResultSet(res); + } + } + } catch (SQLException ex) { + plugin.getLogger().log(Level.SEVERE, "Error retrieving ClanPlayer by name: " + name, ex); + } + return null; + } + + /** + * Helper method to build a ClanPlayer from a ResultSet + */ + private ClanPlayer buildClanPlayerFromResultSet(ResultSet res) throws SQLException { + String uuid = res.getString("uuid"); + String name = res.getString("name"); + String tagStr = res.getString("tag"); + boolean leader = res.getBoolean("leader"); + boolean friendly_fire = res.getBoolean("friendly_fire"); + boolean trusted = res.getBoolean("trusted"); + int neutral_kills = res.getInt("neutral_kills"); + int rival_kills = res.getInt("rival_kills"); + int civilian_kills = res.getInt("civilian_kills"); + int ally_kills = res.getInt("ally_kills"); + int deaths = res.getInt("deaths"); + long last_seen = res.getLong("last_seen"); + long join_date = res.getLong("join_date"); + String flags = res.getString("flags"); + String packed_past_clans = res.getString("packed_past_clans"); + String resign_times = res.getString("resign_times"); + Locale locale = Helper.forLanguageTag(res.getString("locale")); + + if (last_seen == 0) { + last_seen = (new Date()).getTime(); + } + + ClanPlayer cp = new ClanPlayer(); + if (uuid != null) { + cp.setUniqueId(UUID.fromString(uuid)); + } + cp.setFlags(flags); + cp.setName(name); + cp.setLeader(leader); + cp.setFriendlyFire(friendly_fire); + cp.setNeutralKills(neutral_kills); + cp.setRivalKills(rival_kills); + cp.setCivilianKills(civilian_kills); + cp.setAllyKills(ally_kills); + cp.setDeaths(deaths); + cp.setLastSeen(last_seen); + cp.setJoinDate(join_date); + cp.setPackedPastClans(packed_past_clans); + cp.setTrusted(leader || trusted); + cp.setResignTimes(Helper.resignTimesFromJson(resign_times)); + cp.setLocale(locale); + + // Set clan relationship if tag exists + if (tagStr != null && !tagStr.isEmpty()) { + Clan clan = plugin.getClanManager().getClan(tagStr); + if (clan != null) { + cp.setClan(clan); + } + } + + return cp; + } + + /** + * Synchronizes player data in the database asynchronously, handling duplicates + * + * @param player the player to sync + */ + public void syncPlayerDataAsync(@NotNull Player player) { + final String currentName = player.getName(); + final UUID currentUuid = player.getUniqueId(); + new BukkitRunnable() { + @Override + public void run() { + syncPlayerData(currentName, currentUuid); + } + }.runTaskAsynchronously(plugin); + } + + /** + * Synchronizes player data in the database, handling duplicates + * - If name differs but UUID matches: update name + * - If names match but UUIDs differ: update UUID + * - If both name and UUID exist in different records: merge and delete duplicates + * + * @param currentName the player's current name + * @param currentUuid the player's current UUID + */ + private void syncPlayerData(@NotNull String currentName, @NotNull UUID currentUuid) { + try { + ClanPlayer byName = retrieveClanPlayerByName(currentName); + ClanPlayer byUuid = retrieveOneClanPlayer(currentUuid); + + // Case 1: Found by name only, UUID differs - update UUID + if (byName != null && byUuid == null) { + plugin.getLogger().warning(String.format("Correcting UUID for %s: %s → %s", byName.getName(), byName.getUniqueId(), currentUuid)); + + UUID oldUuid = byName.getUniqueId(); + + // Update UUID in database directly + String updateQuery = "UPDATE `" + getPrefixedTable("players") + "` SET `uuid` = ?, `name` = ?, `last_seen` = ? WHERE uuid = ?;"; + try (Connection conn = core.getConnection(); + PreparedStatement ps = conn.prepareStatement(updateQuery)) { + ps.setString(1, currentUuid.toString()); + ps.setString(2, currentName); + ps.setLong(3, System.currentTimeMillis()); + ps.setString(4, oldUuid.toString()); + ps.executeUpdate(); + } + + // Update in-memory references on the main thread + Bukkit.getScheduler().runTask(plugin, () -> { + byName.setUniqueId(currentUuid); + byName.setName(currentName); + byName.setLastSeen(System.currentTimeMillis()); + plugin.getClanManager().deleteClanPlayerFromMemory(oldUuid); + plugin.getClanManager().importClanPlayer(byName); + }); + + plugin.getLogger().info(String.format("UUID corrected in database: %s", currentUuid)); + return; + } + + // Case 2: Found by UUID only, name differs - update name + if (byName == null && byUuid != null) { + plugin.getLogger().info(String.format("Correcting name for %s to %s (%s)", byUuid.getName(), currentName, currentUuid)); + + byUuid.setName(currentName); + byUuid.setLastSeen(System.currentTimeMillis()); + updateClanPlayer(byUuid, true); + plugin.getLogger().info(String.format("Player name updated in database: %s", currentName)); + return; + } + + // Case 3: Both found and they're the same record - just update + if (byName != null && byName.getUniqueId().equals(byUuid.getUniqueId())) { + byUuid.setName(currentName); + byUuid.setLastSeen(System.currentTimeMillis()); + updateClanPlayer(byUuid, true); + return; + } + + // Case 4: Both found but different records - merge duplicates + if (byName != null && byUuid != null) { + plugin.getLogger().warning(String.format("Duplicate detection!%n - Record A: %s/%s%n - Record B: %s/%s%nāžœ Merging records.", byName.getName(), byName.getUniqueId(), byUuid.getName(), byUuid.getUniqueId())); + + UUID oldByNameUuid = byName.getUniqueId(); + + // Merge data (keep the byUuid record as base, merge stats from byName) + ClanPlayer merged = mergeClanPlayers(byUuid, byName); + merged.setUniqueId(currentUuid); + merged.setName(currentName); + + // Delete the record with wrong UUID only + String deleteByName = "DELETE FROM `" + getPrefixedTable("players") + "` WHERE uuid = '" + oldByNameUuid + "';"; + core.executeUpdate(deleteByName); + + // Update the kept record with merged data + updateClanPlayer(merged, true); + + // Update in-memory on the main thread + Bukkit.getScheduler().runTask(plugin, () -> { + plugin.getClanManager().deleteClanPlayerFromMemory(oldByNameUuid); + plugin.getClanManager().importClanPlayer(merged); + }); + + plugin.getLogger().info(String.format("Duplicate records merged for %s (%s)", currentName, currentUuid)); + } + } catch (SQLException e) { + plugin.getServer().getLogger().log(Level.SEVERE, "[SimpleClans] Error synchronizing player data for " + currentName, e); + } + } + + /** + * Merges two ClanPlayer records, combining their stats + */ + private ClanPlayer mergeClanPlayers(ClanPlayer primary, ClanPlayer secondary) { + ClanPlayer merged = new ClanPlayer(); + + // Copy identity from primary + merged.setUniqueId(primary.getUniqueId()); + merged.setName(primary.getName()); + + // Keep clan membership from primary (or secondary if primary has none) + Clan primaryClan = primary.getClan(); + Clan secondaryClan = secondary.getClan(); + if (primaryClan != null) { + merged.setClan(primaryClan); + } else if (secondaryClan != null) { + merged.setClan(secondaryClan); + } + + merged.setLeader(primary.isLeader() || secondary.isLeader()); + merged.setTrusted(primary.isTrusted() || secondary.isTrusted()); + + // Merge stats (sum kills/deaths) + merged.setNeutralKills(primary.getNeutralKills() + secondary.getNeutralKills()); + merged.setRivalKills(primary.getRivalKills() + secondary.getRivalKills()); + merged.setCivilianKills(primary.getCivilianKills() + secondary.getCivilianKills()); + merged.setAllyKills(primary.getAllyKills() + secondary.getAllyKills()); + merged.setDeaths(primary.getDeaths() + secondary.getDeaths()); + + // Keep earliest join date and latest last seen + merged.setJoinDate(Math.min(primary.getJoinDate(), secondary.getJoinDate())); + merged.setLastSeen(Math.max(primary.getLastSeen(), secondary.getLastSeen())); + + // Merge other properties from primary + merged.setFriendlyFire(primary.isFriendlyFire()); + merged.setFlags(primary.getFlags()); + merged.setPackedPastClans(primary.getPackedPastClans()); + merged.setResignTimes(primary.getResignTimes()); + merged.setLocale(primary.getLocale()); + + return merged; } /** * Change the name of a player in the database * * @param cp to update + * @deprecated Use syncPlayerData instead for proper duplicate handling */ + @Deprecated public void updatePlayerName(final @NotNull ClanPlayer cp) { String query = "UPDATE `" + getPrefixedTable("players") + "` SET `name` = '" + cp.getName() + "' WHERE uuid = '" + cp.getUniqueId() + "';"; core.executeUpdate(query); @@ -761,8 +979,7 @@ public void updateClan(Clan clan) { /** * Update a clan to the database * - * @param clan clan to update - * + * @param clan clan to update * @param updateLastUsed should the clan's last used time be updated as well? */ public void updateClan(Clan clan, boolean updateLastUsed) { @@ -783,9 +1000,7 @@ public void updateClan(Clan clan, boolean updateLastUsed) { } private PreparedStatement prepareUpdateClanStatement(Connection connection) throws SQLException { - String sql = "UPDATE `" + getPrefixedTable("clans") + "` SET ranks = ?, banner = ?, description = ?, fee_enabled = ?, fee_value = ?, " + - "verified = ?, tag = ?, color_tag = ?, `name` = ?, friendly_fire = ?, founded = ?, last_used = ?, " + - "packed_allies = ?, packed_rivals = ?, packed_bb = ?, balance = ?, flags = ? WHERE tag = ?;"; + String sql = "UPDATE `" + getPrefixedTable("clans") + "` SET ranks = ?, banner = ?, description = ?, fee_enabled = ?, fee_value = ?, " + "verified = ?, tag = ?, color_tag = ?, `name` = ?, friendly_fire = ?, founded = ?, last_used = ?, " + "packed_allies = ?, packed_rivals = ?, packed_bb = ?, balance = ?, flags = ? WHERE tag = ?;"; return connection.prepareStatement(sql); } @@ -826,14 +1041,8 @@ public void deleteClan(Clan clan) { public void insertClanPlayer(ClanPlayer cp) { plugin.getProxyManager().sendUpdate(cp); - String query = "INSERT INTO `" + getPrefixedTable("players") + "` (`uuid`, `name`, `leader`, `tag`, `friendly_fire`, `neutral_kills`, " + - "`rival_kills`, `civilian_kills`, `deaths`, `last_seen`, `join_date`, `packed_past_clans`, `flags`) "; - String values = "VALUES ('" + cp.getUniqueId().toString() + "', '" + cp.getName() + "'," - + (cp.isLeader() ? 1 : 0) + ",'" + Helper.escapeQuotes(cp.getTag()) + "'," - + (cp.isFriendlyFire() ? 1 : 0) + "," + cp.getNeutralKills() + "," + cp.getRivalKills() - + "," + cp.getCivilianKills() + "," + cp.getDeaths() + ",'" + cp.getLastSeen() + "',' " - + cp.getJoinDate() + "','" + Helper.escapeQuotes(cp.getPackedPastClans()) + "','" - + Helper.escapeQuotes(cp.getFlags()) + "');"; + String query = "INSERT INTO `" + getPrefixedTable("players") + "` (`uuid`, `name`, `leader`, `tag`, `friendly_fire`, `neutral_kills`, " + "`rival_kills`, `civilian_kills`, `deaths`, `last_seen`, `join_date`, `packed_past_clans`, `flags`) "; + String values = "VALUES ('" + cp.getUniqueId().toString() + "', '" + cp.getName() + "'," + (cp.isLeader() ? 1 : 0) + ",'" + Helper.escapeQuotes(cp.getTag()) + "'," + (cp.isFriendlyFire() ? 1 : 0) + "," + cp.getNeutralKills() + "," + cp.getRivalKills() + "," + cp.getCivilianKills() + "," + cp.getDeaths() + ",'" + cp.getLastSeen() + "',' " + cp.getJoinDate() + "','" + Helper.escapeQuotes(cp.getPackedPastClans()) + "','" + Helper.escapeQuotes(cp.getFlags()) + "');"; core.executeUpdate(query + values); } @@ -843,12 +1052,12 @@ public void insertClanPlayer(ClanPlayer cp) { */ @Deprecated public void updateClanPlayerAsync(final ClanPlayer cp) { - new BukkitRunnable() { - @Override - public void run() { + new BukkitRunnable() { + @Override + public void run() { updateClanPlayer(cp); - } - }.runTaskAsynchronously(plugin); + } + }.runTaskAsynchronously(plugin); } /** @@ -856,9 +1065,19 @@ public void run() { * */ public void updateClanPlayer(ClanPlayer cp) { + updateClanPlayer(cp, false); + } + + /** + * Update a clan player to the database + * + * @param cp the clan player to update + * @param forceImmediate if true, bypasses periodic save setting and updates immediately + */ + public void updateClanPlayer(ClanPlayer cp, boolean forceImmediate) { cp.updateLastSeen(); plugin.getProxyManager().sendUpdate(cp); - if (plugin.getSettingsManager().is(PERFORMANCE_SAVE_PERIODICALLY)) { + if (!forceImmediate && plugin.getSettingsManager().is(PERFORMANCE_SAVE_PERIODICALLY)) { modifiedClanPlayers.add(cp); return; } @@ -871,9 +1090,7 @@ public void updateClanPlayer(ClanPlayer cp) { } private PreparedStatement prepareUpdateClanPlayerStatement(Connection connection) throws SQLException { - String sql = "UPDATE `" + getPrefixedTable("players") + "` SET locale = ?, resign_times = ?, leader = ?, tag = ?, friendly_fire = ?," + - " neutral_kills = ?, ally_kills = ?, rival_kills = ?, civilian_kills = ?, deaths = ?, last_seen = ?," + - " packed_past_clans = ?, trusted = ?, flags = ?, `name` = ? WHERE `uuid` = ?;"; + String sql = "UPDATE `" + getPrefixedTable("players") + "` SET locale = ?, resign_times = ?, leader = ?, tag = ?, friendly_fire = ?," + " neutral_kills = ?, ally_kills = ?, rival_kills = ?, civilian_kills = ?, deaths = ?, last_seen = ?," + " packed_past_clans = ?, trusted = ?, flags = ?, `name` = ? WHERE `uuid` = ?;"; return connection.prepareStatement(sql); } @@ -918,22 +1135,20 @@ public void deleteClanPlayer(ClanPlayer cp) { @Deprecated public void insertKill(Player attacker, String attackerTag, Player victim, String victimTag, String type) { String query = "INSERT INTO `" + getPrefixedTable("kills") + "` ( `attacker_uuid`, `attacker`, `attacker_tag`, `victim_uuid`, `victim`, `victim_tag`, `kill_type`) "; - String values = "VALUES ( '" + attacker.getUniqueId() + "','" + attacker.getName() + "','" + attackerTag + "','" + victim.getUniqueId() + "','" + victim.getName() + "','" + victimTag + "','" + type + "');"; - core.executeUpdate(query + values); + String values = "VALUES ( '" + attacker.getUniqueId() + "','" + attacker.getName() + "','" + attackerTag + "','" + victim.getUniqueId() + "','" + victim.getName() + "','" + victimTag + "','" + type + "');"; + core.executeUpdate(query + values); } /** * Insert a kill into the database * * @param attacker the attacker - * @param victim the victim - * @param type the kill type + * @param victim the victim + * @param type the kill type */ public void insertKill(@NotNull ClanPlayer attacker, @NotNull ClanPlayer victim, @NotNull String type, @NotNull LocalDateTime time) { - String query = "INSERT INTO `sc_kills` ( `attacker_uuid`, `attacker`, `attacker_tag`, `victim_uuid`, " + - "`victim`, `victim_tag`, `kill_type`, `created_at`) "; - String values = "VALUES ( '" + attacker.getUniqueId() + "','" + attacker.getName() + "','" + attacker.getTag() - + "','" + victim.getUniqueId() + "','" + victim.getName() + "','" + victim.getTag() + "','" + type + "','" + time + "');"; + String query = "INSERT INTO `sc_kills` ( `attacker_uuid`, `attacker`, `attacker_tag`, `victim_uuid`, " + "`victim`, `victim_tag`, `kill_type`, `created_at`) "; + String values = "VALUES ( '" + attacker.getUniqueId() + "','" + attacker.getName() + "','" + attacker.getTag() + "','" + victim.getUniqueId() + "','" + victim.getName() + "','" + victim.getTag() + "','" + type + "','" + time + "');"; core.executeUpdate(query + values); } @@ -960,7 +1175,6 @@ public void deleteKills(UUID playerUniqueId) { * Returns a map of victim-{@literal >}count of all kills that specific player did * * @param playerName the attacker name - * * @return a map of kills per victim * */ @@ -1032,13 +1246,13 @@ public Map getMostKilled() { * @param callback the callback */ public void getMostKilled(DataCallback> callback) { - new BukkitRunnable() { + new BukkitRunnable() { - @Override - public void run() { - callback.onResultReady(getMostKilled()); - } - }.runTaskAsynchronously(plugin); + @Override + public void run() { + callback.onResultReady(getMostKilled()); + } + }.runTaskAsynchronously(plugin); } /** @@ -1046,12 +1260,12 @@ public void run() { * */ public void getKillsPerPlayer(final String playerName, final DataCallback> callback) { - new BukkitRunnable() { - @Override - public void run() { - callback.onResultReady(getKillsPerPlayer(playerName)); - } - }.runTaskAsynchronously(plugin); + new BukkitRunnable() { + @Override + public void run() { + callback.onResultReady(getKillsPerPlayer(playerName)); + } + }.runTaskAsynchronously(plugin); } /** @@ -1061,11 +1275,11 @@ public void run() { * */ public interface DataCallback { - /** - * Notifies when the result is ready - * - */ - void onResultReady(T data); + /** + * Notifies when the result is ready + * + */ + void onResultReady(T data); } /** @@ -1100,7 +1314,7 @@ private void updateDatabase() { */ if (!core.existsColumn(getPrefixedTable("clans"), "description")) { query = "ALTER TABLE `" + getPrefixedTable("clans") + "` ADD COLUMN `description` varchar(255);"; - core.execute(query); + core.execute(query); } /* @@ -1108,7 +1322,7 @@ private void updateDatabase() { */ if (!core.existsColumn(getPrefixedTable("players"), "resign_times")) { query = "ALTER TABLE `" + getPrefixedTable("players") + "` ADD COLUMN `resign_times` text;"; - core.execute(query); + core.execute(query); } /* @@ -1116,7 +1330,7 @@ private void updateDatabase() { */ if (!core.existsColumn(getPrefixedTable("clans"), "ranks")) { query = "ALTER TABLE `" + getPrefixedTable("clans") + "` ADD COLUMN `ranks` text;"; - core.execute(query); + core.execute(query); } // From 2.12.1 to 2.13.0 @@ -1184,7 +1398,7 @@ private void updateDatabase() { * Updates the database to the latest version * */ - private void updatePlayersToUUID() { + private void updatePlayersToUUID() { logMigrationStart(); List cps = retrieveClanPlayers(); @@ -1213,8 +1427,7 @@ private void updatePlayerInDatabase(String playerName, UUID uuid) { String[] conditions = {"name", "attacker", "victim"}; for (int i = 0; i < tables.length; i++) { - String query = String.format("UPDATE `%s` SET %s = '%s' WHERE %s = '%s';", - getPrefixedTable(tables[i]), columns[i], uuid.toString(), conditions[i], playerName); + String query = String.format("UPDATE `%s` SET %s = '%s' WHERE %s = '%s';", getPrefixedTable(tables[i]), columns[i], uuid.toString(), conditions[i], playerName); core.executeUpdate(query); } } @@ -1226,8 +1439,7 @@ private Map fetchUUIDs(List clanPlayers) { if (SimpleClans.getInstance().getServer().getOnlineMode()) { uuidMap = UUIDFetcher.fetchUUIDsForClanPlayers(clanPlayers); } else { - uuidMap = clanPlayers.stream().collect(Collectors.toMap(ClanPlayer::getName, player -> - UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(StandardCharsets.UTF_8)))); + uuidMap = clanPlayers.stream().collect(Collectors.toMap(ClanPlayer::getName, player -> UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(StandardCharsets.UTF_8)))); } } catch (InterruptedException | ExecutionException ex) { plugin.getLogger().log(Level.SEVERE, "Error fetching UUIDs in bulk: " + ex.getMessage(), ex); @@ -1265,15 +1477,16 @@ private String getPrefixedTable(String name) { return plugin.getSettingsManager().getString(MYSQL_TABLE_PREFIX) + name; } - /** - * Saves modified Clans and ClanPlayers to the database + /** + * Saves modified Clans and ClanPlayers to the database + * * @since 2.10.2 * *

* author: RoinujNosde *

- */ - public void saveModified() { + */ + public void saveModified() { try (PreparedStatement pst = prepareUpdateClanPlayerStatement(core.getConnection())) { //removing purged players modifiedClanPlayers.retainAll(plugin.getClanManager().getAllClanPlayers()); @@ -1301,4 +1514,4 @@ public void saveModified() { plugin.getLogger().log(Level.SEVERE, "Error saving modified Clans:", ex); } } -} +} \ No newline at end of file diff --git a/src/main/java/net/sacredlabyrinth/phaed/simpleclans/storage/DBCore.java b/src/main/java/net/sacredlabyrinth/phaed/simpleclans/storage/DBCore.java index 3f829f0ee..651e64beb 100644 --- a/src/main/java/net/sacredlabyrinth/phaed/simpleclans/storage/DBCore.java +++ b/src/main/java/net/sacredlabyrinth/phaed/simpleclans/storage/DBCore.java @@ -42,8 +42,9 @@ default boolean checkConnection() { * @return the result set or null if the query failed */ default @Nullable ResultSet select(String query) { + Connection connection = getConnection(); try { - return getConnection().createStatement().executeQuery(query); + return connection.createStatement().executeQuery(query); } catch (SQLException ex) { log.log(Level.SEVERE, String.format("Error executing query: %s", query), ex); } @@ -56,8 +57,8 @@ default boolean checkConnection() { * @return true if the statement was executed */ default boolean execute(String query) { - try { - getConnection().createStatement().execute(query); + try (java.sql.Statement statement = getConnection().createStatement()) { + statement.execute(query); return true; } catch (SQLException ex) { log.log(Level.SEVERE, String.format("Error executing query: %s", query), ex); @@ -71,8 +72,7 @@ default boolean execute(String query) { * @return true if the table exists */ default boolean existsTable(String table) { - try { - ResultSet tables = getConnection().getMetaData().getTables(null, null, table, null); + try (ResultSet tables = getConnection().getMetaData().getTables(null, null, table, null)) { return tables.next(); } catch (SQLException ex) { log.log(Level.SEVERE, String.format("Error checking if table %s exists", table), ex); @@ -88,8 +88,7 @@ default boolean existsTable(String table) { * @return true if the column exists */ default boolean existsColumn(String table, String column) { - try { - ResultSet col = getConnection().getMetaData().getColumns(null, null, table, column); + try (ResultSet col = getConnection().getMetaData().getColumns(null, null, table, column)) { return col.next(); } catch (Exception ex) { log.log(Level.SEVERE, String.format("Error checking if column %s exists in table %s", column, table), ex); @@ -100,9 +99,10 @@ default boolean existsColumn(String table, String column) { default void executeUpdate(String query) { final Exception exception = new Exception(); // Stores a reference to the caller's stack trace for async tasks Runnable executeUpdate = () -> { - if (getConnection() != null) { - try { - getConnection().createStatement().executeUpdate(query); + Connection connection = getConnection(); + if (connection != null) { + try (java.sql.Statement statement = connection.createStatement()) { + statement.executeUpdate(query); } catch (SQLException ex) { log.log(Level.SEVERE, String.format("Error executing query: %s", query), ex); if (!Bukkit.isPrimaryThread()) { diff --git a/wiki/.gitbook/assets/2021-08-30_17.58.13.png b/wiki/.gitbook/assets/2021-08-30_17.58.13.png deleted file mode 100644 index 8214445f2..000000000 Binary files a/wiki/.gitbook/assets/2021-08-30_17.58.13.png and /dev/null differ diff --git a/wiki/.gitbook/assets/2021-08-30_18.09.22.png b/wiki/.gitbook/assets/2021-08-30_18.09.22.png deleted file mode 100644 index 2fea13dfa..000000000 Binary files a/wiki/.gitbook/assets/2021-08-30_18.09.22.png and /dev/null differ diff --git a/wiki/.gitbook/assets/clans-below-name.png b/wiki/.gitbook/assets/clans-below-name.png deleted file mode 100644 index 9b7ef36be..000000000 Binary files a/wiki/.gitbook/assets/clans-below-name.png and /dev/null differ diff --git a/wiki/.gitbook/assets/clans-tablist.png b/wiki/.gitbook/assets/clans-tablist.png deleted file mode 100644 index a5870e9ca..000000000 Binary files a/wiki/.gitbook/assets/clans-tablist.png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (1).png b/wiki/.gitbook/assets/izobrazhenie (1).png deleted file mode 100644 index 6408b34b5..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (1).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (2).png b/wiki/.gitbook/assets/izobrazhenie (2).png deleted file mode 100644 index 58b40b11c..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (2).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (3).png b/wiki/.gitbook/assets/izobrazhenie (3).png deleted file mode 100644 index 6cef9a088..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (3).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (4) (1).png b/wiki/.gitbook/assets/izobrazhenie (4) (1).png deleted file mode 100644 index 890b1a8d7..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (4) (1).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (4).png b/wiki/.gitbook/assets/izobrazhenie (4).png deleted file mode 100644 index 890b1a8d7..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (4).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (5) (1).png b/wiki/.gitbook/assets/izobrazhenie (5) (1).png deleted file mode 100644 index f91788ae9..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (5) (1).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (5).png b/wiki/.gitbook/assets/izobrazhenie (5).png deleted file mode 100644 index f91788ae9..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (5).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie (6).png b/wiki/.gitbook/assets/izobrazhenie (6).png deleted file mode 100644 index 2b6875e87..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie (6).png and /dev/null differ diff --git a/wiki/.gitbook/assets/izobrazhenie.png b/wiki/.gitbook/assets/izobrazhenie.png deleted file mode 100644 index 6408b34b5..000000000 Binary files a/wiki/.gitbook/assets/izobrazhenie.png and /dev/null differ diff --git a/wiki/.gitbook/assets/klan.png b/wiki/.gitbook/assets/klan.png deleted file mode 100644 index 711283518..000000000 Binary files a/wiki/.gitbook/assets/klan.png and /dev/null differ diff --git a/wiki/README.md b/wiki/README.md deleted file mode 100644 index 707900e5e..000000000 --- a/wiki/README.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -description: Welcome to the SimpleClans Wiki! ---- - -# Introduction - -Here you will find a complete set of documentation including installation, configuration, permissions and usage for SimpleClans. - -## Support - -`1) The Wiki` - -You should always check this wiki carefully for the answer to your question! Even if it seems hidden, it may be here! - -`2) The Discord` - -If the wiki does not have your answer, feel free to join [the discord](https://discord.gg/CkNwgdE) server to ask for help. - -## Bugs and Suggestions - -`Issue Tracker` - -If you believe you have found a bug in the plugin, feel free to make an issue on the [issue tracker!](https://github.com/RoinujNosde/SimpleClans/issues) Bugs will be looked into and addressed at the earliest opportunity. - diff --git a/wiki/SUMMARY.md b/wiki/SUMMARY.md deleted file mode 100644 index fb2267667..000000000 --- a/wiki/SUMMARY.md +++ /dev/null @@ -1,29 +0,0 @@ -# Table of contents - -* [Introduction](README.md) -* [Discord Support](https://discord.gg/CkNwgdE) -* [Bugs and Suggestions](https://github.com/RoinujNosde/SimpleClans/issues) - -## How to Setup - -* [Configuration](how-to-setup/configuration.md) -* [Translation](how-to-setup/translation.md) -* [Member Fee](how-to-setup/member-fee.md) -* [Clan Upkeep](how-to-setup/clan-upkeep.md) -* [Clan Below Player's Name](how-to-setup/clan-below-players-name.md) -* [Clan on Tablist](how-to-setup/clan-on-tablist.md) - -## Commands and Permissions - -* [Commands](commands-and-permissions/commands.md) -* [Permissions](commands-and-permissions/permissions.md) -* [Clan Alliances and Rivalries](commands-and-permissions/aliances-and-rivalries.md) -* [Ranks with Permissions](commands-and-permissions/ranks-with-permissions.md) - -## Other - -* [Known issues](other/known-issues.md) -* [SimpleClans API Example](other/simpleclans-api.md) -* [PlaceholderAPI Support](other/placeholderapi-support.md) -* [Land Claims Plugins](other/land-claims.md) - diff --git a/wiki/commands-and-permissions/aliances-and-rivalries.md b/wiki/commands-and-permissions/aliances-and-rivalries.md deleted file mode 100644 index b0bc73c9a..000000000 --- a/wiki/commands-and-permissions/aliances-and-rivalries.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: null ---- - -# Clan Alliances and Rivalries - -Any clan leader can send an request to start an alliance with any other clan with `/clan ally add`. If the request is accepted by a leader of the second clan, the alliance is formed. The alliance can be broken by any leader of either clan at any time with `/clan ally remove`, no one needs to accept the removal of an alliance. - -Clan rivalries can be started by any clan at any time, no request is needed, rivalries are automatically formed once a clan leader decides he wants one by using `/clan rival add`. If someone has pissed you off and you want them as rivals, their permission is not needed. To break a clan rivalry on the other hand, you need the acceptance of the other clan, you must use `/clan rival remove` to send the other clan a request, once one of their leaders accept the rivalry is broken. - -You can view a list of all clans and their allies with the `/clan alliances` command, or their rivals with the `/clan rivalries` command. - -## Commands - -| Commands | Description | -| :--- | :--- | -| `/clan ally add [tag]` | Send an request to start an alliance \(acceptance is required\) | -| `/clan ally remove [tag]` | Remove alliance \(no acceptance is required\) | -| `/clan rival add [tag]` | Starting a rivalry \(no acceptance is required\) | -| `/clan rival remove [tag]` | Remove a rivalry \(acceptance is required\) | -| `/clan alliances` | List all clans and their allies | -| `/clan rivalries` | List all clans and their rivals | - -## Permissions - -| Permission | Description | -| :--- | :--- | -| `simpleclans.member.ally` | Can use ally chat | -| `simpleclans.leader.ally` | Can ally his clan with other simpleclans | -| `simpleclans.leader.rival` | Can start a rivalry with another clan | -| `simpleclans.anyone.alliances` | Can view alliances by clan | -| `simpleclans.anyone.rivalries` | Can view rivalries by clan | - diff --git a/wiki/commands-and-permissions/commands.md b/wiki/commands-and-permissions/commands.md deleted file mode 100644 index aaee0e4c5..000000000 --- a/wiki/commands-and-permissions/commands.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -description: null ---- - -# Commands - -> Required arguments are marked with `(argument)` -> -> Optional arguments are marked with `[argument]` - -## Anyone Commands - -| Command | Description | Verified only | | | | | | -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| `/clan` | Opens the GUI or shows the help | No | | | | | | -| `/clan help` | Shows the plugin's commands | No | | | | | | -| `/clan create [tag] [name]` | Creates a new clan | No | | | | | | -| `/accept` | Accepts a request | No | | | | | | -| `/deny` | Denies a request | No | | | | | | -| `/more` | Shows more information | No | | | | | | -| `/clan leaderboard` | Shows the leaderboard | No | | | | | | -| \`/clan list \[name | size | kdr | founded | active\] \[asc | desc\]\` | Lists all clans | No | -| `/clan rivalries` | Shows all clan rivalries | No | | | | | | -| `/clan alliances` | Shows all clan alliances | No | | | | | | -| `/clan lookup [player]` | Looks up your or another player's info | No | | | | | | -| `/clan profile [tag]` | Shows another clan's profile | Yes\* | | | | | | -| `/clan roster [tag]` | Shows another clan's roster | Yes\* | | | | | | -| \`/clan ff \(allow | auto\)\` | Toggles personal friendly fire | No | | | | | -| `/clan resetkdr` | Resets your KDR | No | | | | | | - -\\* The target clan - -## Members Commands - -### General Commands - -| Command | Description | Verified only | -| :--- | :--- | :--- | -| `/clan kills [player]` | Shows your or another player's kill counts | Yes | -| `/clan toggle` | Toggles personal settings | Yes | -| `/clan mostkilled` | Shows server-wide most killed counts | Yes | -| `/clan resign` | Resigns from the clan | No | -| `/clan fee check` | Checks if the fee is enabled and how much it costs | Yes | -| `/clan vitals` | Shows your clan's vitals | Yes | -| `/clan stats` | Shows your clan's stats | Yes | -| `/clan profile` | Shows your clan's profile | Yes | -| `/clan roster` | Shows your clan's roster | Yes | -| `/clan coords` | Shows your clan's coords | Yes | - -### Chat Commands - -| Command | Description | Verified only | | | -| :--- | :--- | :--- | :--- | :--- | -| `/. (message)` | Sends a message to your clan's chat | No | | | -| \`/. \[join | leave | mute\]\` | Joins/leaves/mutes your clan's chat | No | -| `/ally (message)` | Sends a message to the ally chat | No | | | -| \`/ally \[join | leave | mute\]\` | Joins/leaves/mutes the ally chat | No | - -## Leaders Commands - -| Command | Description | Verified only | | -| :--- | :--- | :--- | :--- | -| `/clan description (description)` | Modifies the clan's description | Yes | | -| `/clan invite (player)` | Invites a player | No | | -| `/clan kick (player)` | Kicks a player from the clan | No | | -| `/clan trust (player)` | Sets a member as trusted | No | | -| `/clan untrust (player)` | Sets a member as untrusted | No | | -| `/clan promote (member)` | Promotes a member to leader | No | | -| `/clan demote (leader)` | Demotes a leader to member | No | | -| `/clan setbanner` | Sets the clan's banner | Yes | | -| `/clan modtag (tag)` | Modifies your clan's tag \(only colors and case\) | | | -| \`/clan clanff \(allow | block\)\` | Toggles clan's friendly fire | No | -| \`/clan war \(start | end\) \(tag\)\` | Starts or ends a war | Yes | -| \`/clan rival \(add | remove\) \(tag\)\` | Adds or removes a rival | Yes | -| \`/clan ally \(add | remove\) \(tag\)\` | Adds or removes an ally | Yes | -| `/clan verify` | Verifies your clan | No | | -| `/clan disband` | Disbands your clan | No | | -| `/clan fee set (amount)` | Sets the clan's member fee | No | | -| `/clan regroup me` | Regroups your clan members to your location | Yes | | -| `/clan regroup home` | Regroups your clan members to your clan's home | Yes | | -| `/clan home` | Teleports to your clan's home | Yes | | -| `/clan home clear` | Clears your clan's home | Yes | | -| `/clan home set` | Sets your clan's home | Yes | | -| `/clan rank create` | Creates a rank | Yes | | -| `/clan rank setdisplayname (rank) (displayname)` | Sets the display name of the rank \(it can contain colors and multiple words\) | Yes | | -| `/clan rank assign (player) (rank)` | Assigns a user to a rank | Yes | | -| `/clan rank unassign (player)` | Unassigns a user from a rank | Yes | | -| `/clan rank delete (rank)` | Deletes a rank | Yes | | -| `/clan rank list` | Lists the clan's ranks | Yes | | -| `/clan rank permissions` | Lists the available permissions for ranks | Yes | | -| `/clan rank permissions (rank)` | Lists the rank's permissions | Yes | | -| `/clan rank permissions add (rank) (permission)` | Adds a permission to the rank | Yes | | -| `/clan rank permissions remove (rank) (permission)` | Removes a permission from the rank | Yes | | - -## Mod Commands - -| Command | Description | | -| :--- | :--- | :--- | -| `/clan place (player) (new clan)` | Places a player in a clan | | -| `/clan home set (tag)` | Sets a clan's home | | -| `/clan home tp (tag)` | Teleports to a clan's home | | -| `/clan ban (player)` | Bans a player from clan commands | | -| `/clan unban (player)` | Unbans a player from clan commands | | -| \`/clan globalff \(allow | auto\)\` | Toggles the global friendly-fire status | -| `/clan verify (tag)` | Verifies a clan | | -| `/clan disband (tag)` | Disbands a clan | | - -## Admin Commands - -| Command | Description | -| :--- | :--- | -| `/clan reload` | Reloads the plugin and its configuration \(some features may need a server restart\) | -| `/clan purge` | Purges a player's data | -| `/clan resetkdr everyone` | Resets everyone's KDR | -| `/clan resetkdr (player)` | Resets a player's KDR | -| `/clan admin demote (player)` | Demotes a leader from any clan | -| `/clan admin promote (player)` | Promotes a member from any clan | - diff --git a/wiki/commands-and-permissions/permissions.md b/wiki/commands-and-permissions/permissions.md deleted file mode 100644 index 0f72bbeb6..000000000 --- a/wiki/commands-and-permissions/permissions.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -description: null ---- - -# Permissions - -## SuperPerms Nodes \(Some auto added\) - -These super permission nodes are a quick way to setup SimpleClans, some are automatically given \(See Auto Added\). If you wish to setup individual permissions to groups you will need to deny these auto added super permission nodes and setup permissions one by one after. - -| Permission | Description | -| :--- | :--- | -| `simpleclans.anyone.*` \(Auto added\) | Permissions for anyone | -| `simpleclans.member.*` \(Auto added\) | Permissions for those who can be clan members | -| `simpleclans.leader.*` \(Auto added\) | Permissions for those who can be clan leaders | -| `simpleclans.mod.*` \(Auto added to OPS\) | Permissions for moderators | -| `simpleclans.admin.*` \(Auto added to OPS\) | Permissions for admins | - -## Individual Nodes - -\(You don't need to add these as they are all included if you've already added the node groups \(above\). They are only included here as reference in case you want to toggle a couple of them off individually. Then you can just drop those in, set to false, along with the node groups.\) - -### Anyone Nodes - -| Permission | Description | -| :--- | :--- | -| `simpleclans.anyone.alliances` | Can view alliances by clan | -| `simpleclans.anyone.leaderboard` | Can view the leaderboard | -| `simpleclans.anyone.list` | Can list simpleclans | -| `simpleclans.anyone.lookup` | Can lookup a player's info | -| `simpleclans.anyone.profile` | Can view a clan's profile | -| `simpleclans.anyone.rivalries` | Can view rivalries by clan | -| `simpleclans.anyone.roster` | Can view a clan's member list | - -### Member Nodes - -| Permission | Description | -| :--- | :--- | -| `simpleclans.member.abstain` | Can abstain | -| `simpleclans.member.accept` | Can accept | -| `simpleclans.member.ally` | Can use ally chat | -| `simpleclans.member.chat` | Can use clan chat | -| `simpleclans.member.bank` | Can use the clan bank | -| `simpleclans.member.bb-add` | Can add to his clan's bulletin board | -| `simpleclans.member.bb-toggle` | Can toggle the bulletin board on/off | -| `simpleclans.member.bb` | Can view his clan's bulletin board | -| `simpleclans.member.can-join` | Can join clans | -| `simpleclans.member.coords` | Can view his clan's coords | -| `simpleclans.member.deny` | Can deny | -| `simpleclans.member.ff` | Can toggle his own friendly fire | -| `simpleclans.member.home` | Can tp to home base | -| `simpleclans.member.kills` | Can view his and other's kills | -| `simpleclans.member.lookup` | Can view his own player info | -| `simpleclans.member.profile` | Can view his own clan's profile | -| `simpleclans.member.resign` | Can resign from his clan | -| `simpleclans.member.roster` | Can view his own clan's member list | -| `simpleclans.member.stats` | Can view his clan stats | -| `simpleclans.member.vitals` | Can view his clan's vitals | -| `simpleclans.member.toggle.bb` | Can toggle bb on/off | -| `simpleclans.member.tag-toggle` | Can hide/show their clan tag | -| `simpleclans.member.fee-check` | Allows the member to check how much is the fee and if it's enabled | -| `simpleclans.member.bypass-fee` | Can bypass the member fee | - -### Leader Nodes - -| Permission | Description | -| :--- | :--- | -| `simpleclans.leader.fee` | allows the user to toggle the fee and set its value | -| `simpleclans.leader.ally` | Can ally his clan with other clans | -| `simpleclans.leader.create` | Can create clans | -| `simpleclans.leader.verify` | Can verify their clan | -| `simpleclans.leader.demote` | Can demote clan leaders to normal players | -| `simpleclans.leader.disband` | Can disband his own clan | -| `simpleclans.leader.ff` | Can toggle his clan's friendly fire | -| `simpleclans.leader.home-set` | Can set home base | -| `simpleclans.leader.regroup.me` | Can teleport the entire clan to themself | -| `simpleclans.leader.regroup.home` | Can teleport the entire clan to homebase | -| `simpleclans.leader.invite` | Can invite players into his clan | -| `simpleclans.leader.kick` | Can kick players form his clan | -| `simpleclans.leader.modtag` | Can modify his clan's tag | -| `simpleclans.leader.description` | Can modify their clan's description | -| `simpleclans.leader.coloredtag` | Can use color codes in tags | -| `simpleclans.leader.coloredrank` | Can use color codes in rank display names | -| `simpleclans.leader.promotable` | Can be promoted to clan leader | -| `simpleclans.leader.promote` | Can promote players to clan leaders | -| `simpleclans.leader.rank.assign` | Can assign a rank to a user | -| `simpleclans.leader.rank.unassign` | Can unassign a player from a rank | -| `simpleclans.leader.rank.create` | Can create a new rank | -| `simpleclans.leader.rank.delete` | Can delete a new rank | -| `simpleclans.leader.rank.list` | Can list all the ranks | -| `simpleclans.leader.rank.setdisplayname` | Can set the display name of the rank | -| `simpleclans.leader.rank.permissions.add` | Can add permissions to a rank | -| `simpleclans.leader.rank.permissions.available` | Can list all available permissions | -| `simpleclans.leader.rank.permissions.list` | Can list the rank's permissions | -| `simpleclans.leader.rank.permissions.remove` | Can remove permissions from a rank | -| `simpleclans.leader.rival` | Can start a rivalry with another clan | -| `simpleclans.leader.settrust` | Can set trust levels for members | -| `simpleclans.leader.war` | Can start wars | -| `simpleclans.leader.setbanner` | Can set his clan's banner | -| `simpleclans.leader.withdraw-toggle:` | Can toggle clan bank withdraw | -| `simpleclans.leader.deposit-toggle:` | Can toggle clan bank deposit | -| `simpleclans.leader.bb-clear` | Clan clear their clan's bb | - -### Mod Nodes - -| Permission | Description | -| :--- | :--- | -| `simpleclans.mod.ban` | Can ban players from the entire plugin | -| `simpleclans.mod.bypass` | Can bypass restrictions | -| `simpleclans.mod.disband` | Can disband any clan | -| `simpleclans.mod.globalff` | Can turn off global friendly fire protection | -| `simpleclans.mod.home` | Can set other clan's home | -| `simpleclans.mod.hometp` | Can teleport to all clans homes | -| `simpleclans.mod.staffgui` | Can open the staff GUI | -| `simpleclans.mod.place` | Can manually place players in clans | -| `simpleclans.mod.keep-items` | Can keep items when teleporting home | -| `simpleclans.mod.mostkilled` | Can view his and other's clans mostkilled | -| `simpleclans.mod.nopvpinwar` | Can bypass PvP in wars | -| `simpleclans.mod.unban` | Can unban players from the entire plugin | -| `simpleclans.mod.verify` | Can verify clans | - -### Admin Nodes - -| Permission | Description | -| :--- | :--- | -| `simpleclans.admin.resetkdr` | Can reset a player's or everyone's KDR | -| `simpleclans.admin.purge` | Can purge a player | -| `simpleclans.admin.demote` | Can demote a player back to member | -| `simpleclans.admin.promote` | Can promote players to clan leaders | -| `simpleclans.admin.all-seeing-eye` | Can see all clan chats | -| `simpleclans.admin.reload` | Can reload configuration | - -### Other Nodes - -| Permission | Node | -| :--- | :--- | -| `simpleclans.other.kdr-exempt` | The player's KDR is not affected on killing/dying \(check Known Issues\) | -| `simpleclans.vip.resetkdr` | Can reset their KDR | - diff --git a/wiki/commands-and-permissions/ranks-with-permissions.md b/wiki/commands-and-permissions/ranks-with-permissions.md deleted file mode 100644 index 87f57e52d..000000000 --- a/wiki/commands-and-permissions/ranks-with-permissions.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -description: null ---- - -# Ranks with Permissions - -## How does it work? - -Leaders have the ability to create ranks and give them permissions to perform several actions inside the clan. Unlike `/clan trust`, ranks with permissions allows leaders to have a finer control of who can do what. Ex.: A rank can handle invites \(`invite` permission\), another takes care of moderation \(`kick` permission\), etc - -## Suggested ranks - -| Ranks | Description | Permission | -| :--- | :--- | :---: | -| **Coleader** | Helps take care of the clan | `all` | -| **Treasurer** | Manages the clan's bank account | `bank.balance`, `bank.deposit`, `bank.withdraw` | -| **Ambassador** | Manages the clan's relations with other clans | `ally.chat`, `ally.add`, `ally.remove`, `rival.add`, `rival.remove`, `war.end`, `war.start` | -| **Recruit** | A member in trial | `stats`, `kills`, `mostkilled`, `rank.list` | - -## Ranks Commands - -| Command | Description | -| :--- | :--- | -| `/clan rank create` | Creates a rank with this name | -| `/clan rank setdisplayname [rank] [displayname]` | Sets the display name of the rank \(it can be more than one word and colored\) | -| `/clan rank assign (player) (rank)` | Assigns a user to a rank | -| `/clan rank unassign (player)` | Unassigns a user from a rank | -| `/clan rank delete (rank)` | Deletes a rank | -| `/clan rank list` | Lists the clan's ranks | -| `/clan rank permissions` | Lists the available permissions for ranks | -| `/clan rank permissions (rank)` | Lists the rank's permissions | -| `/clan rank permissions add (rank) (permission)` | Adds a permission to the rank | -| `/clan rank permissions remove (rank) (permission)` | Removes a permission from the rank | - -## Available permissions for ranks - -A player can view those permissions in-game using `/clan rank permissions` - -| Rank Permission | Description | -| :--- | :--- | -| `ally.add` | can add an ally | -| `ally.remove` | can remove an ally | -| `ally.chat` | can use ally chat | -| `bank.balance` | can view the bank balance | -| `bank.deposit` | can deposit money | -| `bank.withdraw` | can withdraw money | -| `bb.add` | can add a message to bb | -| `bb.clear` | can clear the bb | -| `coords` | can view the clan's coords | -| `fee.enable` | can enable the member fee | -| `fee.set` | can change the fee value | -| `home.regroup` | can regroup the clan | -| `home.set` | can set the clan home | -| `home.tp` | can tp to the clan home | -| `invite` | can invite someone to the clan | -| `kick` | can kick someone from the clan | -| `modtag` | can modify the clan tag | -| `rank.displayname` | can modify a rank's display name | -| `rank.list` | can list the ranks | -| `rival.add` | can add a rival | -| `rival.remove` | can remove a rival | -| `war.end` | can end a war | -| `war.start` | can start a war | -| `vitals` | can view the clan's vitals | -| `stats` | can view the clan's stats | -| `kills` | can view his or other's kills | -| `mostkilled` | can view the mostkilled | -| `description` | can change the clan's description | - -## Permissions to use the rank commands - -| Permission | Description | -| :--- | :--- | -| `simpleclans.leader.rank.assign` | Can assign a rank to a user | -| `simpleclans.leader.rank.unassign` | Can unassign a player from a rank | -| `simpleclans.leader.rank.create` | Can create a new rank | -| `simpleclans.leader.rank.delete` | Can delete a new rank | -| `simpleclans.leader.rank.list` | Can list all the ranks | -| `simpleclans.leader.rank.setdisplayname` | Can set the display name of the rank | -| `simpleclans.leader.rank.permissions.add` | Can add permissions to a rank | -| `simpleclans.leader.rank.permissions.available` | Can list all available permissions | -| `simpleclans.leader.rank.permissions.list` | Can list the rank's permissions | -| `simpleclans.leader.rank.permissions.remove` | Can remove permissions from a rank | - diff --git a/wiki/how-to-setup/clan-below-players-name.md b/wiki/how-to-setup/clan-below-players-name.md deleted file mode 100644 index 93dff0411..000000000 --- a/wiki/how-to-setup/clan-below-players-name.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -description: null ---- - -# Clan Below Player's Name - -## Plugins needed - -* [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.6245/) -* [TAB](https://www.spigotmc.org/resources/tab-1-5-x-1-15-x-free-version.57806/) \(you can use a different tablist plugin, as long as it supports PlaceholderAPI\) - -## Step by step - -1. Open TAB's config and edit the Groups section adding `%simpleclans_clan_color_tag%` to `belowname`: - -{% code title="Example:" %} -```yaml -_OTHER_: - tabprefix: "%vault-prefix% " - tagprefix: "%vault-prefix% " - tabsuffix: "%afk%" - tagsuffix: "%afk%" - customtabname: "%essentialsnick%" - customtagname: "%essentialsnick%" - belowname: "&l&b[ %simpleclans_clan_color_tag% &l&b]" -``` -{% endcode %} - -1. Find the option `belowname` or `classic-vanilla-belowname` and disable it. -2. Find the option `unlimited-nametag-prefix-suffix-mode` and enable it. -3. Restart \(or reload\) and enjoy! - -## Screenshot - -![](../.gitbook/assets/clans-below-name.png) - diff --git a/wiki/how-to-setup/clan-on-tablist.md b/wiki/how-to-setup/clan-on-tablist.md deleted file mode 100644 index 5e09dd89a..000000000 --- a/wiki/how-to-setup/clan-on-tablist.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: null ---- - -# Clan on Tablist - -## Plugins needed - -* [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.6245/) -* [PlayerListPlus](https://www.spigotmc.org/resources/%E2%99%9B-playerlistplus-%E2%99%9B-1-8-1-14-3-tablist-editor.55878/) \(you can use a different tablist plugin, as long as it supports PlaceholderAPI\) - -## Step by step - -1. Open PlayerListPlus config and edit the formats adding `%simpleclans_clan_color_tag%`: - -{% code title="Example:" %} -```yaml -slot-items: -# This slot items will shows all players - PLAYERS: - format: "%simpleclans_clan_color_tag%&c.$displayname" - type: PLAYER_LIST - hidevanished: true - ping: true - skin: true -``` -{% endcode %} - -1. Restart \(or reload\) and enjoy! - -## Screenshot - -![](../.gitbook/assets/clans-tablist.png) - diff --git a/wiki/how-to-setup/clan-upkeep.md b/wiki/how-to-setup/clan-upkeep.md deleted file mode 100644 index 96aeb9ec9..000000000 --- a/wiki/how-to-setup/clan-upkeep.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -description: null ---- - -# Clan Upkeep - -## How does it work? - -If enabled, clans will have to pay an amount everyday to keep their clans. The value will be collected at `1:30am`. At `12am`, if the clan doesn't have enough money to pay it, a wan will be sent to the clan's BB. The amount can be fixed or based on the clan size. - -Ex. fee based on the clan size: - -```text -upkeep base = 20.0 -clan size = 10 -final upkeep = 200.0 -``` - -## Configuring - -* `upkeep` - The base upkeep. -* `upkeep-enabled` - Enable or disable the feature. -* `multiply-upkeep-by-clan-size` - This works as explained above -* `charge-upkeep-only-if-member-fee-enabled` - Enable upkeep if [member fee](https://github.com/RoinujNosde/SimpleClans/wiki/Member-Fee) is enabled. - -### Exemple - -```yaml -economy: - upkeep: 200.0 - upkeep-enabled: false - multiply-upkeep-by-clan-size: false - charge-upkeep-only-if-member-fee-enabled: true -``` - diff --git a/wiki/how-to-setup/configuration.md b/wiki/how-to-setup/configuration.md deleted file mode 100644 index dffb648f7..000000000 --- a/wiki/how-to-setup/configuration.md +++ /dev/null @@ -1,510 +0,0 @@ ---- -description: null ---- - -# Configuration - -[The main configuration file for SimpleClans can be found here.](https://github.com/RoinujNosde/SimpleClans/blob/master/src/main/resources/config.yml) - -## General Settings - -* `enable-gui` - Enables the GUI. -* `disable-messages` - This will disable broadcasts from the plugin such as "Clan created", "Clan disbanded", etc. -* `tameable-mobs-sharing` - -* `teleport-blocks` - -* `teleport-home-on-spawn` - Players will be teleported to their clan's home when they respawn. -* `drop-items-on-clan-home` - -* `keep-items-on-clan-home` - -* `item-list` - -* `show-debug-info` - -* `mchat-integration` - -* `enable-auto-groups` - -* `chat-compatibility-mode` - -* `rival-limit-percent` - -* `use-colorcode-from-prefix-for-name` - -* `display-chat-tags` - -* `unrivable-clans` - -* `show-unverified-on-list` - -* `blacklisted-worlds` - -* `banned-players` - -* `disallowed-tags` - -* `language` - -* `language-per-player` - -* `disallowed-tag-colors` - -* `server-name` - -* `new-clan-verification-required` - -* `allow-regroup-command` - -* `allow-reset-kdr` - -* `rejoin-cooldown` - -* `rejoin-cooldown-enabled` - -* `min-to-verify` - The clan must have this amount of members to get verified \(moderators can bypass this\) -* `ranking-type` - Valid options: ORDINAL and DENSE - * `DENSE`: if players have the same KDR, they will have the same rank position. Ex.: 12234 - * `ORDINAL`: Every player will have a different rank position. Ex.: 12345 - -### Example - -```yaml -settings: - enable-gui: true - disable-messages: false - tameable-mobs-sharing: false - teleport-blocks: false - teleport-home-on-spawn: false - drop-items-on-clan-home: false - keep-items-on-clan-home: false - item-list: [] - show-debug-info: false - mchat-integration: true - enable-auto-groups: false - chat-compatibility-mode: true - rival-limit-percent: 50 - use-colorcode-from-prefix-for-name: true - display-chat-tags: true - unrivable-clans: - - admin - - staff - - mod - show-unverified-on-list: false - blacklisted-worlds: [] - banned-players: [] - disallowed-tags: - - vip - - clan - language: en - language-per-player: false - disallowed-tag-colors: - - '4' - server-name: '&4SimpleClans' - new-clan-verification-required: true - allow-regroup-command: true - allow-reset-kdr: false - rejoin-cooldown: 60 - rejoin-cooldown-enabled: false - min-to-verify: 1 - ranking-type: DENSE -``` - -## Tags Format - -### Example - -* `default-color` - -* `max-length` - -* `bracket` - - * `color` - - * `leader-color` - - * `left` - - * `right` - -* `min-length` - -* `separator` - - * `color` - - * `leader-color` - - * `char` - - -```yaml -tag: - default-color: '8' - max-length: 5 - bracket: - color: '8' - leader-color: '4' - left: '' - right: '' - min-length: 2 - separator: - color: '8' - leader-color: '4' - char: ' .' -``` - -## General Commands - -* `more` - -* `ally` - -* `clan` - -* `accept` - -* `deny` - -* `global` - -* `clan_chat` - -* `force-priority` - - -### Example - -```yaml -commands: - more: more - ally: ally - clan: clan - accept: accept - deny: deny - global: global - clan_chat: "." - force-priority: true -``` - -## KDR Grinding Prevention - -* `enable-max-kills` - -* `max-kills-per-victim` - -* `enable-kill-delay` - -* `delay-between-kills` - - -### Example - -```yaml -kdr-grinding-prevention: - enable-max-kills: false - max-kills-per-victim: 10 - enable-kill-delay: false - delay-between-kills: 5 -``` - -## List Commands - -* `size` - -* `kdr` - -* `name` - -* `founded` - -* `active` - -* `asc` - -* `desc` - -* `default` - - -### Example - -```yaml -list: - size: size - kdr: kdr - name: name - founded: founded - active: active - asc: asc - desc: desc - default: kdr -``` - -## Economy - -* `creation-price` - -* `purchase-clan-create` - -* `verification-price` - -* `purchase-clan-verify` - -* `invite-price` - -* `purchase-clan-invite` - -* `home-teleport-price` - -* `purchase-home-teleport` - -* `home-teleport-set-price` - -* `purchase-home-teleport-set` - -* `home-regroup-price` - -* `purchase-home-regroup` - -* `unique-tax-on-regroup` - -* `issuer-pays-regroup` - -* `money-per-kill` - -* `money-per-kill-kdr-multipier` - -* `purchase-reset-kdr` - -* `reset-kdr-price` - -* `purchase-member-fee-set` - -* `member-fee-set-price` - -* `member-fee-enabled` - -* `max-member-fee` - -* `upkeep` - -* `upkeep-enabled` - -* `multiply-upkeep-by-clan-size` - -* `charge-upkeep-only-if-member-fee-enabled` - - -### Example - -```yaml -economy: - creation-price: 100.0 - purchase-clan-create: false - verification-price: 1000.0 - purchase-clan-verify: false - invite-price: 20.0 - purchase-clan-invite: false - home-teleport-price: 5.0 - purchase-home-teleport: false - home-teleport-set-price: 5.0 - purchase-home-teleport-set: false - home-regroup-price: 5.0 - purchase-home-regroup: false - unique-tax-on-regroup: true - issuer-pays-regroup: true - money-per-kill: false - money-per-kill-kdr-multipier: 10 - purchase-reset-kdr: true - reset-kdr-price: 10000.0 - purchase-member-fee-set: false - member-fee-set-price: 1000.0 - member-fee-enabled: false - max-member-fee: 200.0 - upkeep: 200.0 - upkeep-enabled: false - multiply-upkeep-by-clan-size: false - charge-upkeep-only-if-member-fee-enabled: true -``` - -## Kill Weights - -* `rival` - -* `civilian` - -* `neutral` - -* `deny-same-ip-kills` - - -### Example - -```yaml -kill-weights: - rival: 2.0 - civilian: 0.0 - neutral: 1.0 - deny-same-ip-kills: false -``` - -## Clan Settings - -* `homebase-teleport-wait-secs` - -* `homebase-can-be-set-only-once` - -* `min-size-to-set-rival` - -* `max-length` - -* `max-description-length` - -* `min-description-length` - -* `max-members` - -* `confirmation-for-promote` - -* `trust-members-by-default` - -* `confirmation-for-demote` - -* `percentage-online-to-demote` - -* `ff-on-by-default` - -* `min-length` - -* `min-size-to-set-ally` - - -### Example - -```yaml -clan: - homebase-teleport-wait-secs: 10 - homebase-can-be-set-only-once: true - min-size-to-set-rival: 3 - max-length: 25 - max-description-length: 120 - min-description-length: 10 - max-members: 25 - confirmation-for-promote: false - trust-members-by-default: false - confirmation-for-demote: false - percentage-online-to-demote: 100.0 - ff-on-by-default: false - min-length: 2 - min-size-to-set-ally: 3 -``` - -## Tasks - -* `collect-upkeep` - - * `hour` - - * `minute` - -* `collect-upkeep-warning` - - * `hour` - - * `minute` - -* `collect-fee` - - * `hour` - - * `minute` - - -### Example - -```yaml -tasks: - collect-upkeep: - hour: 1 - minute: 30 - collect-upkeep-warning: - hour: 12 - minute: 0 - collect-fee: - hour: 1 - minute: 0 -``` - -## Page - -* `untrusted-color` - -* `clan-name-color` - -* `subtitle-color` - -* `headings-color` - -* `trusted-color` - -* `leader-color` - -* `separator` - -* `size` - - -### Example - -```yaml -page: - untrusted-color: '8' - clan-name-color: b - subtitle-color: '7' - headings-color: '8' - trusted-color: f - leader-color: '4' - separator: '-' - size: 100 -``` - -## Clan Chat - -* `enable` - -* `tag-based-clan-chat` - -* `announcement-color` - -* `format` - -* `rank` - -* `leader-color:` - -* `trusted-color` - -* `member-color` - - -### Example - -```yaml -clanchat: - enable: true - tag-based-clan-chat: false - announcement-color: e - format: "&b[%clan%&b] &4<%nick-color%%player%&4> %rank%: &b%message%" - rank: "&f[%rank%&f]" - leader-color: '4' - trusted-color: 'f' - member-color: '7' -``` - -## Request - -* `message-color` - -* `ask-frequency-secs` - -* `max-asks-per-request` - - -### Example - -```yaml -request: - message-color: b - ask-frequency-secs: 60 - max-asks-per-request: 1440 -``` - -## Bulletin Board - -* `color` - -* `accent-color` - -* `show-on-login` - -* `size` - -* `login-size` - - -### Example - -```yaml -bb: - color: e - accent-color: '8' - show-on-login: true - size: 6 - login-size: 6 -``` - -## Ally Chat - -* `enable` - -* `format` - -* `rank` - -* `leader-color` - -* `trusted-color` - -* `member-color` - - -### Example - -```yaml -allychat: - enable: true - format: "&b[Ally Chat] &4<%clan%&4> <%nick-color%%player%&4> %rank%: &b%message%" - rank: "&f[%rank%&f]" - leader-color: '4' - trusted-color: 'f' - member-color: '7' -``` - -## Purge Data - -* `inactive-player-data-days` - -* `inactive-clan-days` - -* `unverified-clan-days` - - -### Example - -```yaml -purge: - inactive-player-data-days: 30 - inactive-clan-days: 7 - unverified-clan-days: 2 -``` - -## mySQL Settings - -* `username` - -* `host` - -* `port` - -* `enable` - -* `password` - -* `database` - - -### Example - -```yaml -mysql: - username: '' - host: localhost - port: 3306 - enable: false - password: '' - database: '' -``` - -## Permissions - -* `auto-group-groupname` - - -### Example - -```yaml -permissions: - auto-group-groupname: false - YourClanNameHere: - - test.permission -``` - -## Performance - -* `save-periodically` - The plugin will save its data periodically as opposed to right away, **RECOMMENDED** to set it true. -* `save-interval` - The interval **in minutes** in which changes are written to the database. -* `use-threads` - The plugin will not use the main thread to connect with the database if this is true, **RECOMMENDED** to set it true. -* `use-bungeecord` - - -### Example - -```yaml -performance: - save-periodically: true - save-interval: 10 - use-threads: true - use-bungeecord: false -``` - -## Safe Civilians - -* `safe-civilians` - Civilians are safe from PvP, even civilian vs civilian combat is disabled - -### Example - -```yaml -safe-civilians: false -``` - diff --git a/wiki/how-to-setup/member-fee.md b/wiki/how-to-setup/member-fee.md deleted file mode 100644 index e24ad9c0a..000000000 --- a/wiki/how-to-setup/member-fee.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -description: null ---- - -# Member Fee - -## How does it work? - -If enabled by the server and the clan, at `1am` a fee \(set by the leader\) is collected from the non-leaders. A member that doesn't have enough money to pay it will be automatically kicked from the clan. The collected fee is added to the clan bank. - -## Configuration - -* `member-fee-enabled` - Enables or disables the feature. -* `max-member-fee` - Limits the fee, so leaders may not abuse the members. -* `purchase-member-fee-set` - Enable this to charge the value below everytime a leader changes the fee value. -* `member-fee-set-price` - Value to charge for changes on the fee value - -### Example - -```yaml -economy: - member-fee-enabled: false - max-member-fee: 200.0 - purchase-member-fee-set: false - member-fee-set-price: 1000.0 -``` - -## Permissions - -| Permission | Description | -| :--- | :--- | -| `simpleclans.leader.fee` | Allows the user to toggle the fee and set its value | -| `simpleclans.member.fee-check` | allows the member to check how much is the fee and if it's enabled | - -## Commands - -| Permission | Description | Permission | -| :--- | :--- | :--- | -| `/clan toggle fee` | Enables/disables the fee | `simpleclans.leader.fee` | -| `/clan fee set [amount]` | Sets the fee value | `simpleclans.leader.fee` | -| `/clan fee check` | Checks the status of the fee | `simpleclans.member.fee-check` | - diff --git a/wiki/how-to-setup/translation.md b/wiki/how-to-setup/translation.md deleted file mode 100644 index c09789f05..000000000 --- a/wiki/how-to-setup/translation.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: null ---- - -# Translation - -## Editing the plugin's messages - -### Requirements: - -* A ZIP explorer program \(such as [WinRAR](https://www.win-rar.com/download.html?&L=0) or [7-Zip](https://www.7-zip.org/download.html)\) -* A Text editor like [NotePad++](https://notepad-plus-plus.org/downloads/), [Visual Studio Code](https://code.visualstudio.com/) or [Sublime Text](https://www.sublimetext.com/). - -### Step by step - -1. Right click the plugin jar, click on "Open as" and choose the ZIP program; -2. Copy the messages file corresponding to your language to the plugin's folder; - 1. If there isn't one for your language, copy "messages.properties" instead and rename it with your language code appended. For example, if your language is Russian: `messages_ru_RU.properties` -3. Edit the messages and save; -4. Change `language` in config.yml to your language code; -5. Reload the plugin using /clan reload. - -### A little trick - -If you like the current translation, but want to change only a few lines: 1. Copy the file to the plugin's folder; 2. Delete all messages except the ones you would like to edit; 3. Edit them and save. - -> **Note**: Please note that your custom `messages.properties` does not automatically update when new messages are added. - -## Share your translations! - -SimpleClans has a project on [Crowdin](https://crowdin.com/project/simpleclans). There you can translate the messages and suggest corrections! - -> **Note**: if you have an old `language.yml` file for SimpleClans that you translated to your language, [open an issue here](https://github.com/RoinujNosde/SimpleClans/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc), I will convert the file and add it to the plugin. - diff --git a/wiki/other/known-issues.md b/wiki/other/known-issues.md deleted file mode 100644 index fdaa35528..000000000 --- a/wiki/other/known-issues.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -description: List of the plugin's known issues and possible solutions. ---- - -# Known issues - -## MySQL \#1366 - Incorrect string value - -This error happens when you try to insert characters that MySQL's current encoding doesn't support. - -**Solution:** change MySQL's encoding to `utf8mb4`. -1. Open MySQL's `my.cnf`. -2. Add these configurations, save and restart MySQL: - -```text -[mysql] -default-character-set=utf8mb4 -[mysqld] -character-set-server=utf8mb4 -collation-server=utf8mb4_unicode_ci -``` - -## KDR is not counted - -Players report that their KDR is not changing. - -**Solution:** deny the permission `simpleclans.other.kdr-exempt`. In some permission plugins, just add a `-` before the node. Others accept the `false` value. - diff --git a/wiki/other/land-claims.md b/wiki/other/land-claims.md deleted file mode 100644 index 76573dadc..000000000 --- a/wiki/other/land-claims.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -description: null ---- - -# Land Claims Plugins - -## Configuration - -* `enable-auto-groups` - -* `auto-group-groupname`- - -### Exemple - -```yaml -settings: - enable-auto-groups: false -permissions: - auto-group-groupname: true - YourClanNameHere: - - test.permission -``` - -## GriefPrevention - -You can replace `` with ANY clan tag \(ally, rival, etc\) - -| Command | Description | -| :--- | :--- | -| `/Trust group.` | Gives the Clan members permission to edit in your claim | -| `/AccessTrust group.` | Gives the Clan members permission to use your buttons, levers, and beds | -| `/ContainerTrust group.` | Gives the Clan members permission to use your buttons, levers, beds, crafting gear, containers, and animals | -| `/PermissionTrust group.` | Gives the Clan members permission to share their permission level with others | -| `/UnTrust group.` | Revokes any permissions granted to a Clan in your claim | - -## Note - -After the permission is given, the player must reconnect. - diff --git a/wiki/other/placeholderapi-support.md b/wiki/other/placeholderapi-support.md deleted file mode 100644 index 2c29a8c3d..000000000 --- a/wiki/other/placeholderapi-support.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -description: null ---- - -# PlaceholderAPI Support - -## Available placeholders - -| Placeholder | Result | Description | | -| :--- | :--- | :--- | :--- | -| %simpleclans\_neutral\_kills% | INTEGER | | | -| %simpleclans\_rival\_kills% | INTEGER | | | -| %simpleclans\_civilian\_kills% | INTEGER | | | -| %simpleclans\_total\_kills% | INTEGER | | | -| %simpleclans\_weighted\_kills% | INTEGER | | | -| %simpleclans\_deaths% | INTEGER | | | -| %simpleclans\_kdr% | FLOAT | | | -| %simpleclans\_in\_clan% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_leader% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_trusted% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_member% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_bb\_enabled% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_usechatshortcut% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_allychat% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_clanchat% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_globalchat% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_cape\_enabled% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_tag\_enabled% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_friendlyfire\_on% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_muted% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_is\_mutedally% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_join\_date% | DATE | Month, Day, Year, Hour | | -| %simpleclans\_inactive\_days% | INTEGER | | | -| %simpleclans\_lastseen% | INTEGER | | | -| %simpleclans\_lastseendays% | INTEGER | | | -| %simpleclans\_tag% | STRING | lowerscored Clan tag without color | | -| %simpleclans\_tag\_label% | STRING | Clan tag with correct mayus, color and at the end &c | | -| %simpleclans\_rank% | STRING | | | -| %simpleclans\_rank\_displayname% | STRING | | | -| %simpleclans\_clanchat\_player\_color% | | | | -| %simpleclans\_allychat\_player\_color% | | | | -| %simpleclans\_clan\_total\_neutral% | INTEGER | | | -| %simpleclans\_clan\_total\_civilian% | INTEGER | | | -| %simpleclans\_clan\_total\_rival% | INTEGER | | | -| %simpleclans\_clan\_total\_kills% | INTEGER | | | -| %simpleclans\_clan\_total\_deaths% | INTEGER | | | -| %simpleclans\_clan\_total\_kdr% | FLOAT | | | -| %simpleclans\_clan\_average\_wk% | INTEGER | | | -| %simpleclans\_clan\_leader\_size% | INTEGER | | | -| %simpleclans\_clan\_balance% | INTEGER | | | -| %simpleclans\_clan\_allow\_withdraw% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_clan\_allow\_deposit% | BOOLEAN \(YES/NO\) | | | -| %simpleclans\_clan\_size% | INTEGER | | | -| %simpleclans\_clan\_name% | STRING | | | -| %simpleclans\_clan\_color\_tag% | | | | -| %simpleclans\_clan\_tag% | | | | -| %simpleclans\_clan\_founded% | | | | -| %simpleclans\_clan\_friendly\_fire% | | | | -| %simpleclans\_clan\_is\_unrivable% | | | | -| %simpleclans\_clan\_is\_anyonline% | | | | -| %simpleclans\_clan\_is\_verified% | | | | -| %simpleclans\_clan\_capeurl% | | | | -| %simpleclans\_clan\_inactivedays% | | | | -| %simpleclans\_clan\_onlinemembers\_count% | | | | -| %simpleclans\_clan\_allies\_count% | | | | -| %simpleclans\_clan\_rivals\_count% | | | | -| %simpleclanstopclans\_\#\_clan\_total\_neutral% | | | | -| %simpleclanstopclans\_\#\_clan\_total\_civilian% | | | | -| %simpleclanstopclans\_\#\_clan\_total\_rival% | | | | -| %simpleclanstopclans\_\#\_clan\_total\_kills% | | | | -| %simpleclanstopclans\_\#\_clan\_total\_deaths% | | | | -| %simpleclanstopclans\_\#\_clan\_total\_kdr% | | | | -| %simpleclanstopclans\_\#\_clan\_average\_wk% | | | | -| %simpleclanstopclans\_\#\_clan\_leader\_size% | | | | -| %simpleclanstopclans\_\#\_clan\_balance% | | | | -| %simpleclanstopclans\_\#\_clan\_allow\_withdraw% | | | | -| %simpleclanstopclans\_\#\_clan\_allow\_deposit% | | | | -| %simpleclanstopclans\_\#\_clan\_size% | | | | -| %simpleclanstopclans\_\#\_clan\_name% | | | | -| %simpleclanstopclans\_\#\_clan\_color\_tag% | | | | -| %simpleclanstopclans\_\#\_clan\_tag% | | | | -| %simpleclanstopclans\_\#\_clan\_founded% | | | | -| %simpleclanstopclans\_\#\_clan\_friendly\_fire% | | | | -| %simpleclanstopclans\_\#\_clan\_is\_unrivable% | | | | -| %simpleclanstopclans\_\#\_clan\_is\_anyonline% | | | | -| %simpleclanstopclans\_\#\_clan\_is\_verified% | | | | -| %simpleclanstopclans\_\#\_clan\_capeurl% | | | | -| %simpleclanstopclans\_\#\_clan\_inactivedays% | | | | -| %simpleclanstopclans\_\#\_clan\_onlinemembers\_count% | | | | -| %simpleclanstopclans\_\#\_clan\_allies\_count% | | | | -| %simpleclanstopclans\_\#\_clan\_rivals\_count% | | | | - diff --git a/wiki/other/simpleclans-api.md b/wiki/other/simpleclans-api.md deleted file mode 100644 index cccba0dbb..000000000 --- a/wiki/other/simpleclans-api.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -description: null ---- - -# SimpleClans API Example - -You can hook into SimpleClans plugin like so: - -```java -private SimpleClans sc; - -public void onEnable() -{ - Plugin plug = getServer().getPluginManager().getPlugin("SimpleClans"); - - if (plug != null) - { - sc = ((SimpleClans) plug); - } -} -``` - -```java -public void doClanStuff(Player player) -{ - // get a player's clan - - if (sc != null) - { - ClanPlayer cp = sc.getClanManager().getClanPlayer(player.getUniqueId()); - - if (cp != null) - { - Clan clan = cp.getClan(); - } - else - { - // player is not in a clan - } - } - - // get a clan from a clan tag - - if (sc != null) - { - Clan clan = sc.getClanManager().getClan("staff"); - - if (clan != null) - { - // clan exists - } - } -} -``` - -Every player has a **ClanPlayer** object which holds all his information, including his clan, and can be used to perform various operations on the player. - -The **Clan** object holds all the information for a clan and can be used to perform various operations on the clan. - -The **ClanManager** holds all the **Clans** and **ClanPlayers** and contains methods that allow you to retrieve them. -