1
0
mirror of https://github.com/lucko/LuckPerms.git synced 2025-08-09 16:17:56 +02:00

Remove Forge capability attachment

This commit is contained in:
Luck
2025-06-19 19:53:09 +01:00
parent 3aca721f96
commit c20776d6aa
13 changed files with 26 additions and 431 deletions

View File

@@ -21,7 +21,6 @@ dependencies {
annotationProcessor 'net.minecraftforge:eventbus-validator:7.0-beta.7'
implementation project(':common')
compileOnly project(':common:loader-utils')
compileOnly project(':forge:forge-api')
}
shadowJar {

View File

@@ -1,15 +0,0 @@
plugins {
alias(libs.plugins.forgegradle)
}
sourceCompatibility = 21
targetCompatibility = 21
minecraft {
mappings channel: 'official', version: minecraftVersion
}
dependencies {
minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}"
implementation project(':api')
}

View File

@@ -1,85 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.forge.capabilities;
import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
/**
* A Forge {@link Capability} that attaches LuckPerms functionality onto {@link ServerPlayer}s.
*/
public interface UserCapability {
/**
* The identifier used for the capability
*/
ResourceLocation IDENTIFIER = ResourceLocation.fromNamespaceAndPath("luckperms", "user");
/**
* The capability instance.
*/
Capability<UserCapability> CAPABILITY = CapabilityManager.get(new CapabilityToken<UserCapability>(){});
/**
* Checks for a permission.
*
* @param permission the permission
* @return the result
*/
default boolean hasPermission(String permission) {
return checkPermission(permission).asBoolean();
}
/**
* Runs a permission check.
*
* @param permission the permission
* @return the result
*/
Tristate checkPermission(String permission);
/**
* Runs a permission check.
*
* @param permission the permission
* @param queryOptions the query options
* @return the result
*/
Tristate checkPermission(String permission, QueryOptions queryOptions);
/**
* Gets the user's currently query options.
*
* @return the current query options for the user
*/
QueryOptions getQueryOptions();
}

View File

@@ -15,12 +15,10 @@ dependencies {
minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}"
implementation project(':api')
implementation project(':common:loader-utils')
implementation project(':forge:forge-api')
}
build {
dependsOn(":forge:build")
dependsOn(":forge:forge-api:build")
}
jar {

View File

@@ -29,15 +29,15 @@ import com.mojang.brigadier.ParseResults;
import com.mojang.serialization.JsonOps;
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
import me.lucko.luckperms.common.locale.TranslationManager;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.query.QueryOptionsImpl;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.sender.SenderFactory;
import me.lucko.luckperms.common.verbose.VerboseCheckTarget;
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
import me.lucko.luckperms.forge.capabilities.UserCapability;
import me.lucko.luckperms.forge.capabilities.UserCapabilityImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
@@ -73,24 +73,22 @@ public class ForgeSenderFactory extends SenderFactory<LPForgePlugin, CommandSour
@Override
protected void sendMessage(CommandSourceStack sender, Component message) {
Locale locale;
if (sender.getEntity() instanceof ServerPlayer) {
ServerPlayer player = (ServerPlayer) sender.getEntity();
UserCapabilityImpl user = UserCapabilityImpl.get(player);
locale = user.getLocale(player);
} else {
locale = null;
}
Locale locale = sender.getEntity() instanceof ServerPlayer player
? TranslationManager.parseLocale(player.getLanguage())
: null;
sender.sendSuccess(() -> toNativeText(TranslationManager.render(message, locale)), false);
}
@Override
protected Tristate getPermissionValue(CommandSourceStack commandSource, String node) {
if (commandSource.getEntity() instanceof ServerPlayer) {
ServerPlayer player = (ServerPlayer) commandSource.getEntity();
UserCapability user = UserCapabilityImpl.get(player);
return user.checkPermission(node);
if (commandSource.getEntity() instanceof ServerPlayer player) {
User user = getPlugin().getUserManager().getIfLoaded(player.getUUID());
if (user == null) {
return Tristate.UNDEFINED;
}
QueryOptions queryOptions = getPlugin().getContextManager().getQueryOptions(player);
return user.getCachedData().getPermissionData(queryOptions).checkPermission(node, CheckOrigin.PLATFORM_API_HAS_PERMISSION).result();
}
VerboseCheckTarget target = VerboseCheckTarget.internal(commandSource.getTextName());

View File

@@ -41,7 +41,6 @@ import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
import me.lucko.luckperms.common.sender.DummyConsoleSender;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.forge.calculator.ForgeCalculatorFactory;
import me.lucko.luckperms.forge.capabilities.UserCapabilityListener;
import me.lucko.luckperms.forge.context.ForgeContextManager;
import me.lucko.luckperms.forge.context.ForgePlayerCalculator;
import me.lucko.luckperms.forge.listeners.ForgeAutoOpListener;
@@ -93,9 +92,6 @@ public class LPForgePlugin extends AbstractLuckPermsPlugin {
ForgePlatformListener platformListener = new ForgePlatformListener(this);
this.bootstrap.registerListeners(platformListener);
UserCapabilityListener userCapabilityListener = new UserCapabilityListener(this);
this.bootstrap.registerListeners(userCapabilityListener);
ForgePermissionHandlerListener permissionHandlerListener = new ForgePermissionHandlerListener(this);
this.bootstrap.registerListeners(permissionHandlerListener);

View File

@@ -1,158 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.forge.capabilities;
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
import me.lucko.luckperms.common.locale.TranslationManager;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
import me.lucko.luckperms.forge.LPForgePlugin;
import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
public class UserCapabilityImpl implements UserCapability {
private static LazyOptional<UserCapability> getCapability(Player player) {
LazyOptional<UserCapability> optional = player.getCapability(CAPABILITY);
if (optional.isPresent()) {
return optional;
}
// if capability is missing, try to restore them before trying again
player.reviveCaps();
return player.getCapability(CAPABILITY);
}
/**
* Gets a {@link UserCapability} for a given {@link ServerPlayer}.
*
* @param player the player
* @return the capability
*/
public static @NotNull UserCapabilityImpl get(@NotNull Player player) {
return (UserCapabilityImpl) getCapability(player).orElseThrow(() -> new IllegalStateException("Capability missing for " + player.getUUID()));
}
/**
* Gets a {@link UserCapability} for a given {@link ServerPlayer}.
*
* @param player the player
* @return the capability, or null
*/
public static @Nullable UserCapabilityImpl getNullable(@NotNull Player player) {
return (UserCapabilityImpl) getCapability(player).resolve().orElse(null);
}
private boolean initialised = false;
private User user;
private QueryOptionsSupplier queryOptionsSupplier;
private String language;
private Locale locale;
public UserCapabilityImpl() {
}
public void initialise(UserCapabilityImpl previous, ServerPlayer player, LPForgePlugin plugin) {
this.user = previous.user;
this.queryOptionsSupplier = plugin.getContextManager().createQueryOptionsSupplier(player);
this.language = previous.language;
this.locale = previous.locale;
this.initialised = true;
}
public void initialise(User user, ServerPlayer player, LPForgePlugin plugin) {
this.user = user;
this.queryOptionsSupplier = plugin.getContextManager().createQueryOptionsSupplier(player);
this.initialised = true;
}
private void assertInitialised() {
if (!this.initialised) {
throw new IllegalStateException("Capability has not been initialised");
}
}
@Override
public Tristate checkPermission(String permission) {
assertInitialised();
if (permission == null) {
throw new NullPointerException("permission");
}
return checkPermission(permission, this.queryOptionsSupplier.getQueryOptions());
}
@Override
public Tristate checkPermission(String permission, QueryOptions queryOptions) {
assertInitialised();
if (permission == null) {
throw new NullPointerException("permission");
}
if (queryOptions == null) {
throw new NullPointerException("queryOptions");
}
PermissionCache cache = this.user.getCachedData().getPermissionData(queryOptions);
return cache.checkPermission(permission, CheckOrigin.PLATFORM_API_HAS_PERMISSION).result();
}
public User getUser() {
assertInitialised();
return this.user;
}
@Override
public QueryOptions getQueryOptions() {
return getQueryOptionsSupplier().getQueryOptions();
}
public QueryOptionsSupplier getQueryOptionsSupplier() {
assertInitialised();
return this.queryOptionsSupplier;
}
public Locale getLocale(ServerPlayer player) {
if (this.language == null || !this.language.equals(player.getLanguage())) {
this.language = player.getLanguage();
this.locale = TranslationManager.parseLocale(this.language);
}
return this.locale;
}
}

View File

@@ -1,107 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.forge.capabilities;
import me.lucko.luckperms.forge.LPForgePlugin;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.listener.SubscribeEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class UserCapabilityListener {
private final LPForgePlugin plugin;
public UserCapabilityListener(LPForgePlugin plugin) {
this.plugin = plugin;
}
@SubscribeEvent
public void onRegisterCapabilities(RegisterCapabilitiesEvent event) {
event.register(UserCapabilityImpl.class);
}
@SubscribeEvent
public void onAttachCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (!(event.getObject() instanceof ServerPlayer)) {
return;
}
event.addCapability(UserCapability.IDENTIFIER, new UserCapabilityProvider(new UserCapabilityImpl()));
}
@SubscribeEvent
public void onPlayerClone(PlayerEvent.Clone event) {
Player previousPlayer = event.getOriginal();
Player currentPlayer = event.getEntity();
if (!(currentPlayer instanceof ServerPlayer)) {
return;
}
previousPlayer.reviveCaps();
try {
UserCapabilityImpl previous = UserCapabilityImpl.get(previousPlayer);
UserCapabilityImpl current = UserCapabilityImpl.get(currentPlayer);
current.initialise(previous, ((ServerPlayer) currentPlayer), this.plugin);
current.getQueryOptionsSupplier().invalidateCache();
} catch (IllegalStateException e) {
// continue on if we cannot copy original data
} finally {
previousPlayer.invalidateCaps();
}
}
private static final class UserCapabilityProvider implements ICapabilityProvider {
private final UserCapabilityImpl userCapability;
private UserCapabilityProvider(UserCapabilityImpl userCapability) {
this.userCapability = userCapability;
}
@SuppressWarnings("unchecked")
@NotNull
@Override
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (cap != UserCapability.CAPABILITY) {
return LazyOptional.empty();
}
return LazyOptional.of(() -> (T) this.userCapability);
}
}
}

View File

@@ -25,19 +25,15 @@
package me.lucko.luckperms.forge.context;
import me.lucko.luckperms.common.context.manager.DetachedContextManager;
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
import me.lucko.luckperms.common.context.manager.SimpleContextManager;
import me.lucko.luckperms.forge.LPForgePlugin;
import me.lucko.luckperms.forge.capabilities.UserCapabilityImpl;
import net.luckperms.api.query.OptionKey;
import net.luckperms.api.query.QueryOptions;
import net.minecraft.server.level.ServerPlayer;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Objects;
import java.util.UUID;
public class ForgeContextManager extends DetachedContextManager<ServerPlayer, ServerPlayer> {
public class ForgeContextManager extends SimpleContextManager<ServerPlayer, ServerPlayer> {
public static final OptionKey<Boolean> INTEGRATED_SERVER_OWNER = OptionKey.of("integrated_server_owner", Boolean.class);
public ForgeContextManager(LPForgePlugin plugin) {
@@ -49,16 +45,6 @@ public class ForgeContextManager extends DetachedContextManager<ServerPlayer, Se
return player.getUUID();
}
@Override
public @Nullable QueryOptionsSupplier getQueryOptionsSupplier(ServerPlayer subject) {
Objects.requireNonNull(subject, "subject");
UserCapabilityImpl capability = UserCapabilityImpl.getNullable(subject);
if (capability != null) {
return capability.getQueryOptionsSupplier();
}
return null;
}
@Override
public void customizeQueryOptions(ServerPlayer subject, QueryOptions.Builder builder) {
if (subject.getServer() != null && subject.getServer().isSingleplayerOwner(subject.getGameProfile())) {

View File

@@ -33,7 +33,6 @@ import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
import me.lucko.luckperms.forge.ForgeSenderFactory;
import me.lucko.luckperms.forge.LPForgePlugin;
import me.lucko.luckperms.forge.capabilities.UserCapabilityImpl;
import me.lucko.luckperms.forge.util.AsyncConfigurationTask;
import net.kyori.adventure.text.Component;
import net.minecraft.network.Connection;
@@ -146,9 +145,6 @@ public class ForgeConnectionListener extends AbstractConnectionListener {
}
}
// initialise capability
UserCapabilityImpl userCapability = UserCapabilityImpl.get(player);
userCapability.initialise(user, player, this.plugin);
this.plugin.getContextManager().signalContextUpdate(player);
}

View File

@@ -32,7 +32,6 @@ import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
import me.lucko.luckperms.forge.LPForgeBootstrap;
import me.lucko.luckperms.forge.LPForgePlugin;
import me.lucko.luckperms.forge.capabilities.UserCapabilityImpl;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.query.QueryMode;
import net.luckperms.api.query.QueryOptions;
@@ -78,12 +77,9 @@ public class ForgePermissionHandler implements IPermissionHandler {
@Override
public <T> T getPermission(ServerPlayer player, PermissionNode<T> node, PermissionDynamicContext<?>... context) {
UserCapabilityImpl capability = UserCapabilityImpl.getNullable(player);
if (capability != null) {
User user = capability.getUser();
QueryOptions queryOptions = capability.getQueryOptionsSupplier().getQueryOptions();
User user = this.plugin.getUserManager().getIfLoaded(player.getUUID());
if (user != null) {
QueryOptions queryOptions = this.plugin.getContextManager().getQueryOptions(player);
T value = getPermissionValue(user, queryOptions, node, context);
if (value != null) {
return value;

View File

@@ -32,8 +32,7 @@ import me.lucko.luckperms.common.graph.Graph;
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.forge.LPForgePlugin;
import me.lucko.luckperms.forge.capabilities.UserCapability;
import me.lucko.luckperms.forge.capabilities.UserCapabilityImpl;
import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.level.ServerPlayer;
@@ -140,22 +139,15 @@ public final class BrigadierInjector {
@Override
public boolean test(CommandSourceStack source) {
if (source.getEntity() instanceof ServerPlayer) {
ServerPlayer player = (ServerPlayer) source.getEntity();
Tristate state = Tristate.UNDEFINED;
// If player is still connecting and has not been added to world then check LP user directly
if (!player.isAddedToWorld()) {
User user = this.plugin.getUserManager().getIfLoaded(player.getUUID());
if (user == null) {
// Should never happen but just in case...
return false;
}
state = user.getCachedData().getPermissionData().checkPermission(permission);
} else {
UserCapability user = UserCapabilityImpl.get(player);
state = user.checkPermission(this.permission);
if (source.getEntity() instanceof ServerPlayer player) {
User user = this.plugin.getUserManager().getIfLoaded(player.getUUID());
if (user == null) {
return false;
}
QueryOptions queryOptions = this.plugin.getContextManager().getQueryOptions(player);
Tristate state = user.getCachedData().getPermissionData(queryOptions).checkPermission(this.permission);
if (state != Tristate.UNDEFINED) {
return state.asBoolean() && this.delegate.test(source.withPermission(4));
}

View File

@@ -32,7 +32,6 @@ include (
'neoforge:loader',
'forge',
'forge:loader',
'forge:forge-api',
'nukkit',
'nukkit:loader',
'sponge',