diff --git a/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java b/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java index aa5dc60fd..858ed6b6c 100644 --- a/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java +++ b/Plan/src/main/java/com/djrapitops/plan/PlanSponge.java @@ -20,12 +20,23 @@ import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.game.state.GameStartedServerEvent; import org.spongepowered.api.event.game.state.GameStoppingServerEvent; +import org.spongepowered.api.plugin.Dependency; import org.spongepowered.api.plugin.Plugin; import java.io.File; import java.io.InputStream; -@Plugin(id = "plan", name = "Plan", version = "4.4.6", description = "Player Analytics Plugin by Rsl1122", authors = {"Rsl1122"}) +@Plugin( + id = "plan", + name = "Plan", + version = "4.4.7", + description = "Player Analytics Plugin by Rsl1122", + authors = {"Rsl1122"}, + dependencies = { + @Dependency(id = "nucleus", optional = true), + @Dependency(id = "luckperms", optional = true) + } +) public class PlanSponge extends SpongePlugin implements PlanPlugin { @Inject diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java b/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java index 21eb8bfca..a6aa0970d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/DBSystem.java @@ -81,7 +81,7 @@ public abstract class DBSystem implements SubSystem { try { Benchmark.start("Init Database"); initDatabase(); - db.scheduleClean(1L); + db.scheduleClean(20L); Log.info(locale.get().getString(PluginLang.ENABLED_DATABASE, db.getName())); Benchmark.stop("Enable", "Init Database"); } catch (DBInitException e) { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/GeoInfoLastUsedPatch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/GeoInfoLastUsedPatch.java index 80b0d2ef5..d4ab90098 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/GeoInfoLastUsedPatch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/GeoInfoLastUsedPatch.java @@ -16,7 +16,7 @@ public class GeoInfoLastUsedPatch extends Patch { @Override public void apply() { - addColumns(GeoInfoTable.TABLE_NAME, + addColumn(GeoInfoTable.TABLE_NAME, GeoInfoTable.Col.LAST_USED + " bigint NOT NULL DEFAULT 0" ); } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/IPHashPatch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/IPHashPatch.java index a83134639..8f4b675ea 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/IPHashPatch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/IPHashPatch.java @@ -16,6 +16,6 @@ public class IPHashPatch extends Patch { @Override public void apply() { - addColumns(GeoInfoTable.Col.IP_HASH.get() + " varchar(200) DEFAULT ''"); + addColumn(GeoInfoTable.TABLE_NAME, GeoInfoTable.Col.IP_HASH.get() + " varchar(200) DEFAULT ''"); } } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/KillsServerIDPatch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/KillsServerIDPatch.java index e6832a7fd..8428524da 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/KillsServerIDPatch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/KillsServerIDPatch.java @@ -40,7 +40,7 @@ public class KillsServerIDPatch extends Patch { @Override public void apply() { - addColumns(KillsTable.Col.SERVER_ID + " integer NOT NULL DEFAULT 0"); + addColumn(KillsTable.TABLE_NAME, KillsTable.Col.SERVER_ID + " integer NOT NULL DEFAULT 0"); Map sessionIDServerIDRelation = db.getSessionsTable().getIDServerIDRelation(); diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/NicknameLastSeenPatch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/NicknameLastSeenPatch.java index a45bc697b..a9155de2f 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/NicknameLastSeenPatch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/NicknameLastSeenPatch.java @@ -25,7 +25,7 @@ public class NicknameLastSeenPatch extends Patch { @Override public void apply() { - addColumns(NicknamesTable.TABLE_NAME, + addColumn(NicknamesTable.TABLE_NAME, NicknamesTable.Col.LAST_USED + " bigint NOT NULL DEFAULT '0'" ); diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java index cb4fcbb28..9ad3c26b5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java @@ -78,11 +78,8 @@ public abstract class Patch { }); } - protected void addColumns(String tableName, String... columnInfo) { - for (int i = 0; i < columnInfo.length; i++) { - columnInfo[i] = "ALTER TABLE " + tableName + " ADD " + (usingMySQL ? "" : "COLUMN ") + columnInfo[i]; - } - db.executeUnsafe(columnInfo); + protected void addColumn(String tableName, String columnInfo) { + db.executeUnsafe("ALTER TABLE " + tableName + " ADD " + (usingMySQL ? "" : "COLUMN ") + columnInfo); } protected void dropTable(String name) { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionAFKTimePatch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionAFKTimePatch.java index 672780d3c..5e8a28032 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionAFKTimePatch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionAFKTimePatch.java @@ -16,7 +16,7 @@ public class SessionAFKTimePatch extends Patch { @Override public void apply() { - addColumns(SessionsTable.TABLE_NAME, + addColumn(SessionsTable.TABLE_NAME, SessionsTable.Col.AFK_TIME + " bigint NOT NULL DEFAULT 0" ); } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/TransferPartitionPatch.java b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/TransferPartitionPatch.java index 147d8e47a..eea4affe9 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/TransferPartitionPatch.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/TransferPartitionPatch.java @@ -16,6 +16,6 @@ public class TransferPartitionPatch extends Patch { @Override public void apply() { - addColumns(TransferTable.TABLE_NAME, TransferTable.Col.PART + " bigint NOT NULL DEFAULT 0"); + addColumn(TransferTable.TABLE_NAME, TransferTable.Col.PART + " bigint NOT NULL DEFAULT 0"); } } diff --git a/Plan/src/main/resources/bungee.yml b/Plan/src/main/resources/bungee.yml index 048b498cc..b165e7633 100644 --- a/Plan/src/main/resources/bungee.yml +++ b/Plan/src/main/resources/bungee.yml @@ -1,4 +1,9 @@ name: Plan author: Rsl1122 main: com.djrapitops.plan.PlanBungee -version: 4.4.6 \ No newline at end of file +version: 4.4.7 +softdepend: +- AdvancedBan +- LiteBans +- LuckPerms +- ViaVersion \ No newline at end of file diff --git a/Plan/src/main/resources/plugin.yml b/Plan/src/main/resources/plugin.yml index 56ef3675e..f83a18fa4 100644 --- a/Plan/src/main/resources/plugin.yml +++ b/Plan/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: Plan author: Rsl1122 main: com.djrapitops.plan.Plan -version: 4.4.6 +version: 4.4.7 softdepend: - EssentialsX - Towny @@ -20,6 +20,8 @@ softdepend: - Kingdoms - RedProtect - AdvancedBan +- LuckPerms +- DiscordSRV commands: plan: @@ -88,7 +90,7 @@ permissions: default: op plan.webmanage: description: Manage the webusers, delete, list, check - default: op; + default: op plan.basic: children: diff --git a/PlanPluginBridge/PlanPluginBridge-4.4.0.jar b/PlanPluginBridge/PlanPluginBridge-4.4.0.jar index 25b269757..6e1a2c5da 100644 Binary files a/PlanPluginBridge/PlanPluginBridge-4.4.0.jar and b/PlanPluginBridge/PlanPluginBridge-4.4.0.jar differ diff --git a/PlanPluginBridge/pom.xml b/PlanPluginBridge/pom.xml index a4f68f61d..329b230d8 100644 --- a/PlanPluginBridge/pom.xml +++ b/PlanPluginBridge/pom.xml @@ -85,6 +85,10 @@ nucleus-repo http://repo.drnaylor.co.uk/artifactory/list/minecraft + + discordsrv-repo + https://ci.scarsz.me/plugin/repository/everything/ + @@ -94,6 +98,12 @@ 4.3.0-SNAPSHOT provided + + org.apache.commons + commons-text + 1.3 + + @@ -167,6 +177,18 @@ 1.6.0-PR1-S7.0 provided + + me.lucko.luckperms + luckperms-api + 4.3 + provided + + + github.scarsz.discordsrv + DiscordSRV + 1.16.4 + provided + diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java index 2adf0dfbd..4ac01895d 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java @@ -10,6 +10,7 @@ import com.djrapitops.pluginbridge.plan.advancedban.AdvancedBanHook; import com.djrapitops.pluginbridge.plan.askyblock.ASkyBlockHook; import com.djrapitops.pluginbridge.plan.banmanager.BanManagerHook; import com.djrapitops.pluginbridge.plan.buycraft.BuyCraftHook; +import com.djrapitops.pluginbridge.plan.discordsrv.DiscordSRVHook; import com.djrapitops.pluginbridge.plan.essentials.EssentialsHook; import com.djrapitops.pluginbridge.plan.factions.FactionsHook; import com.djrapitops.pluginbridge.plan.griefprevention.GriefPreventionHook; @@ -18,6 +19,7 @@ import com.djrapitops.pluginbridge.plan.jobs.JobsHook; import com.djrapitops.pluginbridge.plan.kingdoms.KingdomsHook; import com.djrapitops.pluginbridge.plan.litebans.LiteBansBukkitHook; import com.djrapitops.pluginbridge.plan.litebans.LiteBansBungeeHook; +import com.djrapitops.pluginbridge.plan.luckperms.LuckPermsHook; import com.djrapitops.pluginbridge.plan.mcmmo.McmmoHook; import com.djrapitops.pluginbridge.plan.nucleus.NucleusHook; import com.djrapitops.pluginbridge.plan.protocolsupport.ProtocolSupportHook; @@ -75,6 +77,7 @@ public class Bridge { private static Hook[] getSpongeHooks(HookHandler h) { return new Hook[]{ new BuyCraftHook(h), + new LuckPermsHook(h), new SpongeEconomyHook(h), new NucleusHook(h) }; @@ -85,6 +88,7 @@ public class Bridge { new AdvancedBanHook(h), new BuyCraftHook(h), new LiteBansBungeeHook(h), + new LuckPermsHook(h), new ViaVersionBungeeHook(h) }; } @@ -97,6 +101,7 @@ public class Bridge { new ASkyBlockHook(h), new BanManagerHook(h), new BuyCraftHook(h), + new DiscordSRVHook(h), new EssentialsHook(h), new FactionsHook(h), new GriefPreventionHook(h), @@ -104,6 +109,7 @@ public class Bridge { new JobsHook(h), new KingdomsHook(h), new LiteBansBukkitHook(h), + new LuckPermsHook(h), new McmmoHook(h), new SuperbVoteHook(h), new ProtocolSupportHook(h), diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/discordsrv/DiscordSRVData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/discordsrv/DiscordSRVData.java new file mode 100644 index 000000000..0223833ca --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/discordsrv/DiscordSRVData.java @@ -0,0 +1,124 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.pluginbridge.plan.discordsrv; + +import com.djrapitops.plan.data.element.AnalysisContainer; +import com.djrapitops.plan.data.element.InspectContainer; +import com.djrapitops.plan.data.plugin.ContainerSize; +import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.utilities.FormatUtils; +import com.djrapitops.plan.utilities.html.icon.Color; +import com.djrapitops.plan.utilities.html.icon.Family; +import com.djrapitops.plan.utilities.html.icon.Icon; +import github.scarsz.discordsrv.DiscordSRV; +import github.scarsz.discordsrv.dependencies.jda.core.entities.Member; +import github.scarsz.discordsrv.dependencies.jda.core.entities.Role; +import github.scarsz.discordsrv.dependencies.jda.core.entities.User; +import github.scarsz.discordsrv.util.DiscordUtil; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import org.apache.commons.text.TextStringBuilder; + +/** + * PluginData for DiscordSRV plugin. + * + * @author Vankka + */ +public class DiscordSRVData extends PluginData { + public DiscordSRVData() { + super(ContainerSize.THIRD, "DiscordSRV"); + setPluginIcon(Icon.called("discord").of(Family.BRAND).build()); + } + + @Override + public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) { + if (!DiscordSRV.isReady) { + return inspectContainer; + } + + String userId = DiscordSRV.getPlugin().getAccountLinkManager().getDiscordId(uuid); + User user = userId != null ? DiscordUtil.getUserById(userId) : null; + + if (user == null) { + return inspectContainer; + } + + inspectContainer.addValue( + getWithIcon("Username", Icon.called("user").of(Family.SOLID).of(Color.CYAN)), + "@" + user.getName() + "#" + user.getDiscriminator() + ); + inspectContainer.addValue( + getWithIcon("Account creation date", Icon.called("plus").of(Family.SOLID).of(Color.BLUE)), + FormatUtils.formatTimeStampYear(user.getCreationTime().toEpochSecond() * 1000L) + ); + + Member member = DiscordSRV.getPlugin().getMainGuild().getMember(user); + + if (member != null) { + addMemberData(member, inspectContainer); + } + + return inspectContainer; + } + + private void addMemberData(Member member, InspectContainer inspectContainer) { + String nickname = member.getNickname(); + + inspectContainer.addValue( + getWithIcon("Nickname", Icon.called("user-ninja").of(Family.SOLID).of(Color.ORANGE)), + nickname != null ? nickname : "None" + ); + inspectContainer.addValue( + getWithIcon("Join Date", Icon.called("plus").of(Family.SOLID).of(Color.GREEN)), + FormatUtils.formatTimeStampYear(member.getJoinDate().toEpochSecond() * 1000L) + ); + + List roles = member.getRoles().stream().map(Role::getName).collect(Collectors.toList()); // Ordered list of role names + if (!roles.isEmpty()) { + inspectContainer.addValue( + getWithIcon("Roles", Icon.called("user-circle").of(Family.SOLID).of(Color.RED)), + new TextStringBuilder().appendWithSeparators(roles, ", ").build() + ); + } + } + + @Override + public AnalysisContainer getServerData(Collection uuids, AnalysisContainer analysisContainer) { + if (!DiscordSRV.isReady) { + return analysisContainer; + } + + int accountsLinked = DiscordSRV.getPlugin().getAccountLinkManager().getLinkedAccounts().size(); + int guildUsers = DiscordSRV.getPlugin().getMainGuild().getMembers().size(); + + analysisContainer.addValue( + getWithIcon("Accounts linked", Icon.called("link").of(Family.SOLID).of(Color.CYAN)), + accountsLinked + ); + analysisContainer.addValue( + getWithIcon("Users in main guild", Icon.called("users").of(Family.SOLID).of(Color.GREEN)), + guildUsers + ); + analysisContainer.addValue( + getWithIcon("Accounts linked / Total players", Icon.called("percentage").of(Family.SOLID).of(Color.TEAL)), + calculatePercentage(accountsLinked, uuids.size()) + "%" + ); + analysisContainer.addValue( + getWithIcon("Accounts linked / Users in main guild", Icon.called("percentage").of(Family.SOLID).of(Color.LIGHT_GREEN)), + calculatePercentage(accountsLinked, guildUsers) + "%" + ); + + return analysisContainer; + } + + private double calculatePercentage(int input1, int input2) { + if (input1 == 0 || input2 == 0) + return 0D; + + return Math.round((double) input1 / input2 * 10000D) / 100D; // 2 decimals + } +} diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/discordsrv/DiscordSRVHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/discordsrv/DiscordSRVHook.java new file mode 100644 index 000000000..0c951b7c6 --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/discordsrv/DiscordSRVHook.java @@ -0,0 +1,26 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.pluginbridge.plan.discordsrv; + +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.pluginbridge.plan.Hook; + +/** + * Hook for DiscordSRV plugin. + * + * @author Vankka + */ +public class DiscordSRVHook extends Hook { + public DiscordSRVHook(HookHandler hookHandler) { + super("github.scarsz.discordsrv.DiscordSRV", hookHandler); + } + + @Override + public void hook() throws NoClassDefFoundError { + if (enabled) { + addPluginDataSource(new DiscordSRVData()); + } + } +} diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/factions/FactionsData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/factions/FactionsData.java index b6b63c650..b3e017a88 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/factions/FactionsData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/factions/FactionsData.java @@ -72,7 +72,8 @@ public class FactionsData extends PluginData { if (!factions.isEmpty()) { FactionsAccordion factionsAccordion = new FactionsAccordion( factions, - analysisData.getValue(AnalysisKeys.PLAYERS_MUTATOR).orElse(new PlayersMutator(new ArrayList<>())) + Optional.ofNullable(analysisData).flatMap(c -> c.getValue(AnalysisKeys.PLAYERS_MUTATOR)) + .orElse(new PlayersMutator(new ArrayList<>())) ); analysisContainer.addHtml("factionAccordion", factionsAccordion.toHtml()); diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/kingdoms/KingdomsData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/kingdoms/KingdomsData.java index 53e97c965..7e842e0cf 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/kingdoms/KingdomsData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/kingdoms/KingdomsData.java @@ -1,4 +1,4 @@ -/* +/* * Licence is provided in the jar as license.yml also here: * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml */ @@ -62,7 +62,8 @@ public class KingdomsData extends PluginData { if (!kingdoms.isEmpty()) { KingdomsAccordion kingdomsAccordion = new KingdomsAccordion( kingdoms, - analysisData.getValue(AnalysisKeys.PLAYERS_MUTATOR).orElse(new PlayersMutator(new ArrayList<>())) + Optional.ofNullable(analysisData).flatMap(c -> c.getValue(AnalysisKeys.PLAYERS_MUTATOR)) + .orElse(new PlayersMutator(new ArrayList<>())) ); analysisContainer.addHtml("kingdomsAccordion", kingdomsAccordion.toHtml()); diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java index f58704be9..92dfadfa9 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/litebans/LiteBansData.java @@ -179,7 +179,8 @@ public class LiteBansData extends PluginData implements BanData { if (objects.isEmpty()) { table.addRow("No Data"); } else { - Map playerNames = analysisData.getValue(AnalysisKeys.PLAYER_NAMES).orElse(new HashMap<>()); + Map playerNames = Optional.ofNullable(analysisData) + .flatMap(c -> c.getValue(AnalysisKeys.PLAYER_NAMES)).orElse(new HashMap<>()); for (LiteBansDBObj object : objects) { UUID uuid = object.getUuid(); String name = playerNames.getOrDefault(uuid, uuid.toString()); diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/luckperms/LuckPermsData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/luckperms/LuckPermsData.java new file mode 100644 index 000000000..9c10055ec --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/luckperms/LuckPermsData.java @@ -0,0 +1,125 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.pluginbridge.plan.luckperms; + +import com.djrapitops.plan.data.element.AnalysisContainer; +import com.djrapitops.plan.data.element.InspectContainer; +import com.djrapitops.plan.data.element.TableContainer; +import com.djrapitops.plan.data.plugin.ContainerSize; +import com.djrapitops.plan.data.plugin.PluginData; +import com.djrapitops.plan.utilities.html.icon.Color; +import com.djrapitops.plan.utilities.html.icon.Family; +import com.djrapitops.plan.utilities.html.icon.Icon; +import java.util.*; +import java.util.stream.Collectors; +import me.lucko.luckperms.api.*; +import me.lucko.luckperms.api.caching.MetaData; +import org.apache.commons.text.TextStringBuilder; + +/** + * PluginData for LuckPerms plugin. + * + * @author Vankka + */ +public class LuckPermsData extends PluginData { + private LuckPermsApi api; + + public LuckPermsData(LuckPermsApi api) { + super(ContainerSize.THIRD, "LuckPerms"); + setPluginIcon(Icon.called("exclamation-triangle").of(Color.LIGHT_GREEN).build()); + + this.api = api; + } + + @Override + public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) { + User user = api.getUser(uuid); + + if (user == null) { + inspectContainer.addValue("Data unavailable", "Could not get user data"); + return inspectContainer; + } + + MetaData metaData = user.getCachedData().getMetaData(Contexts.allowAll()); + String prefix = metaData.getPrefix(); + String suffix = metaData.getSuffix(); + + inspectContainer.addValue(getWithIcon("Primary group", Icon.called("user-friends").of(Family.SOLID)), user.getPrimaryGroup()); + inspectContainer.addValue(getWithIcon("Prefix", Icon.called("file-signature").of(Family.SOLID).of(Color.GREEN)), prefix != null ? prefix : "None"); + inspectContainer.addValue(getWithIcon("Suffix", Icon.called("file-signature").of(Family.SOLID).of(Color.BLUE)),suffix != null ? suffix : "None"); + + if (!metaData.getMeta().isEmpty()) { + TableContainer metaTable = new TableContainer( + getWithIcon("Meta", Icon.called("info-circle").of(Family.SOLID)), + getWithIcon("Value", Icon.called("file-alt").of(Family.SOLID)) + ); + metaData.getMeta().forEach((key, value) -> metaTable.addRow(key, value)); + inspectContainer.addTable("Meta", metaTable); + } + + List groups = user.getPermissions().stream() + .filter(Node::isGroupNode) + .map(Node::getGroupName) + .sorted() + .collect(Collectors.toList()); + + inspectContainer.addValue( + getWithIcon("Groups", Icon.called("user-friends").of(Family.SOLID)), + new TextStringBuilder().appendWithSeparators(groups, ", ").build() + ); + + Set tracks = api.getTracks(); + if (!tracks.isEmpty()) { + TableContainer trackTable = new TableContainer( + getWithIcon("Track", Icon.called("ellipsis-h").of(Family.SOLID)), + getWithIcon("Group", Icon.called("user-friends").of(Family.SOLID)) + ); + for (Track track : tracks) { + // reduce is used to get the last element + String currentGroup = api.getGroups().stream() + .map(this::getGroupDisplayName).filter(groups::contains) + .reduce((first, second) -> second).orElse("None"); + trackTable.addRow(track.getName(), currentGroup); + } + inspectContainer.addTable("Tracks", trackTable); + } + + return inspectContainer; + } + + @Override + public AnalysisContainer getServerData(Collection uuids, AnalysisContainer analysisContainer) { + // There will *always* be atleast 1 group + TableContainer groupTable = new TableContainer( + getWithIcon("Group", Icon.called("user-friends").of(Family.SOLID)), + getWithIcon("Weight", Icon.called("weight-hanging").of(Family.SOLID)), + getWithIcon("Permissions", Icon.called("list").of(Family.SOLID)) + ); + + api.getGroups().stream().sorted(Comparator.comparing(Group::getName)).forEach(group -> { + OptionalInt weight = group.getWeight(); + + groupTable.addRow(getGroupDisplayName(group), weight.isPresent() ? weight.getAsInt() : "None", group.getPermissions().size()); + }); + analysisContainer.addTable("Groups", groupTable); + + Set tracks = api.getTracks(); + if (!tracks.isEmpty()) { + TableContainer trackTable = new TableContainer( + getWithIcon("Track", Icon.called("ellipsis-h").of(Family.SOLID)), + getWithIcon("Size", Icon.called("list").of(Family.SOLID)) + ); + tracks.forEach(track -> trackTable.addRow(track.getName(), track.getSize())); + analysisContainer.addTable("Tracks", trackTable); + } + + return analysisContainer; + } + + private String getGroupDisplayName(Group group) { + String displayName = group.getDisplayName(); + return displayName != null ? displayName : group.getName(); + } +} diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/luckperms/LuckPermsHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/luckperms/LuckPermsHook.java new file mode 100644 index 000000000..341ed1853 --- /dev/null +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/luckperms/LuckPermsHook.java @@ -0,0 +1,27 @@ +/* + * Licence is provided in the jar as license.yml also here: + * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml + */ +package com.djrapitops.pluginbridge.plan.luckperms; + +import com.djrapitops.plan.data.plugin.HookHandler; +import com.djrapitops.pluginbridge.plan.Hook; +import me.lucko.luckperms.LuckPerms; + +/** + * Hook for LuckPerms plugin. + * + * @author Vankka + */ +public class LuckPermsHook extends Hook { + public LuckPermsHook(HookHandler hookHandler) { + super("me.lucko.luckperms.LuckPerms", hookHandler); + } + + @Override + public void hook() throws IllegalStateException { + if (enabled) { + addPluginDataSource(new LuckPermsData(LuckPerms.getApi())); + } + } +} diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/towny/TownyData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/towny/TownyData.java index bacdd88ec..83c902822 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/towny/TownyData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/towny/TownyData.java @@ -97,7 +97,8 @@ public class TownyData extends PluginData { TownsAccordion townsAccordion = new TownsAccordion( towns, - analysisData.getValue(AnalysisKeys.PLAYERS_MUTATOR).orElse(new PlayersMutator(new ArrayList<>())) + Optional.ofNullable(analysisData).flatMap(c -> c.getValue(AnalysisKeys.PLAYERS_MUTATOR)) + .orElse(new PlayersMutator(new ArrayList<>())) ); analysisContainer.addHtml("townAccordion", townsAccordion.toHtml()); diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultEcoData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultEcoData.java index 175672de1..92c5047fc 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultEcoData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultEcoData.java @@ -9,7 +9,6 @@ import com.djrapitops.plan.data.element.InspectContainer; import com.djrapitops.plan.data.plugin.ContainerSize; import com.djrapitops.plan.data.plugin.PluginData; import com.djrapitops.plan.data.store.keys.AnalysisKeys; -import com.djrapitops.plan.data.store.mutators.PlayersMutator; import com.djrapitops.plan.system.cache.DataCache; import com.djrapitops.plan.utilities.FormatUtils; import com.djrapitops.plan.utilities.html.icon.Color; @@ -50,10 +49,11 @@ public class VaultEcoData extends PluginData { @Override public AnalysisContainer getServerData(Collection collection, AnalysisContainer analysisContainer) { - List offlinePlayers = analysisData.getValue(AnalysisKeys.PLAYERS_MUTATOR) - .map(PlayersMutator::all).orElse(new ArrayList<>()) - .stream().map(FakeOfflinePlayer::new) - .collect(Collectors.toList()); + List offlinePlayers = Optional.ofNullable(analysisData) + .flatMap(c -> c.getValue(AnalysisKeys.PLAYERS_MUTATOR)) + .map(mutator -> mutator.all().stream().map(FakeOfflinePlayer::new) + .collect(Collectors.toList())) + .orElse(new ArrayList<>()); Map balances = new HashMap<>(); double totalBalance = 0.0; diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultPermData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultPermData.java index 1e9d83dce..e2701c6b2 100644 --- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultPermData.java +++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/vault/VaultPermData.java @@ -9,7 +9,6 @@ import com.djrapitops.plan.data.element.InspectContainer; import com.djrapitops.plan.data.plugin.ContainerSize; import com.djrapitops.plan.data.plugin.PluginData; import com.djrapitops.plan.data.store.keys.AnalysisKeys; -import com.djrapitops.plan.data.store.mutators.PlayersMutator; import com.djrapitops.plan.system.cache.DataCache; import com.djrapitops.pluginbridge.plan.FakeOfflinePlayer; import net.milkbowl.vault.permission.Permission; @@ -49,10 +48,11 @@ public class VaultPermData extends PluginData { @Override public AnalysisContainer getServerData(Collection collection, AnalysisContainer analysisContainer) { - List offlinePlayers = analysisData.getValue(AnalysisKeys.PLAYERS_MUTATOR) - .map(PlayersMutator::all).orElse(new ArrayList<>()) - .stream().map(FakeOfflinePlayer::new) - .collect(Collectors.toList()); + List offlinePlayers = Optional.ofNullable(analysisData) + .flatMap(c -> c.getValue(AnalysisKeys.PLAYERS_MUTATOR)) + .map(mutator -> mutator.all().stream().map(FakeOfflinePlayer::new) + .collect(Collectors.toList())) + .orElse(new ArrayList<>()); Map groups = new HashMap<>(); for (FakeOfflinePlayer p : offlinePlayers) {