From d2aca8ffa956fda73ffda2ff8ddf70ce861018e9 Mon Sep 17 00:00:00 2001 From: hypherionmc Date: Mon, 25 Nov 2024 14:06:59 +0200 Subject: [PATCH] [WIP] FTB Ranks/LuckPerms API's --- Common/build.gradle | 1 + .../api/events/compat/FTBRankEvents.java | 56 +++++++++++++ .../events/compat/LuckPermsCompatEvents.java | 32 +++++++ .../craterlib/compat/LuckPermsCompat.java | 84 ++++++++++++++++++- .../compat/ftbranks/BridgedRank.java | 24 ++++++ .../craterlib/compat/ftbranks/FTBRanks.java | 83 ++++++++++++++++++ Fabric/build.gradle | 1 + NeoForge/build.gradle | 1 + changelog.md | 1 + gradle.properties | 3 +- 10 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/FTBRankEvents.java create mode 100644 Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/LuckPermsCompatEvents.java create mode 100644 Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/BridgedRank.java create mode 100644 Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/FTBRanks.java diff --git a/Common/build.gradle b/Common/build.gradle index 15a4dec..81fbb3f 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -2,6 +2,7 @@ archivesBaseName = "${mod_name.replace(" ", "")}-Common-${minecraft_version}" dependencies { stupidRemapArch("dev.ftb.mods:ftb-essentials:${ftb_essentials}") + stupidRemapArch("dev.ftb.mods:ftb-ranks:${ftb_ranks}") } shadowJar { diff --git a/Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/FTBRankEvents.java b/Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/FTBRankEvents.java new file mode 100644 index 0000000..777e43c --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/FTBRankEvents.java @@ -0,0 +1,56 @@ +// @excludeplugin +package com.hypherionmc.craterlib.api.events.compat; + +import com.hypherionmc.craterlib.compat.ftbranks.BridgedRank; +import com.hypherionmc.craterlib.core.event.CraterEvent; +import com.hypherionmc.craterlib.nojang.authlib.BridgedGameProfile; +import com.mojang.authlib.GameProfile; +import dev.ftb.mods.ftbranks.api.Rank; +import lombok.Getter; + +public class FTBRankEvents { + + @Getter + public static class RankAddedEvent extends CraterEvent { + private final BridgedGameProfile gameProfile; + private final BridgedRank rank; + + private RankAddedEvent(BridgedGameProfile gameProfile, BridgedRank rank) { + this.gameProfile = gameProfile; + this.rank = rank; + } + + public static RankAddedEvent of(GameProfile profile, Rank rank) { + return new RankAddedEvent(BridgedGameProfile.of(profile), BridgedRank.of(rank)); + } + } + + @Getter + public static class RankRemovedEvent extends CraterEvent { + private final BridgedGameProfile gameProfile; + private final BridgedRank rank; + + private RankRemovedEvent(BridgedGameProfile gameProfile, BridgedRank rank) { + this.gameProfile = gameProfile; + this.rank = rank; + } + + public static RankRemovedEvent of(GameProfile profile, Rank rank) { + return new RankRemovedEvent(BridgedGameProfile.of(profile), BridgedRank.of(rank)); + } + } + + @Getter + public static class RankDeletedEvent extends CraterEvent { + private final BridgedRank rank; + + private RankDeletedEvent(BridgedRank rank) { + this.rank = rank; + } + + public static RankDeletedEvent of(Rank rank) { + return new RankDeletedEvent(BridgedRank.of(rank)); + } + } + +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/LuckPermsCompatEvents.java b/Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/LuckPermsCompatEvents.java new file mode 100644 index 0000000..69e75ad --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/api/events/compat/LuckPermsCompatEvents.java @@ -0,0 +1,32 @@ +package com.hypherionmc.craterlib.api.events.compat; + +import com.hypherionmc.craterlib.core.event.CraterEvent; +import com.hypherionmc.craterlib.nojang.authlib.BridgedGameProfile; +import lombok.RequiredArgsConstructor; + +import java.util.UUID; + +public class LuckPermsCompatEvents { + + @RequiredArgsConstructor(staticName = "of") + public static class GroupAddedEvent extends CraterEvent { + private final String identifier; + private final UUID uuid; + private final String username; + + public BridgedGameProfile toProfile() { + return BridgedGameProfile.mojang(uuid, username); + } + } + + @RequiredArgsConstructor(staticName = "of") + public static class GroupRemovedEvent extends CraterEvent { + private final String identifier; + private final UUID uuid; + private final String username; + + public BridgedGameProfile toProfile() { + return BridgedGameProfile.mojang(uuid, username); + } + } +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java b/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java index a77e1f4..686f500 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java @@ -1,20 +1,102 @@ package com.hypherionmc.craterlib.compat; +import com.hypherionmc.craterlib.api.events.compat.LuckPermsCompatEvents; +import com.hypherionmc.craterlib.core.event.CraterEventBus; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.event.EventBus; +import net.luckperms.api.event.node.NodeMutateEvent; +import net.luckperms.api.model.group.Group; import net.luckperms.api.model.user.User; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.InheritanceNode; import net.minecraft.server.level.ServerPlayer; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + public class LuckPermsCompat { public static final LuckPermsCompat INSTANCE = new LuckPermsCompat(); private final LuckPerms luckPerms = LuckPermsProvider.get(); - LuckPermsCompat() {} + LuckPermsCompat() { + EventBus bus = luckPerms.getEventBus(); + + bus.subscribe(NodeMutateEvent.class, e -> { + if (!e.isUser()) + return; + + User user = (User) e.getTarget(); + + Set addedInheritance = e.getDataAfter().stream() + .filter(node -> node.getType() == NodeType.INHERITANCE && !e.getDataBefore().contains(node)) + .map(NodeType.INHERITANCE::cast) + .collect(Collectors.toSet()); + + Set removedInheritance = e.getDataBefore().stream() + .filter(node -> node.getType() == NodeType.INHERITANCE && !e.getDataAfter().contains(node)) + .map(NodeType.INHERITANCE::cast) + .collect(Collectors.toSet()); + + if(addedInheritance.isEmpty() && removedInheritance.isEmpty()) return; + + addedInheritance.forEach(node -> { + CraterEventBus.INSTANCE.postEvent(LuckPermsCompatEvents.GroupAddedEvent.of(node.getGroupName(), user.getUniqueId(), user.getUsername())); + }); + + removedInheritance.forEach(node -> { + CraterEventBus.INSTANCE.postEvent(LuckPermsCompatEvents.GroupRemovedEvent.of(node.getGroupName(), user.getUniqueId(), user.getUsername())); + }); + }); + } public boolean hasPermission(ServerPlayer player, String perm) { User luckPermsUser = luckPerms.getPlayerAdapter(ServerPlayer.class).getUser(player); return luckPermsUser.getCachedData().getPermissionData().checkPermission(perm).asBoolean(); } + public boolean hasGroup(UUID uuid, String group) { + return getUserGroups(uuid).stream().anyMatch(g -> g.equalsIgnoreCase(group)); + } + + public Set getUserGroups(UUID uuid) { + User user = luckPerms.getUserManager().getUser(uuid); + if (user == null) + return new HashSet<>(); + + return user.getNodes(NodeType.INHERITANCE).stream().map(InheritanceNode::getGroupName).collect(Collectors.toSet()); + } + + public boolean addGroupToUser(UUID uuid, String group) { + AtomicBoolean added = new AtomicBoolean(false); + + Group g = luckPerms.getGroupManager().getGroup(group); + if (g == null) { + return false; + } + + luckPerms.getUserManager().loadUser(uuid).thenAcceptAsync(user -> { + if (user == null) return; + user.data().add(InheritanceNode.builder(group).build()); + luckPerms.getUserManager().saveUser(user); + added.set(true); + }); + + return added.get(); + } + + public boolean removeGroupFromUser(UUID uuid, String group) { + AtomicBoolean removed = new AtomicBoolean(false); + + luckPerms.getUserManager().loadUser(uuid).thenAcceptAsync(user -> { + if (user == null) return; + user.data().remove(InheritanceNode.builder(group).build()); + luckPerms.getUserManager().saveUser(user); + removed.set(true); + }); + + return removed.get(); + } } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/BridgedRank.java b/Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/BridgedRank.java new file mode 100644 index 0000000..e429fce --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/BridgedRank.java @@ -0,0 +1,24 @@ +// @excludeplugin +package com.hypherionmc.craterlib.compat.ftbranks; + +import dev.ftb.mods.ftbranks.api.Rank; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor(staticName = "of") +public class BridgedRank { + + private final Rank internal; + + public String name() { + return internal.getName(); + } + + public String id() { + return internal.getId(); + } + + public Rank toFtb() { + return internal; + } + +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/FTBRanks.java b/Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/FTBRanks.java new file mode 100644 index 0000000..c9d16a3 --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/compat/ftbranks/FTBRanks.java @@ -0,0 +1,83 @@ +// @excludeplugin +package com.hypherionmc.craterlib.compat.ftbranks; + +import com.hypherionmc.craterlib.api.events.compat.FTBRankEvents; +import com.hypherionmc.craterlib.core.event.CraterEventBus; +import com.hypherionmc.craterlib.nojang.authlib.BridgedGameProfile; +import dev.ftb.mods.ftbranks.api.FTBRanksAPI; +import dev.ftb.mods.ftbranks.api.event.PlayerAddedToRankEvent; +import dev.ftb.mods.ftbranks.api.event.PlayerRemovedFromRankEvent; +import dev.ftb.mods.ftbranks.api.event.RankDeletedEvent; +import dev.ftb.mods.ftbranks.api.event.RankEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class FTBRanks { + + public static final FTBRanks INSTANCE = new FTBRanks(); + + private FTBRanks() { + registerEvents(); + } + + public List getPlayerRanks(BridgedGameProfile profile) { + List ranks = new ArrayList<>(); + FTBRanksAPI.manager().getAddedRanks(profile.toMojang()).forEach(rank -> ranks.add(BridgedRank.of(rank))); + return ranks; + } + + public List getAllRanks() { + List ranks = new ArrayList<>(); + FTBRanksAPI.manager().getAllRanks().forEach(r -> ranks.add(BridgedRank.of(r))); + return ranks; + } + + public boolean hasRank(BridgedGameProfile profile, String rank) { + return getPlayerRanks(profile).stream().anyMatch(r -> r.toFtb().getName().equalsIgnoreCase(rank) || r.toFtb().getId().equalsIgnoreCase(rank)); + } + + public boolean addRank(BridgedGameProfile profile, String rank) { + rank = rank.toLowerCase(); + + AtomicBoolean didAddRank = new AtomicBoolean(false); + FTBRanksAPI.manager().getRank(rank).ifPresent(r -> { + r.add(profile.toMojang()); + didAddRank.set(true); + }); + + return didAddRank.get(); + } + + public boolean removeRank(BridgedGameProfile profile, String rank) { + rank = rank.toLowerCase(); + + AtomicBoolean didRemoveRank = new AtomicBoolean(false); + FTBRanksAPI.manager().getRank(rank).ifPresent(r -> { + r.remove(profile.toMojang()); + didRemoveRank.set(true); + }); + + return didRemoveRank.get(); + } + + public void registerEvents() { + RankEvent.ADD_PLAYER.register(this::playerAddedToRank); + RankEvent.REMOVE_PLAYER.register(this::playerRemovedFromRank); + RankEvent.DELETED.register(this::rankDeleted); + } + + private void rankDeleted(RankDeletedEvent rankDeletedEvent) { + CraterEventBus.INSTANCE.postEvent(FTBRankEvents.RankDeletedEvent.of(rankDeletedEvent.getRank())); + } + + private void playerRemovedFromRank(PlayerRemovedFromRankEvent playerRemovedFromRankEvent) { + CraterEventBus.INSTANCE.postEvent(FTBRankEvents.RankRemovedEvent.of(playerRemovedFromRankEvent.getPlayer(), playerRemovedFromRankEvent.getRank())); + } + + private void playerAddedToRank(PlayerAddedToRankEvent playerAddedToRankEvent) { + CraterEventBus.INSTANCE.postEvent(FTBRankEvents.RankAddedEvent.of(playerAddedToRankEvent.getPlayer(), playerAddedToRankEvent.getRank())); + } + +} diff --git a/Fabric/build.gradle b/Fabric/build.gradle index d14e5d4..b3da913 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -10,6 +10,7 @@ dependencies { } stupidRemapArch("dev.ftb.mods:ftb-essentials:${ftb_essentials}") + stupidRemapArch("dev.ftb.mods:ftb-ranks:${ftb_ranks}") modImplementation "maven.modrinth:fabrictailor:${fabrictailor}" modImplementation "maven.modrinth:vanish:${vanish}" diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index cec72cb..bc934ff 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -5,6 +5,7 @@ dependencies { modImplementation("maven.modrinth:vanishmod:${vanishmod_neo}") stupidRemapArch("dev.ftb.mods:ftb-essentials-neoforge:${ftb_essentials}") + stupidRemapArch("dev.ftb.mods:ftb-ranks-neoforge:${ftb_ranks}") // Do not edit or remove implementation project(":Common") diff --git a/changelog.md b/changelog.md index c66ef9b..4ecb3ae 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ **New Features**: - Paper Support. Currently only available on Modrinth and NightBloom +- Added API's for working with FTB Ranks and LuckPerms groups **Bug Fixes**: diff --git a/gradle.properties b/gradle.properties index 1d9e085..812aff8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ version_major=2 version_minor=1 version_patch=2 -version_build=0 +version_build=1 #Mod mod_author=HypherionSA @@ -37,6 +37,7 @@ mod_menu_version=10.0.0-beta.1 vanishmod=1.1.12.1 vanishmod_neo=puxrKAMr ftb_essentials=2101.1.0 +ftb_ranks=2101.1.1 # Publishing curse_id=867099