LuckPerms

LuckPerms

41.4k Downloads

Custom ContextCalculator does not work with permissions

KaiKikuchi opened this issue ยท 9 comments

commented

luckperms info:

Running LuckPerms v5.0.83 by Luck.
-  Platform: Sponge
-  Server Brand: SpongeForge
-  Server Version:
-  SpongeAPI: 7.1.0-ea50f0c2 - SpongeForge: 1.12.2-2838-7.1.9
-  Storage:
-     Type: H2
-     File Size: 0.03MB
-  Messaging: None
-  Instance:
-     Static contexts: None
-     Online Players: 1 (1 unique)
-     Uptime: 4m 22s
-     Local Data: 1 users, 1 groups, 0 tracks

How to reproduce
I create a fresh installation of the server with the details above. Plugins: LuckPerms and my Test Plugin.

This test plugin was made only to register a custom ContextCalculator defined like this:

public class CustomCalculator implements ContextCalculator<Subject> {
  @Override  
  public void calculate(Subject subject, ContextConsumer contextConsumer) {
    if (subject instanceof Identifiable) {
      contextConsumer.accept("test", "0");
      System.out.println("calculated context test=0");
    }
  }

  @Override
  public ContextSet estimatePotentialContexts() {
    ImmutableContextSet.Builder builder = ImmutableContextSet.builder();
    builder.add("test", "0");
    builder.add("test", "1");
    return builder.build();
  }
}

This ContextCalculator is registered in the main plugin class like this:

@Listener
public void onStarted(GameStartedServerEvent event) {
  LuckPermsProvider.get().getContextManager().registerCalculator(new CustomCalculator());
}

/lp user KaiNoMood info:

> User Info: kainomood
- UUID: a54a7884-9ea4-4d54-ac35-1623d70ffbe1 (type: mojang)
- Status: Online
- Primary Group: default
- Parent Groups:
-    > default
- Contextual Data:
-    Has contextual data: true
-    Applicable contexts: (test=0) (world=world) (dimension=minecraft.overworld) (remoteip=**redacted**) (localip=**redacted**) (localport=25566) (localhost=**redacted**)
-    Prefix: None
-    Suffix: None
-    Meta: None

When I do /lp user KaiNoMood info, the console shows calculated context test=0, so my custom ContextCalculator is "working" there. My context shows in the list of "Applicable contexts".

Added a permission that I did not have with /lp user KaiNoMood perm set minecraft.command.effect test=0

/lp user KaiNoMood perm info:

kainomood's Permissions:  (page 1 of 1 - 2 entries)
> minecraft.command.effect (true) (test=0)
> luckperms (true)

The error:
I enabled verbose with /lp verbose on minecraft.command.effect, then used the /effect command:
image

Console does not show calculated context test=0 as specified on my context calculator.

What I expected:
The /effect command should work because the user has the "test" context set to "0".

More details:
/lp user KaiNoMood perm checkinherits minecraft.command.effect:
kainomood has permission minecraft.command.effect set to undefined in context global. (inherited from self)

/lp user KaiNoMood perm checkinherits minecraft.command.effect test=0:
kainomood has permission minecraft.command.effect set to true in context test=0. (inherited from self)

Console does not show calculated context test=0 when I run the 2 commands above.

I am following the instructions provided in the wiki here. I can't make it work no matter what. Changing the name of the context, the value, registering it during GameInitializationEvent, or using a "custom" permission like "test.permission" and using it with something like player.hasPermission("test.permission") still does not produce any positive result.

Any help is appreciated! Thank you for reading!

commented

Could you run /lp verbose paste after attempting to run the effect command and send the link here.

commented

That contains IP addresses. Can I DM it to you on Discord or somewhere else privately? Sorry.

commented

Yes, you can send the link privately if you like.

  1. Go to https://keybase.io/encrypt
  2. Set the recipient to luck
  3. Copy "the secret messge" plaintext and post it here.

Sorry to be a pain - I have discord DMs disabled & ^^ is probably the easiest / most secure way if you're worried about that.

commented
-----BEGIN PGP MESSAGE-----
Version: Keybase OpenPGP v2.1.13
Comment: https://keybase.io/crypto

wcFMAxavkAf6LzVtARAAjcqvGYbbB6RynPvrSR612NPLuOHuJNY4RhMHcgE8ajIi
sxFeHTqvA66c8ZZTaCc30+kaHI1YG8dUJ3lgerNhDjiJUJmF5udlWiNAxi/Umzqf
hHHx1P/sLT+jvFzZj7gtobok51t2pzT7rNobZOPl3gRH1j5iy3f+3/DiIYXfDSxR
cUKtDSxIO1/skw6d2Fdme/QvawQNspRinFRnyvT6b1PZUPb/hD/HHiA627lHnH4O
/MWlc/xVb/6S91VooVvxEK3iSgv5LVM/940D8DWWBZHcdIsPEIDQr7H+Pi1G2W7M
37IV2ME5Ub+Zhizv9KamRRccXtuH9mFR5TdEAt9LQnA01nHlv/jE0wdUO3fUcELK
Mrm2Sbru3ptqKaU2d/629lpFJjHo06dQEHyNW0fyh8JXNxjTLPqaHDjYmDvKQ/th
qnLRHN7S0MHkbkCbyRFVX8Mo4RgPxf0DnS1ABmTO6oWVljb8s/rFzQweVhB4wH2O
QagOTkgBUfbWEOfY9Ep5n7efwIpakUAuuBO3P2ZMInd/HC6dgxHxm+Aej0w4ern/
T4i2GPlugjFCvrUuGe5er4//MkHoj1Mu32nwECTBDXb66j3c7Epauc14r8h6LUjY
+YonaUDYSUWU9GzzYNTtZHjVdGND6fyGp+p0w4C22a0n2qu7+4SWALsADyc30JHS
ZQF3FNkmYN4ub1jbYbSviLLQxdXOgTbZBQyN0PxwSSQgkdqMzGB4C1YXwFXtOHRi
D/lMMIspj5J708hrCb0KUi/RpFU36bj2SR//XG1TalrigGcM6Gj0EUJ7dJv48TCn
0CFQ/f/O
=NpZS
-----END PGP MESSAGE-----

That's actually smart, I'll keep it in mind!

commented

Hmm ok interesting.

I suspect the issue is with this line:

if (subject instanceof Identifiable)

Could you try removing that from your test to see if it works?

commented

Yeah, that works.

The reason I added if (subject instanceof Identifiable) is because in my actual code, also used in Spigot, I actually need the UUID object.

I didn't want to use UUID.fromString(subject.getIdentifier()) for performance optimization.
The Player interface in Sponge extends both Subject and Identifiable, and I just needed the UUID object, so I used Identifiable.

Is there any reason the Subject is not actually the Player object (or at least User)?

Do you have any suggestion other than deserializing the subject identifier? Thank you for your quick help!

commented

Is there any reason the Subject is not actually the Player object (or at least User)?

Yes - there are (usually) two implementations of Subject for a given unique player present at runtime.

  • One is the actual Player Minecraft object - the one Sponge mixes into to implement it's API - this object will implement Identifiable and other interfaces.
  • The other is an object provided by the Permission Service (LuckPerms in this case) which actually implements the permission methods.

Sponge proxies the permission related methods from the actual Player object to the LuckPerms one automagically at runtime with Mixin.

Do you have any suggestion other than deserializing the subject identifier? Thank you for your quick help!

If you want to guarantee that you'll end up with a "player like" object every time, you need to use Subject#getCommandSource.

Something like this should work:

@Override
public void calculate(@NonNull Subject subject, @NonNull ContextConsumer consumer) {
    Identifiable identifiable;
    if (subject instanceof Identifiable) {
        identifiable = (Identifiable) subject;
    } else {
        Optional<CommandSource> commandSource = subject.getCommandSource();
        if (commandSource.isPresent() && commandSource.get() instanceof Identifiable) {
            identifiable = (Identifiable) commandSource.get();
        } else {
            return;
        }
    }

    // TODO: do something with identifiable to calculate contexts
    
}
commented

Or even just this will work for Players:

@Override
public void calculate(@NonNull Subject subject, @NonNull ContextConsumer consumer) {
    CommandSource commandSource = subject.getCommandSource().orElse(null);
    if (!(commandSource instanceof Identifiable)) {
        return; // not a command source or identifiable
    }

    Identifiable identifiable = (Identifiable) commandSource;
    
    // TODO: do something with identifiable to calculate contexts
}
commented

Ah I get it, I just assumed the Subject object was the actual Player object, as that's the "behaviour" in Bukkit as you get the actual Player object.

Thank you very much for your help!